
<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'>

![1763741345921](image/wk/1763741345921.png)

</div>


#### 学生管理模块

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

![1763741409950](image/wk/1763741409950.png)

</div>


#### 积分管理模块

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

![1763741428619](image/wk/1763741428619.png)


</div>


#### 数据可视化模块

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

![1763741444137](image/wk/1763741444137.png)

</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'>

![1763882982337](image/实验报告/1763882982337.png)


![1763883004840](image/实验报告/1763883004840.png)

</div>


### 3.3 算法的关键与关键实现部分流程图（2分）

**加权随机选择算法流程图**：

<div class ='image-gallery'>

![1763883127026](image/2024软⼯K班结对编程任务/1763883127026.png)

</div>

**积分计算流程图**：



<div class ='image-gallery'>

![1763883216625](image/2024软⼯K班结对编程任务/1763883216625.png)

![1763883255812](image/2024软⼯K班结对编程任务/1763883255812.png)


</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'>

![1763782697976](image/wk/1763782697976.png)

</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. **工程实践意识**：理解了软件工程规范的重要性

**对课程的建议**：
- 希望有更多实际项目的练习机会
- 可以增加代码审查和项目演示环节
- 提供更详细的技术指导文档和示例代码

---
