https://gitee.com/ldkcode/ketangdianming/tree/master
https://blog.csdn.net/2301_80295708/article/details/155162048?sharetype=blogdetail&sharerId=155162048&sharerefer=PC&sharesource=2301_80295708&spm=1011.2480.3001.8118
https://www.bilibili.com/video/BV1UhUNB7EFu/?share_source=copy_web&vd_source=a158081635caa5791dcda7f052a73018
一、结对探索
1.1 队伍基本信息
结对编号:1a2a3a;队伍名称:码上点到你
| 学号 | 姓名 | 作业博客链接 | 具体分工 |
|---|---|---|---|
| 102301446 | 林得恺 | 2025软工K班结对编程任务 | 前端与交互负责人:负责React架构搭建、UI组件开发(评分弹窗、图表)、动画效果实现及前端状态管理(乐观更新策略)。 |
| 102301445 | 林潇 | 2025软工K班结对编程任务 | 后端与系统负责人:负责Flask环境搭建、数据库设计(MySQL/SQLite双模)、API接口开发与测试、数据导入导出逻辑及部署文档编写。 |
1.2 描述结对的过程
本次结对编程我们采取了“前后端分离、核心逻辑共研”的模式。
- 初期阶段:我们共同阅读了作业需求,确定了使用 React + Python Flask 的技术栈,并讨论了“本地/云端双模”这一核心架构,以解决网络不稳定时的可用性问题。
- 开发阶段:利用QQ和微信进行实时沟通。在编写核心算法(如加权随机点名)时,我们使用了屏幕共享进行结对编程(Driver-Navigator模式),一人负责写代码,另一人负责实时Code Review和逻辑检查。
- 联调阶段:针对出现的跨域问题(CORS)和云数据库连接超时问题,我们共同排查,最终通过优化后端连接池参数和前端请求逻辑解决了问题。
1.3 非摆拍的两人在讨论设计或结对编程过程的照片

二、原型设计
2.1 原型工具的选择
我们选择了 Figma 作为原型设计工具,并在后期结合 墨刀 进行交互演示。
- 选择理由:Figma 支持多人在线协作,方便我们在异地也能同时编辑同一个设计稿。其强大的组件库功能让我们能快速搭建出符合 Material Design 风格的界面。墨刀则用于快速生成可交互的演示链接,方便验证用户体验。
2.2 遇到的困难与解决办法
- 困难1:点名过程的紧张感营造
- 描述:最初设计仅是一个简单的文本跳动,缺乏课堂点名的“刺激感”。
- 解决:我们参考了类似抽奖系统的设计,引入了“滚动动画”和“减速停止”的视觉效果。通过 CSS 动画配合 JS 定时器,实现了名字从快速滚动到慢慢停下的效果。
- 困难2:复杂数据的移动端适配
- 描述:积分排行榜包含多个维度的数据(积分、点名次数),在手机端展示时容易拥挤。
- 解决:我们在原型中设计了响应式布局,在移动端自动隐藏次要信息,或将图表转换为更适合竖屏的列表形式。
2.3 原型作品链接
本作品需要在双终端下运行。
1. 后端启动 (Python)
确保已安装 Python 3.8+。
# 1. 安装依赖
pip install flask flask-cors pymysql
# 2. 启动服务 (默认端口 5000)
python server.py
注意:
server.py已配置为动态读取前端传来的数据库配置,并设置了 20s 的连接超时以适应慢速云数据库。
2. 前端启动 (React)
确保已安装 Node.js 16+。
# 1. 安装依赖
npm install
# 2. 启动开发服务器
npm run dev
访问链接 http://localhost:5173 即可使用。
2.4 原型界面图片展示
-
主界面(待机与点名中):界面简洁,左侧显示当前连接状态(本地/在线),中间为巨大的点名卡片。支持“随机点名”和“顺序点名”两种模式入口。

-
评分反馈弹窗:点名结束后自动弹出。设计了快捷评分按钮(出勤+1,复述准确+0.5等)。
创新点:支持触发“双倍积分”等随机事件的视觉反馈。

-
数据可视化看板:利用柱状图和折线图展示积分前10名的同学及其被点名次数,直观反映课堂活跃度。

