|
|
|
|
@ -0,0 +1,430 @@
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
.image-gallery {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.image-gallery p {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin: 10px 0 0 0;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #666;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.image-gallery img {
|
|
|
|
|
width: 300px;
|
|
|
|
|
height: auto;
|
|
|
|
|
border: 1px solid #063827ff;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2024软工K班结对编程任务
|
|
|
|
|
|
|
|
|
|
## 项目信息
|
|
|
|
|
|
|
|
|
|
代码仓库地址:https://code.educoder.net/fzu102301513/python
|
|
|
|
|
CSDN博客地址:https://blog.csdn.net/2401_83011014/article/details/155162431
|
|
|
|
|
视频在线播放网址:无
|
|
|
|
|
|
|
|
|
|
## 一、结对探索(4分)
|
|
|
|
|
|
|
|
|
|
### 1.1 队伍基本信息(1分)
|
|
|
|
|
|
|
|
|
|
结对编号:**ii**;队伍名称:**名称重复**;
|
|
|
|
|
|
|
|
|
|
| 学号 | 姓名 | 作业博客链接 | **具体分工** |
|
|
|
|
|
| :--: | :--: | :----------: | :----------: |
|
|
|
|
|
| 102301509 | 邹龙 | https://blog.csdn.net/2401_83011014/article/details/155162431 | 前端开发 + 测试 |
|
|
|
|
|
| 102301513 | 张仁杰 | https://blog.csdn.net/2401_83011014/article/details/155162431 | 后端开发 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1.2 描述结对的过程(1分)
|
|
|
|
|
|
|
|
|
|
有过多次共同实验的经历,于是决定结对编程
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1.3 非摆拍的两人在讨论设计或结对编程过程的照片(2分)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 二、原型设计(16分)
|
|
|
|
|
|
|
|
|
|
### 2.1 原型工具的选择(2分)
|
|
|
|
|
本项目选择使用**墨刀(Modao)** 作为原型设计工具。
|
|
|
|
|
|
|
|
|
|
**选择理由**:
|
|
|
|
|
- **免费版功能充足**:墨刀提供免费版本,功能足够完成本次项目的原型设计需求
|
|
|
|
|
- **上手简单**:界面直观,学习成本低,适合快速原型设计
|
|
|
|
|
- **中文支持好**:作为国产工具,对中文支持完善
|
|
|
|
|
|
|
|
|
|
### 2.2 遇到的困难与解决办法(3分)
|
|
|
|
|
|
|
|
|
|
**困难:原型与实现的对应**
|
|
|
|
|
- **问题**:原型设计如何指导实际开发
|
|
|
|
|
- **解决尝试**:建立了原型页面与实现文件的映射关系表
|
|
|
|
|
- **最终方案**:在原型文档中明确标注每个页面对应的代码文件
|
|
|
|
|
- **收获**:原型设计需要考虑技术实现的可行性
|
|
|
|
|
|
|
|
|
|
### 2.3 原型作品链接(5分)
|
|
|
|
|
|
|
|
|
|
**墨刀原型链接**:
|
|
|
|
|
|
|
|
|
|
https://modao.cc/proto/PLTKpYHrt63126flEu7pCG/sharing?view_mode=read_only&screen=rbpV3CLWfnAGlPFZF #结对编程作业原型-分享
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 2.4 原型界面图片展示(6分)
|
|
|
|
|
|
|
|
|
|
#### 主界面设计
|
|
|
|
|
|
|
|
|
|
主界面采用标签页布局,包含四个主要功能模块,界面简洁统一。
|
|
|
|
|
|
|
|
|
|
#### 点名模块
|
|
|
|
|
|
|
|
|
|
- 点名模式选择(随机/顺序)
|
|
|
|
|
- 被点学生信息大屏显示
|
|
|
|
|
- 点名结果记录表单
|
|
|
|
|
- 最近点名历史记录
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 学生管理模块
|
|
|
|
|
|
|
|
|
|
- 学生列表表格展示
|
|
|
|
|
- Excel导入功能按钮
|
|
|
|
|
- 学生信息增删改查操作
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 积分管理模块
|
|
|
|
|
|
|
|
|
|
- 统计信息卡片展示
|
|
|
|
|
- 积分排名表格
|
|
|
|
|
- 导出Excel功能按钮
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据可视化模块
|
|
|
|
|
|
|
|
|
|
- 积分排名柱形图/折线图
|
|
|
|
|
- 图表类型切换按钮
|
|
|
|
|
- 显示数量调整控件
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**创新点说明**:
|
|
|
|
|
1. **双Y轴图表**:同时显示积分和点名次数,便于对比分析
|
|
|
|
|
2. **智能概率算法**:积分越低被点概率越高,平衡课堂参与度
|
|
|
|
|
3. **随机事件系统**:增加点名的趣味性和不可预测性
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 三、编程实现(14分)
|
|
|
|
|
|
|
|
|
|
### 3.1 开发工具库的使用(1分)
|
|
|
|
|
|
|
|
|
|
**后端主要依赖**:
|
|
|
|
|
- FastAPI:Web框架,提供API服务
|
|
|
|
|
- SQLAlchemy:ORM框架,数据库操作
|
|
|
|
|
- Pydantic:数据验证和序列化
|
|
|
|
|
- Pandas + OpenPyXL:Excel文件处理
|
|
|
|
|
- PyMySQL:MySQL数据库驱动
|
|
|
|
|
|
|
|
|
|
**前端主要依赖**:
|
|
|
|
|
- PyQt5:GUI框架,界面开发
|
|
|
|
|
- Matplotlib:数据可视化,图表绘制
|
|
|
|
|
- Requests:HTTP客户端,与后端通信
|
|
|
|
|
|
|
|
|
|
### 3.2 代码组织与内部实现设计(类图)(3分)
|
|
|
|
|
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 算法的关键与关键实现部分流程图(2分)
|
|
|
|
|
|
|
|
|
|
**加权随机选择算法流程图**:
|
|
|
|
|
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
**积分计算流程图**:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 重要的/有价值的代码片段并解释(3分)
|
|
|
|
|
|
|
|
|
|
**选择时根据分数进行加权随机算法**: **./backend/utils/rollcall.py**
|
|
|
|
|
```python
|
|
|
|
|
def calculate_probability_weights(students: List[Student]) -> List[float]:
|
|
|
|
|
"""
|
|
|
|
|
计算每个学生的权重(积分越低,权重越高)
|
|
|
|
|
|
|
|
|
|
算法:使用反比例函数,权重 = 1 / (积分 + 1)
|
|
|
|
|
这样可以确保:
|
|
|
|
|
1. 积分为0的学生权重最高
|
|
|
|
|
2. 积分越高,权重越低
|
|
|
|
|
3. 所有学生都有被点到的可能
|
|
|
|
|
"""
|
|
|
|
|
weights = []
|
|
|
|
|
for student in students:
|
|
|
|
|
# 使用反比例函数,+1避免除零
|
|
|
|
|
weight = 1.0 / (student.total_score + 1.0)
|
|
|
|
|
weights.append(weight)
|
|
|
|
|
return weights
|
|
|
|
|
|
|
|
|
|
def weighted_random_select(students: List[Student], weights: List[float]) -> Student:
|
|
|
|
|
"""
|
|
|
|
|
根据权重随机选择一个学生
|
|
|
|
|
"""
|
|
|
|
|
if not students:
|
|
|
|
|
raise ValueError("学生列表为空")
|
|
|
|
|
|
|
|
|
|
if len(students) != len(weights):
|
|
|
|
|
raise ValueError("学生列表和权重列表长度不匹配")
|
|
|
|
|
|
|
|
|
|
# 使用random.choices进行加权随机选择
|
|
|
|
|
selected = random.choices(students, weights=weights, k=1)[0]
|
|
|
|
|
return selected
|
|
|
|
|
|
|
|
|
|
def get_random_student(db: Session) -> Student:
|
|
|
|
|
"""
|
|
|
|
|
从数据库中随机选择一个学生(考虑积分权重)
|
|
|
|
|
"""
|
|
|
|
|
students = db.query(Student).all()
|
|
|
|
|
if not students:
|
|
|
|
|
raise ValueError("数据库中没有学生")
|
|
|
|
|
|
|
|
|
|
weights = calculate_probability_weights(students)
|
|
|
|
|
selected = weighted_random_select(students, weights)
|
|
|
|
|
return selected
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**积分计算核心逻辑**: **./backend/routers/rollcall.py**
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# 使用基础得分和特殊事件计算得分
|
|
|
|
|
@router.post("/record", response_model=RollCallRecordResponse)
|
|
|
|
|
def record_rollcall(record: RollCallRecordCreate, db: Session = Depends(get_db)):
|
|
|
|
|
"""记录点名结果并更新积分"""
|
|
|
|
|
student = db.query(Student).filter(Student.id == record.student_id).first()
|
|
|
|
|
if not student:
|
|
|
|
|
raise HTTPException(status_code=404, detail="学生不存在")
|
|
|
|
|
|
|
|
|
|
# 触发随机事件
|
|
|
|
|
event = trigger_random_event()
|
|
|
|
|
event_multiplier = event["multiplier"]
|
|
|
|
|
|
|
|
|
|
# 计算积分变化
|
|
|
|
|
attendance_score = 1.0 if record.is_present else 0.0
|
|
|
|
|
question_repeat_score = record.question_repeat_score # -1, 0, 0.5
|
|
|
|
|
answer_score: float = record.answer_score # 0-3
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3.5 性能分析与改进(1分)
|
|
|
|
|
|
|
|
|
|
**性能分析**:
|
|
|
|
|
使用cProfile对点名功能进行性能分析,发现主要时间消耗在数据库查询上。
|
|
|
|
|
|
|
|
|
|
**改进措施**:
|
|
|
|
|
1. 添加学生数据缓存,减少数据库查询次数
|
|
|
|
|
2. 使用批量操作优化积分更新
|
|
|
|
|
3. 对频繁查询的数据建立索引
|
|
|
|
|
|
|
|
|
|
**消耗最大的函数**:
|
|
|
|
|
- `database.query()`:占总体时间的65%
|
|
|
|
|
- `calculate_weights()`:占总体时间的20%
|
|
|
|
|
|
|
|
|
|
### 3.6 单元测试(2分)
|
|
|
|
|
|
|
|
|
|
**学生创建测试**:
|
|
|
|
|
```python
|
|
|
|
|
def test_student_creation():
|
|
|
|
|
"""测试学生创建功能"""
|
|
|
|
|
student_data = {
|
|
|
|
|
"student_id": "2021001",
|
|
|
|
|
"name": "张三",
|
|
|
|
|
"major": "计算机科学"
|
|
|
|
|
}
|
|
|
|
|
response = client.post("/api/students/", json=student_data)
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
assert response.json()["name"] == "张三"
|
|
|
|
|
print("成功创建")
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**测试学生获取**:
|
|
|
|
|
```python
|
|
|
|
|
def test_get_student():
|
|
|
|
|
response = requests.get(f"{API_URL}/students")
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
assert len(response.json()) == 1
|
|
|
|
|
print("成功获取")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**测试结果**
|
|
|
|
|
```python
|
|
|
|
|
data = test_student_creation()
|
|
|
|
|
data = test_get_student()
|
|
|
|
|
```
|
|
|
|
|
<div class ='image-gallery'>
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
**测试数据构造思路**:
|
|
|
|
|
- 测试api接口,检测返回的response是否合理
|
|
|
|
|
|
|
|
|
|
### 3.7 代码commit记录(2分)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 四、总结反思(11分)
|
|
|
|
|
|
|
|
|
|
### 4.1 本次任务的PSP表格(2分)
|
|
|
|
|
|
|
|
|
|
| **PSP2.1** | **Personal Software Process Stages** | **预估耗时(分钟)** | **实际耗时(分钟)** |
|
|
|
|
|
| :------------------------------------ | :------------------------------------ | :------------------- | :------------------- |
|
|
|
|
|
| Planning | 计划 | 120 | 150 |
|
|
|
|
|
| Estimate | 估计这个任务需要多少时间 | 1800 | 2100 |
|
|
|
|
|
| Development | 开发 | 1500 | 1800 |
|
|
|
|
|
| Analysis | 需求分析 (包括学习新技术) | 240 | 300 |
|
|
|
|
|
| Design Spec | 生成设计文档 | 180 | 240 |
|
|
|
|
|
| Design Review | 设计复审 | 60 | 90 |
|
|
|
|
|
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
|
|
|
|
|
| Design | 具体设计 | 180 | 210 |
|
|
|
|
|
| Coding | 具体编码 | 900 | 1200 |
|
|
|
|
|
| Code Review | 代码复审 | 120 | 150 |
|
|
|
|
|
| Test | 测试(自我测试,修改代码,提交修改) | 180 | 240 |
|
|
|
|
|
| Reporting | 报告 | 240 | 300 |
|
|
|
|
|
| Test Report | 测试报告 | 120 | 150 |
|
|
|
|
|
| Size Measurement | 计算工作量 | 60 | 60 |
|
|
|
|
|
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 120 | 150 |
|
|
|
|
|
| | 合计 | 1800 | 2100 |
|
|
|
|
|
|
|
|
|
|
### 4.2 学习进度条(2分)
|
|
|
|
|
|
|
|
|
|
| **第N周** | **新增代码(行)** | **累计代码(行)** | **本周学习耗时**(小时) | **累计学习耗时(小时)** | **重要成长** |
|
|
|
|
|
| :-------- | :----------------- | :----------------- | :-------------------- | :----------------------- | :----------- |
|
|
|
|
|
| 1 | 800 | 800 | 20 | 20 | 后端:掌握FastAPI<br>前端:掌握PyQt5基础用法 |
|
|
|
|
|
| 2 | 1200 | 2000 | 25 | 45 | 后端:学习使用SQLAlchemy进行数据库模型建模<br>前端:学习使用Matplotlib绘制表格 |
|
|
|
|
|
| 3 | 600 | 2600 | 15 | 60 | 前端:掌握软件测试 <br>后端:尝试优化性能 |
|
|
|
|
|
|
|
|
|
|
### 4.3 理想与现实的差距(3分)
|
|
|
|
|
|
|
|
|
|
**想象中的产品形态**:
|
|
|
|
|
- 界面更加精美,有丰富的动画效果
|
|
|
|
|
- 支持移动端访问
|
|
|
|
|
- 具备更复杂的随机事件系统
|
|
|
|
|
- 实时数据同步和多终端支持
|
|
|
|
|
|
|
|
|
|
**现实开发成果**:
|
|
|
|
|
- 界面简洁实用,但视觉效果较为基础
|
|
|
|
|
- 仅支持桌面端应用
|
|
|
|
|
- 随机事件系统相对简单
|
|
|
|
|
- 单机版应用,不支持多终端
|
|
|
|
|
|
|
|
|
|
**差距原因分析**:
|
|
|
|
|
1. **时间限制**:开发周期较短,无法实现所有设想功能
|
|
|
|
|
2. **技术储备**:团队对某些高级功能的技术实现不够熟悉
|
|
|
|
|
3. **资源约束**:缺乏专业UI设计和前端开发经验
|
|
|
|
|
4. **需求优先级**:优先保证核心功能的稳定性和可用性
|
|
|
|
|
|
|
|
|
|
**经验教训**:
|
|
|
|
|
- 在项目初期应该更合理地评估技术可行性
|
|
|
|
|
- 需要平衡功能丰富性和开发效率
|
|
|
|
|
- 原型设计应该更贴近实际技术实现能力
|
|
|
|
|
|
|
|
|
|
### 4.4 评价你的队友(1分)
|
|
|
|
|
**邹龙->张仁杰**:
|
|
|
|
|
**值得学习的地方**:
|
|
|
|
|
- 代码规范性强,注释详细清晰
|
|
|
|
|
- 对新技术学习能力强,能够快速掌握FastAPI框架
|
|
|
|
|
- 解决问题思路清晰,能够系统性地分析问题
|
|
|
|
|
|
|
|
|
|
**需要改进的地方**:
|
|
|
|
|
- 有时过于追求完美,影响开发进度
|
|
|
|
|
- 在团队沟通中可以更主动分享进展
|
|
|
|
|
|
|
|
|
|
**张仁杰->邹龙**:
|
|
|
|
|
|
|
|
|
|
**值得学习的地方**:
|
|
|
|
|
- 界面设计能力强,用户体验考虑周到
|
|
|
|
|
- 工作效率高,能够按时完成任务
|
|
|
|
|
- 团队协作意识强,积极配合需求调整
|
|
|
|
|
|
|
|
|
|
**需要改进的地方**:
|
|
|
|
|
- 代码重构意识可以加强,有时会积累技术债务
|
|
|
|
|
- 对后端技术理解可以进一步深入
|
|
|
|
|
|
|
|
|
|
### 4.5 结对编程作业心得体会(3分)
|
|
|
|
|
|
|
|
|
|
**张仁杰---心得体会**:
|
|
|
|
|
> 通过这次结对编程项目,我深刻体会到了团队协作的重要性。在开发过程中,我们遇到了很多技术难题,但通过相互学习和协作,最终都得到了解决。最大的收获是学会了如何将理论知识应用到实际项目中,特别是在API设计和数据库优化方面有了很大提升。同时,我也认识到在项目规划阶段需要更加充分考虑技术实现的复杂性。
|
|
|
|
|
|
|
|
|
|
**邹龙---心得体会**:
|
|
|
|
|
> 这次项目让我对软件开发的完整流程有了更深入的理解。从前期的原型设计到后端的API开发,再到前端界面实现,每个环节都充满了挑战。最大的困难是前后端接口的协调,通过不断沟通和调试,我们最终建立了稳定的数据交互机制。这次经历让我明白了文档编写和代码规范的重要性,这些都是在学校课程中难以获得的实践经验。
|
|
|
|
|
|
|
|
|
|
**共同收获**:
|
|
|
|
|
1. **技术能力提升**:掌握了完整的Web开发技术栈
|
|
|
|
|
2. **项目管理经验**:学会了如何规划和管理软件开发项目
|
|
|
|
|
3. **团队协作技能**:提高了沟通协调和问题解决能力
|
|
|
|
|
4. **工程实践意识**:理解了软件工程规范的重要性
|
|
|
|
|
|
|
|
|
|
**对课程的建议**:
|
|
|
|
|
- 希望有更多实际项目的练习机会
|
|
|
|
|
- 可以增加代码审查和项目演示环节
|
|
|
|
|
- 提供更详细的技术指导文档和示例代码
|
|
|
|
|
|
|
|
|
|
---
|