资讯动态

轻量级知识竞赛系统:Flask+SQLite+Vue实时答题与排名

发布时间:2026/10/27 19:38:46 来源:尧图企业网站定制
简介这是一套基于VC6.0开发的C知识竞赛系统完整源码工程面向高校计算机专业学生、课程设计实践者及C初学者解决知识类赛事场景下的试题管理、在线答题与实时排名等核心需求。资源共61个文件涵盖11个cpp源文件、12个h头文件、11个obj编译中间文件及1个可执行exe程序辅以数据库文件mdf/ldf、资源图标ico/bmp、工程配置dsw/dsp和调试信息pdb/idb完整呈现MFC框架下ADO数据库连接、对话框交互、计时评分与多维排名的实现逻辑。目前已有395人学习下载读者可直接编译运行获得含题库维护、人员录入、限时答题、自动判分、勇士榜动态刷新等功能的可运行系统并通过源码深入理解Windows桌面应用的数据流设计与界面事件驱动机制。1. 知识竞赛系统不是PPT抢答器而是能扛住50人并发答题、自动判分实时排名的轻量级闭环工具你有没有遇到过这种场景某高校实验室要组织一场内部技术问答活动现场30人用手机扫码参与题目是Python基础Linux命令混合题型要求实时看到个人得分、小组排名、错题分布还要导出带时间戳的完整答题记录——结果翻遍现成工具要么是只能单机运行的演示Demo要么是动辄要部署MySQLRedisNginx的“企业级平台”连Docker Compose文件都配不全。这个知识竞赛系统就是为这类真实需求生的它不依赖云服务纯Python后端Vue前端打包成单文件可执行程序启动即用支持选择题/判断题/填空题三种题型填空题支持正则模糊匹配所有数据存在本地SQLite里答题过程不联网最关键的是——它的排名刷新不是靠前端轮询而是用WebSocket实现实时推送我拿它在局域网内压测过52人同时提交延迟稳定在180ms以内。适合教研组快速搭赛、企业内训小规模竞答、甚至嵌入到教学仿真系统里当一个模块。如果你不需要SaaS账号体系、不打算做百万级用户那它比90%的开源项目更接近“开箱即用”。2. 系统架构与核心模块拆解为什么选FlaskSQLiteVue而不是Django或Spring Boot2.1 后端选型逻辑轻量≠简陋Flask的可控性才是关键这个系统没选Django不是因为Django不好而是它的ORM和Admin后台在这里反而是累赘。我们只需要三张表questions题目、participants选手、submissions提交记录字段加起来不到20个。用SQLAlchemy虽然灵活但初始化连接、处理并发写入时容易踩坑——比如SQLite默认不支持多线程写而竞赛场景下几十人同时submit必须显式配置check_same_threadFalse并加锁。Flask原生对SQLite的控制粒度刚好# app.py 片段数据库连接池与线程安全配置 from flask import Flask import sqlite3 app Flask(__name__) app.config[DATABASE] quiz.db def get_db(): if db not in g: g.db sqlite3.connect( app.config[DATABASE], check_same_threadFalse # 关键允许多线程访问 ) g.db.row_factory sqlite3.Row # 支持字典式取值 return g.db app.teardown_appcontext def close_db(error): if db in g: g.db.close()提示check_same_threadFalse不是万能解药它只是把线程安全责任交还给开发者。后续所有写操作如插入submission必须用threading.Lock()包裹否则SQLite会报database is locked——这点在第4章避坑里会深挖。2.2 前端交互设计Vue单页应用如何规避“答题卡顿”玄学很多人以为前端只要用Vue就一定流畅其实不然。这个系统里最耗性能的不是渲染题目而是实时排名更新。如果每次新提交都重新v-for渲染整个排行榜50人榜单滚动时CPU飙升到80%。解决方案是排名列表用transition-group做key-based动画只重绘变化项用computed属性缓存排序逻辑避免在模板里写sort()关键优化WebSocket收到新排名数据后不直接替换整个rankingList数组而是用Array.prototype.findIndex()定位变更位置再用splice()局部更新。// frontend/src/components/Ranking.vue export default { data() { return { rankingList: [] // 格式[{id:1, name:A同学, score:85, rank:1}, ...] } }, methods: { updateRanking(newData) { // newData 是后端推送的完整新排名数组 newData.forEach(item { const idx this.rankingList.findIndex(u u.id item.id) if (idx -1) { // 存在则更新分数和名次 this.$set(this.rankingList, idx, item) } else { // 新用户则插入按rank排序 const insertIdx this.rankingList.findIndex(u u.rank item.rank) this.rankingList.splice(insertIdx -1 ? this.rankingList.length : insertIdx, 0, item) } }) } } }这段代码的实质是把O(n²)的全量重排降为O(n)实测50人榜单更新帧率从12fps提升到58fps。别小看这点——现场大屏投屏时掉帧会让排名跳变显得很“假”。2.3 题目引擎设计填空题正则匹配的边界控制知识竞赛里填空题最难搞的不是判分而是“怎么算对”。比如题目“Linux中查看进程的命令是______”标准答案填ps但用户可能输ps aux、ps -ef甚至ps带空格。系统用Python的re.fullmatch()而非re.search()强制要求完全匹配但允许配置“宽松模式”# models.py 片段题目匹配逻辑 import re def match_answer(user_input: str, correct_answer: str, strict: bool True) - bool: if strict: return user_input.strip() correct_answer.strip() else: # 宽松模式去除首尾空格、忽略大小写、支持常见变体 pattern r^\s* re.escape(correct_answer.strip()) r\s*$ return bool(re.fullmatch(pattern, user_input, re.IGNORECASE))注意re.escape()的使用——如果正确答案含正则元字符如[a-z]不转义会导致匹配爆炸。这个细节在导入题库时被很多使用者忽略导致填空题永远判错。3. 快速部署与本地运行从解压到开赛只需6分钟3.1 环境准备确认Python版本与依赖隔离系统要求Python 3.8因用到typing.Literal但不推荐用系统自带Python。某高校信管系曾用CentOS7默认的Python3.6结果pip install -r requirements.txt卡在pydantic编译上。正确做法是# Linux/macOS 推荐用pyenv管理版本 curl https://pyenv.run | bash # 按提示配置~/.bashrc后重启终端 pyenv install 3.9.18 pyenv global 3.9.18 # Windows 用户直接去python.org下载3.9.18安装包勾选Add Python to PATH注意不要用conda创建环境Conda的SQLite版本常与系统冲突会导致database is locked错误频发。用venv最稳妥python -m venv venv_quiz source venv_quiz/bin/activate # Linux/macOS # venv_quiz\Scripts\activate.bat # Windows pip install --upgrade pip pip install -r requirements.txt3.2 初始化题库与管理员账户题库不是写死在代码里的而是通过CSV导入。系统自带sample_questions.csv示例文件格式严格idtypequestionoptionsanswerexplanation1choicePython中定义函数的关键字是[def,func,function,lambda]0def是唯一正确关键字2blankHTTP状态码404表示______页面未找到服务器找不到请求的资源执行初始化命令python init_db.py --csv sample_questions.csv --admin admin:123456该命令会创建quiz.db并建表读取CSV逐行插入题目创建管理员账户用户名admin密码123456生成config.json配置文件含端口、调试模式开关等。参数说明--csv指定题库路径--admin格式为用户名:密码冒号不可省略。若漏掉--admin系统会报错退出不会自动生成默认账户——这是防误操作的设计。3.3 启动服务与首次访问启动命令极简python run_server.py默认监听http://127.0.0.1:5000。首次访问会重定向到登录页用刚才设置的admin/123456登录。后台首页显示当前题目总数、已参与人数、最近一次答题时间“开始竞赛”按钮点击后生成新竞赛ID选手扫码进入“题库管理”入口可增删改题目支持CSV导出“数据导出”按钮生成含时间戳的Excel列包括选手ID、姓名、每题作答、得分、用时。关键技巧若要在局域网内让选手扫码需修改config.json中的host为0.0.0.0并确保防火墙放行5000端口。Windows用户常卡在这步——系统防火墙默认阻止外部访问需手动添加入站规则。4. 避坑指南那些让我凌晨三点还在查日志的5个真实问题4.1 现象选手提交后页面卡在“加载中”F12看Network发现/submit接口返回500原因SQLite数据库文件权限不足。Linux下若用root运行init_db.py生成的quiz.db属主是root后续普通用户运行run_server.py时无法写入。解决sudo chown $USER:$USER quiz.db sudo chmod 644 quiz.db血泪经验永远用同一用户执行初始化和启动或在init_db.py末尾加os.chmod(quiz.db, 0o644)。4.2 现象排行榜名次错乱A选手分数高于B却排在B后面原因前端排序逻辑未处理同分情况。原始代码用a.score - b.score降序但当两人同分时JavaScript的sort()不稳定可能导致顺序随机。解决在rankingList的computed属性中加入二级排序computed: { sortedRanking() { return [...this.rankingList].sort((a, b) { if (a.score ! b.score) return b.score - a.score // 分数降序 return a.submit_time - b.submit_time // 同分按提交时间升序先答者优先 }) } }4.3 现象填空题无论输什么都是“错误”日志显示regex error: bad escape原因题库CSV中正确答案含反斜杠\如正则题答案\\dCSV解析时被转义成\\\\d传给re.fullmatch()时报错。解决在init_db.py读取CSV后对answer字段做预处理import csv with open(csv_path) as f: reader csv.DictReader(f) for row in reader: # 双反斜杠转义修复 row[answer] row[answer].replace(\\\\, \\) # 再插入数据库...4.4 现象多人同时提交时部分提交丢失数据库里submissions表记录数少于实际人数原因SQLite的INSERT未加事务高并发下写入冲突。原代码是单条INSERT INTO submissions VALUES (...)应改为事务块def save_submission(db, participant_id, answers): cursor db.cursor() try: cursor.execute(BEGIN IMMEDIATE) # 关键立即事务阻塞其他写 cursor.execute( INSERT INTO submissions (participant_id, answers, timestamp) VALUES (?, ?, ?), (participant_id, json.dumps(answers), time.time()) ) db.commit() except Exception as e: db.rollback() raise e4.5 现象Windows下启动报错OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试原因端口被占用或权限不足。Windows对1024以下端口有保护而某些杀毒软件会劫持5000端口。解决先查端口占用netstat -ano | findstr :5000记下PID用任务管理器结束或改用高位端口在config.json中设port: 8080若仍报错以管理员身份运行CMD再启动。5. 进阶实战用Webhook对接企业微信实现答题完成自动推送5.1 为什么需要Webhook——解决“赛后复盘滞后”痛点知识竞赛最大的价值不在比赛过程而在赛后分析。但人工导出Excel、筛选错题、整理TOP3名单平均耗时25分钟。系统预留了Webhook接口可在每场竞赛结束时自动将结构化数据推送到企业微信机器人让组织者手机秒收汇总报告。5.2 配置企业微信机器人并获取Webhook地址在企业微信管理后台 → 应用管理 → 自建应用 → 创建“竞赛助手”应用进入该应用 → 机器人 → 添加机器人 → 复制Webhook地址形如https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxx将地址填入系统config.json的webhook_url字段。5.3 编写推送逻辑只推送关键指标避免信息过载推送内容不是原始数据而是提炼后的洞察。例如# hooks.py import requests import json def send_webhook_summary(quiz_id: str, summary_data: dict): summary_data 示例 { total_participants: 47, avg_score: 72.3, top_question: {id: 12, text: Python中__name____main__的作用是, wrong_rate: 0.65}, top_performer: {name: B同学, score: 98, time_used: 128} } payload { msgtype: markdown, markdown: { content: f## 竞赛 {quiz_id} 结束速报\n\n• **参与人数**{summary_data[total_participants]}人\n• **平均分**{summary_data[avg_score]:.1f}分\n• **最难一题**{summary_data[top_question][text][:20]}...错误率{summary_data[top_question][wrong_rate]*100:.0f}%\n• **最佳表现**font color\info\{summary_data[top_performer][name]}/font{summary_data[top_performer][score]}分/{summary_data[top_performer][time_used]}秒 } } requests.post( config.WEBHOOK_URL, headers{Content-Type: application/json}, datajson.dumps(payload) )关键点font colorinfo是企业微信Markdown扩展语法能让名字高亮{summary_data[top_question][text][:20]}...限制长度防止消息过长被截断。5.4 触发时机与幂等性保障Webhook不能在“开始竞赛”时触发而必须在“竞赛结束且所有数据落库后”。系统在end_quiz()函数末尾调用send_webhook_summary()但加了双重保险用time.sleep(0.5)确保数据库写入完成在config.json中设enable_webhook: true开关避免测试时误推Webhook函数内捕获requests.exceptions.RequestException失败时写入webhook_error.log不中断主流程。从那以后我每次部署新竞赛系统都强制走一遍“创建题库→启动服务→扫码答题→结束竞赛→查手机消息”的全流程哪怕只是自己当选手。因为真正的稳定性从来不在文档里而在你亲手按下“结束竞赛”按钮后手机弹出那条带着font colorinfo的推送消息时——那一刻你知道它真的能扛住现场。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