-
数据库配置与管理:支持一键切换本地/云端模式,并提供 Excel 批量导入功能。
云端模式
本地离线模式
三、编程实现
3.1 开发工具库(如文件读取包等)的使用
本项目使用了以下关键库:
- 前端:
React 18+Vite:构建高性能前端应用。XLSX (SheetJS):用于在浏览器端解析 Excel 文件,实现名单导入。Dexie.js:封装 IndexedDB,实现浏览器的本地数据库存储。Recharts:基于 D3 的图表库,用于绘制积分排行榜。Tailwind CSS:原子化 CSS 框架,快速构建美观界面。
- 后端:
Flask:轻量级 Python Web 框架,提供 RESTful API。PyMySQL:用于连接云端 MySQL 数据库。Flask-CORS:解决前后端分离带来的跨域资源共享问题。
3.2 代码组织与内部实现设计(类图)
系统采用前后端分离架构。
- 前端 (App.tsx) 作为核心控制器,维护
currentStudent(当前学生)、dbMode(数据库模式)等全局状态。 - 服务层 (services/) 封装了
api.ts(云端交互) 和db.ts(本地存储),通过统一的接口(如addStudent,updateStudent)屏蔽了底层数据的差异,实现了“双模切换”对业务逻辑的透明化。 - 后端 (server.py) 采用工厂模式管理数据库连接,根据请求头动态连接不同的数据库实例。
3.3 说明算法的关键与关键实现部分流程图
核心算法:加权随机点名算法
为了实现“积分越高,被点概率越低”的需求,我们设计了反向加权算法。
- 计算每个学生的权重:
weight = 1 / (score + 1)(防止分数为0导致除零错误)。 - 计算总权重
totalWeight。 - 生成一个
0到totalWeight之间的随机数r。 - 遍历学生列表,累加权重,当累加值大于
r时,该学生即为中选者。

3.4 贴出重要的/有价值的代码片段并解释
片段1:前端乐观更新(Optimistic UI) 实现
为了解决连接云数据库时 2-3 秒 的延迟感,我们在提交评分时采用了“先更新界面,后同步数据”的策略。
// App.tsx
const handleGradingSubmit = async (delta: number) => {
// 1. 立即关闭弹窗,给用户极速响应
setShowGrading(false);
// 2. 【乐观更新】立即在本地修改显示的分数,不需要等数据库返回
if (dbMode === 'online') {
setRemoteStudents(prev => prev.map(s => {
// 匹配当前学生并更新视图
if (String(s.studentId) === String(currentStudent.studentId)) {
return { ...s, score: s.score + delta, callCount: s.callCount + 1 };
}
return s;
}));
}
// 3. 【后台静默同步】发送真实请求给后端,用户无需等待此处完成
try {
await api.updateStudent(currentStudent.studentId, {
score: currentStudent.score + delta,
callCount: currentStudent.callCount + 1
});
} catch (error) {
console.error("同步失败:", error); // 仅在控制台报错,不打断用户流程
}
};
片段2:后端动态数据库连接与超时控制
为了适应免费云数据库性能较差的情况,我们在后端增加了超时控制和重连机制。
# server.py
def get_db_connection():
# ... 从请求头获取配置 ...
try:
connection = pymysql.connect(
host=host,
user=user,
password=password,
database=database,
charset='utf8mb4',
connect_timeout=20, # 增加连接超时时间防止前端卡死
read_timeout=20,
write_timeout=20
)
return connection
except Exception as e:
print(f"Database connection error: {str(e)}")
return None
3.5 性能分析与改进
- 问题:在测试导入 50 人以上的名单到云数据库时,页面卡顿严重。
- 分析:最初的实现是循环发送 50 次
POST请求,每次请求都需要建立 TCP 连接和数据库握手,耗时极长且容易触发浏览器的并发限制。 - 改进:
- 后端新增
/api/students/batch批量插入接口,使用 SQL 的INSERT INTO ... VALUES (...), (...)语法。 - 前端改造导入逻辑,一次性将解析好的数组发送给后端。
- 结果:导入 50 人名单的时间从 15秒 缩短至 0.5秒。
- 后端新增
3.6 单元测试
我们编写了脚本对后端的随机算法API进行了统计学测试。
# test_random.py 部分代码
def test_weighted_random():
# 构造数据:A(0分), B(100分)
# 预期:A 的权重是 1/1=1,B 的权重是 1/101≈0.01
# A 被选中的概率应接近 99%
counts = {'A': 0, 'B': 0}
for _ in range(1000):
result = simulate_random_pick([student_A, student_B])
counts[result['name']] += 1
print(f"A: {counts['A']}, B: {counts['B']}")
assert counts['A'] > 900 # 验证概率分布是否符合预期
3.7 贴出代码commit记录

四、总结反思
4.1 本次任务的PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 60 | 45 |
| Estimate | 估计这个任务需要多少时间 | 30 | 30 |
| Development | 开发 | 1200 | 1450 |
| Analysis | 需求分析 (包括学习新技术) | 120 | 200 |
| Design Spec | 生成设计文档 | 60 | 60 |
| Design Review | 设计复审 | 30 | 45 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
| Design | 具体设计 | 120 | 150 |
| Coding | 具体编码 | 600 | 850 |
| Code Review | 代码复审 | 60 | 90 |
| Test | 测试(自我测试,修改代码,提交修改) | 180 | 300 |
| Reporting | 报告 | 60 | 90 |
| Test Report | 测试报告 | 30 | 30 |
| Size Measurement | 计算工作量 | 20 | 20 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 40 |
| 合计 | 2660 | 3420 |
4.2 学习进度条(每周追加)
| 第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
|---|---|---|---|---|---|
| 1 | 300 | 300 | 8 | 8 | 搭建React+Flask基础框架,打通前后端连接 |
| 2 | 800 | 1100 | 15 | 23 | 实现核心点名逻辑、IndexedDB本地存储及云端同步 |
| 3 | 500 | 1600 | 10 | 33 | 完成图表可视化、UI美化、解决CORS和死锁Bug |
4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?
- 差距分析:最初想象中,我们希望系统能像原生 App 一样流畅动画。但在实际开发中,受限于 Web 浏览器的性能和云数据库的网络延迟,在“在线模式”下的点名动画一度出现卡顿。
- 原因:
- 网络延迟:免费的云数据库服务器在海外,连接耗时较长(400ms+),导致交互产生裂痕。
- 技术选型:最初使用了轮询方式同步数据,效率低下。
- 弥补:我们后期引入了“乐观更新”策略,在视觉上欺骗了用户,让交互看起来是即时的,从而极大地缩小了最终成品与设计原型在体验上的差距。
4.4 评价你的队友
评价林得恺 [前端负责人]:
- 值得学习:对 UI 细节的把控非常到位,特别是那个“双倍积分”的弹出动画,极大地增加了系统的趣味性。解决问题非常执着,Recharts 图表对齐那个 Bug 熬夜修好了,令人佩服。
- 需要改进:有时候改代码比较急,变量名拼写容易出错(比如
setIsGradingModalOpen),以后可以多用 IDE 的自动补全。
评价林潇 [后端负责人]:
- 值得学习:逻辑思维严密,API 接口设计得很规范,不仅考虑了正常流程,还处理了 405、500 等各种异常情况。编写的数据库修复脚本帮了大忙。
- 需要改进:初期对前端 React 的机制不太了解,导致接口返回的数据结构不太符合前端预期,沟通成本稍高,建议以后可以多了解下游技术。
4.5 结对编程作业心得体会
林得恺 [前端负责人]:
本次结对编程最大的收获在于体会到了 “1+1>2” 的效应。
- 互补性:当一方陷入逻辑死胡同(例如处理图表对齐问题)时,另一方能从不同角度提出“加空格”这种跳出框架的解决方案,迅速破局。
- 代码质量:因为有 Code Review 环节,我们在提交代码前会不自觉地写得更规范,因为知道有另一个人在看。
- 全栈视野:虽然分工明确,但为了解决 Bug,我们都深入了解了对方的技术栈。前端学会了 SQL 优化,后端学会了 React 的生命周期,这对我们未来的职业发展大有裨益。
林潇 [后端负责人]:
本次结对编程任务主要收获如下:
-
多维视角打破思维定势:在解决“排行榜图表名字靠左”这个顽固 Bug 时,前端负责人陷入了查阅 CSS 和 Recharts 文档的死胡同,而后端负责人从数据处理的角度提出“在后端给名字加空格”的临时方案。虽然最终我们采用了更正规的前端
BarChart修复方案,但这种“一个问题,两种视角”的碰撞极大地拓宽了我们的调试思路。 -
技术约束驱动架构升级:最初我们因免费云数据库的高延迟而苦恼,认为这是不可抗力。但在结对讨论中,我们决定引入 “乐观更新 (Optimistic UI)” 策略。这一经历让我们明白,恶劣的外部条件往往能倒逼出更优秀的架构设计,最终成品的交互体验甚至优于本地模式。
-
代码质量与规范意识:引入 Code Review 机制后,我们发现很多低级错误(如
startSequentialCall中的定时器未清理导致的死锁)在合并代码前就被拦截了。这种写代码时知道有人在看的心理暗示,让我们在变量命名和错误处理(try-catch)上变得更加严谨。
1299

被折叠的 条评论
为什么被折叠?



