save docs

This commit is contained in:
2026-05-07 14:56:53 +08:00
parent 037be95a7d
commit 78aaebcd89
7 changed files with 819 additions and 6 deletions

5
.gitignore vendored
View File

@@ -31,10 +31,6 @@ Thumbs.db
*.log *.log
*.txt *.txt
# Excel files (示例数据)
老师信息示例.xlsx
学生信息示例.xlsx
匹配结果示例.xlsx
# Certificates # Certificates
*.pfx *.pfx
@@ -49,4 +45,3 @@ Thumbs.db
# Documentation (auto-generated) # Documentation (auto-generated)
*.html *.html
*.md

105
debug_match.py Normal file
View File

@@ -0,0 +1,105 @@
import pandas as pd
df_teachers = pd.read_excel('老师信息示例.xlsx')
df_students = pd.read_excel('学生信息示例.xlsx')
teachers = []
for _, row in df_teachers.iterrows():
availability = {}
for col in df_teachers.columns:
if col not in ['老师姓名', '老师类型']:
val = row.get(col, '')
if pd.notna(val) and str(val).strip():
availability[col] = str(val)
teachers.append({
'id': row['老师姓名'],
'name': row['老师姓名'],
'type': row['老师类型'],
'availability': availability
})
students = []
for _, row in df_students.iterrows():
history_str = row.get('历史匹配老师', '')
history = []
if pd.notna(history_str) and str(history_str).strip():
history = [t.strip() for t in str(history_str).split(',')]
availability = {}
for col in df_students.columns:
if col not in ['学生姓名', '历史匹配老师']:
val = row.get(col, '')
if pd.notna(val) and str(val).strip():
availability[col] = str(val)
students.append({
'id': row['学生姓名'],
'name': row['学生姓名'],
'availability': availability,
'history': history
})
print('=== 检查数据导入 ===')
print(f'老师数量: {len(teachers)}')
print(f'学生数量: {len(students)}')
print()
print('=== 检查老师类型分布 ===')
new_count = sum(1 for t in teachers if t['type'] == '')
old_count = sum(1 for t in teachers if t['type'] == '')
print(f'新老师: {new_count}, 旧老师: {old_count}')
print()
print('=== 检查学生历史记录分布 ===')
history_counts = {}
for s in students:
cnt = len(s['history'])
history_counts[cnt] = history_counts.get(cnt, 0) + 1
print('学生历史记录数量分布:')
for cnt in sorted(history_counts.keys()):
print(f' {cnt} 个历史老师: {history_counts[cnt]}')
print()
def parse_slots(time_str):
slots = []
for slot in time_str.split(';'):
slot = slot.strip()
if slot and '-' in slot:
parts = slot.split('-')
if len(parts) == 2:
slots.append((parts[0].strip(), parts[1].strip()))
return slots
print('=== 检查时间段匹配情况 ===')
for student in students[:5]:
history_count = len(student['history'])
expected_type = '' if history_count == 0 else ('' if history_count % 2 == 1 else '')
print(f'\n学生: {student["name"]}')
print(f' 期望老师类型: {expected_type}')
print(f' 可用时间: {student["availability"]}')
print(f' 历史老师: {student["history"]}')
found_match = False
for teacher in teachers:
if teacher['type'] != expected_type:
continue
if teacher['id'] in student['history']:
continue
for day, s_time in student['availability'].items():
if day not in teacher['availability']:
continue
t_time = teacher['availability'][day]
s_slots = parse_slots(s_time)
t_slots = parse_slots(t_time)
for s_start, s_end in s_slots:
for t_start, t_end in t_slots:
if s_start == t_start and s_end == t_end:
print(f'{teacher["name"]}{day} 有匹配时间段: {s_start}-{s_end}')
found_match = True
if not found_match:
print(f' ✗ 未找到匹配的老师')

BIN
匹配结果示例.xlsx Normal file

Binary file not shown.

BIN
学生信息示例.xlsx Normal file

Binary file not shown.

558
开发文档.md Normal file
View File

@@ -0,0 +1,558 @@
# 老师学员匹配系统 - 开发文档
## 项目概述
一个用于老师和学生智能匹配的桌面应用程序基于Flet框架开发支持时间兼容性检查、历史匹配记录规避、新/旧老师交替匹配、每日唯一性约束等功能。
## 技术栈
| 技术 | 版本 | 用途 |
|------|------|------|
| Python | 3.13+ | 开发语言 |
| Flet | 0.80.4+ | UI框架基于Flutter |
| pandas | 2.3+ | Excel数据处理 |
| openpyxl | 3.1+ | Excel文件读写 |
| PyInstaller | 6.16+ | 打包工具 |
## 项目结构
```
paike/
├── main.py # 主程序入口
├── build.bat # 打包脚本
├── requirements.txt # 依赖列表(可选)
├── 老师信息示例.xlsx # 老师数据示例
├── 学生信息示例.xlsx # 学生数据示例
├── generate_test_data.py # 测试数据生成脚本
├── dist/ # 打包输出目录
│ ├── main.exe # 打包后的可执行文件
│ ├── 老师信息示例.xlsx
│ └── 学生信息示例.xlsx
└── build/ # PyInstaller构建缓存
```
## 核心功能需求
### 1. 数据导入
- 从Excel文件导入老师信息包含老师类型
- 从Excel文件导入学生信息包含历史匹配
- 支持的文件格式:`.xlsx`
### 2. 匹配规则(按优先级)
| 优先级 | 规则 | 类型 | 说明 |
|-------|------|------|------|
| 1 | 首次上课限制 | 硬约束 | 学生第一次上课只能匹配旧老师 |
| 2 | 交替匹配规则 | 硬约束 | 后续上课按"新老师→旧老师→新老师→..."交替 |
| 3 | 历史匹配规避 | 硬约束 | 学生不能匹配之前上过课的老师 |
| 4 | 每日唯一性 | 硬约束 | 每位老师每天只能接待一位学生 |
| 5 | 均衡分配 | 软约束 | 优先匹配次数少的老师 |
### 3. 结果导出
- 导出匹配结果到Excel文件
- 用户可选择保存位置
- 中文列标题
## 数据格式规范
### 老师信息Excel格式
| 列名 | 数据类型 | 说明 | 示例 |
|------|----------|------|------|
| 老师姓名 | 字符串 | 老师唯一标识 | 张1老师 |
| 老师类型 | 字符串 | 新老师/旧老师 | 旧老师 |
| 备注 | 字符串 | 备注信息(可选) | 数学老师 |
| 1月1日 | 字符串 | 可用时间段(分号分隔) | 9:00-10:30; 14:00-15:30 |
| 1月2日 | 字符串 | 可用时间段(分号分隔) | 10:30-12:00 |
| ... | ... | ... | ... |
**注意**
- 时间段格式:`开始时间-结束时间`
- 多个时间段用分号`;`分隔
- 没有可用时间的日期留空
### 学生信息Excel格式
| 列名 | 数据类型 | 说明 | 示例 |
|------|----------|------|------|
| 学生姓名 | 字符串 | 学生唯一标识 | 学生1 |
| 历史匹配老师 | 字符串 | 历史老师姓名(逗号分隔) | 张1老师,张2老师 |
| 备注 | 字符串 | 备注信息(可选) | |
| 1月1日 | 字符串 | 可用时间段(分号分隔) | 9:00-10:30; 14:00-15:30 |
| 1月2日 | 字符串 | 可用时间段(分号分隔) | 10:30-12:00 |
| ... | ... | ... | ... |
### 匹配结果Excel格式
| 列名 | 说明 |
|------|------|
| 学生 | 学生姓名 |
| 老师 | 匹配的老师姓名 |
| 日期 | 匹配日期 |
| 时段 | 匹配时间段 |
| 状态 | 成功/未匹配 |
## 代码架构
### 主类TeacherStudentMatcher
```python
class TeacherStudentMatcher:
def __init__(self, page: ft.Page):
# 初始化页面配置
self.page.title = "老师学员匹配系统"
self.page.window_width = 1400
self.page.window_height = 800
# 数据存储
self.teachers = [] # 老师列表
self.students = [] # 学生列表
self.matches = [] # 匹配结果
```
### 核心数据结构
```python
# 老师数据结构
teacher = {
"id": "老师姓名",
"name": "老师姓名",
"type": "旧老师", # 新增:老师类型
"availability": {
"1月1日": "9:00-10:30; 14:00-15:30",
"1月2日": "10:30-12:00",
# ...
},
"other": "备注信息"
}
# 学生数据结构
student = {
"id": "学生姓名",
"name": "学生姓名",
"availability": {
"1月1日": "9:00-10:30; 14:00-15:30",
# ...
},
"history": ["张1老师", "张2老师"], # 历史匹配老师列表
"other": "备注信息"
}
# 匹配结果结构
match = {
"student_name": "学生姓名",
"teacher_name": "老师姓名",
"match_date": "1月1日",
"match_period": "9:00-10:30",
"status": "成功"
}
```
### 核心方法
#### 1. UI初始化
```python
def setup_ui(self):
# 创建页面布局:三栏布局
# - 顶部标题栏
# - 操作按钮栏
# - 主内容区(老师信息 | 学生信息 | 匹配结果)
```
#### 2. 数据导入
```python
def import_teachers(self, e):
# 使用tkinter文件对话框选择Excel文件
# 解析Excel数据提取老师信息
# 动态列(日期)作为可用时间段存储
# 新增:解析"老师类型"字段
def import_students(self, e):
# 使用tkinter文件对话框选择Excel文件
# 解析Excel数据提取学生信息
# 历史匹配老师用逗号分隔
# 动态列(日期)作为可用时间段存储
```
#### 3. 时间段解析
```python
def parse_time_slots(self, time_str):
# 输入: "9:00-10:30; 14:00-15:30"
# 输出: [("9:00", "10:30"), ("14:00", "15:30")]
#
# 解析逻辑:
# 1. 按分号分割时间段
# 2. 每个时间段按短横线分割起始和结束时间
# 3. 返回时间对元组列表
```
#### 4. 匹配算法
```python
def start_match(self, e):
# 匹配流程:
# 1. 初始化数据结构
# - teacher_assigned_days: 记录老师已分配的日期(新增)
# - teacher_match_count: 记录每个老师已匹配的学生数
#
# 2. 遍历每个学生
# a. 计算期望老师类型(新增逻辑)
# - 历史记录为空 → 旧老师
# - 历史记录奇数 → 新老师
# - 历史记录偶数 → 旧老师
# b. 收集所有可能的匹配
# - 遍历所有老师
# - 跳过历史匹配过的老师
# - 检查老师类型是否符合期望(新增)
# - 检查时间兼容性
# - 检查老师该日期是否已被分配(新增:按日期而非时段)
#
# c. 选择最优匹配
# - 按老师已匹配次数升序排序(优先选择匹配次数少的老师)
# - 选择第一个(匹配次数最少的)
#
# d. 更新状态
# - 记录匹配结果
# - 更新学生的历史匹配记录
# - 标记老师该日期已分配(新增:按日期)
# - 增加老师的匹配计数
#
# e. 处理未匹配情况
# - 如果没有可用的匹配,记录状态为"未匹配"
```
#### 5. 结果导出
```python
def export_results(self, e):
# 使用tkinter文件对话框让用户选择保存位置
# 导出为Excel文件中文列标题
```
## 匹配算法详解
### 贪心匹配策略
本系统采用贪心算法实现匹配,优先考虑:
1. **首次上课限制**(硬约束)
- 如果学生没有历史匹配记录,只能匹配旧老师
- 确保新学生由经验丰富的老师指导
2. **交替匹配规则**(硬约束)
- 根据历史匹配次数的奇偶性决定期望老师类型
- 历史次数为偶数包括0→ 期望旧老师
- 历史次数为奇数 → 期望新老师
- 实现新/旧老师交替教学
3. **历史匹配规避**(硬约束)
- 如果学生与某老师有过匹配记录,跳过该老师
- 确保每个学生接触不同的老师
4. **每日唯一性**(硬约束)
- 每位老师每天只能接待一位学生
- 使用`teacher_assigned_days`字典追踪已分配日期
- 老师某天被匹配后,当天其他时段不再接受预约
5. **时间兼容性**(硬约束)
- 学生和老师必须在同一天有相同的时间段
- 时间段必须完全一致如都是9:00-10:30
6. **均衡分配**(软约束/优化目标)
- 优先选择匹配次数较少的老师
- 让更多老师参与到匹配中
- 使用`teacher_match_count`字典实现
### 伪代码
```
for each student in students:
possible_matches = []
# 计算期望老师类型(新增逻辑)
history_count = len(student.history)
if history_count == 0:
expected_type = "旧老师" # 首次上课
elif history_count % 2 == 1:
expected_type = "新老师" # 第2,4,6...次
else:
expected_type = "旧老师" # 第3,5,7...次
for each teacher in teachers:
if teacher in student.history:
continue # 跳过历史老师
if teacher.type != expected_type:
continue # 跳过类型不匹配的老师(新增)
for each (day, student_time) in student.availability:
if day not in teacher.availability:
continue
if day in teacher_assigned_days[teacher]:
continue # 老师当天已被预约(新增)
teacher_time = teacher.availability[day]
if student_time and teacher_time:
student_slots = parse_time_slots(student_time)
teacher_slots = parse_time_slots(teacher_time)
for each (s_start, s_end) in student_slots:
for each (t_start, t_end) in teacher_slots:
if s_start == t_start and s_end == t_end:
possible_matches.append((teacher, day, s_start, s_end))
if possible_matches:
# 按老师匹配次数升序排序
possible_matches.sort(key=lambda x: teacher_match_count[x[0]])
teacher, day, s_start, s_end = possible_matches[0]
# 创建匹配记录
create_match(student, teacher, day, s_start, s_end, "成功")
# 更新状态
student.history.append(teacher)
teacher_assigned_days[teacher].add(day) # 标记日期已分配(修改)
teacher_match_count[teacher] += 1
else:
# 没有可用匹配
create_match(student, null, "-", "-", "-", "未匹配")
```
## UI设计规范
### 配色方案
| 用途 | 颜色代码 | 说明 |
|------|----------|------|
| 标题文字 | #1a1a2e | 深色标题 |
| 主色调 | #2563eb | 主要操作按钮(蓝色) |
| 成功色 | #10b981 | 成功状态(绿色) |
| 警告色 | #f59e0b | 警告状态(橙色) |
| 错误色 | #ef4444 | 错误状态(红色) |
| 背景色 | #f8f9fa | 页面背景 |
| 卡片背景 | #ffffff | 卡片白色背景 |
| 边框色 | #f0f0f0 | 细微边框 |
| 新老师标识 | #2563eb | 蓝色 |
| 旧老师标识 | #10b981 | 绿色 |
### 布局结构
```
┌─────────────────────────────────────────────────────────────────┐
│ 老师学员匹配系统 [按钮组] │
│ Teacher-Student Matching System │
├─────────────────────────────────────────────────────────────────┤
│ 数据操作 │ 导入老师 │ 导入学生 │ 匹配操作 │ 开始匹配 │ 导出 │ 清空 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ 老师信息 │ │ 学生信息 │ │ 匹配结果 │ │
│ │ Teacher Info │ │ Student Info │ │ Matching R. │ │
│ ├─────────────────────┤ ├─────────────────┤ ├─────────────┤ │
│ │ 姓名 │ 类型 │ 备注 │ │ 姓名│历史│备注 │ │ 学生│老师│...│ │
│ ├─────────────────────┤ ├─────────────────┤ ├─────────────┤ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ └─────────────────────┘ └─────────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### 窗口配置
```python
self.page.window_width = 1400 # 窗口宽度
self.page.window_height = 800 # 窗口高度
self.page.theme_mode = ft.ThemeMode.LIGHT # 浅色主题
```
## Flet API兼容性说明
### Flet 0.80.4 版本API
本项目针对Flet 0.80.4版本编写使用了以下兼容API
```python
# 颜色使用字符串而非ft.colors枚举
ft.Text("text", color="#333333") # ✓ 正确
ft.Text("text", color=ft.colors.WHITE) # ✗ 已废弃
# 对齐使用Alignment类
ft.alignment.Alignment(0, 0) # ✓ 正确
ft.alignment.top_left # ✗ 已废弃
# 边框使用Border类
ft.Border.all(1, "#e0e0e0") # ✓ 正确
ft.border.all(1, "#e0e0e0") # ✗ 已废弃
# 内边距使用Padding类
ft.Padding.only(left=20, right=20) # ✓ 正确
ft.padding.only(left=20, right=20) # ✗ 已废弃
# 外边距使用Margin类
ft.Margin.only(left=20, right=20) # ✓ 正确
ft.margin.only(left=20, right=20) # ✗ 已废弃
# 按钮使用Button而非ElevatedButton
ft.Button(...) # ✓ 正确
ft.ElevatedButton(...) # ✗ 已废弃
# SnackBar使用page.snack_bar属性
self.page.snack_bar = ft.SnackBar(...)
self.page.snack_bar.open = True # ✓ 正确
self.page.show_snack_bar(...) # ✗ 已废弃
# 应用入口使用ft.run
ft.run(main) # ✓ 正确
ft.app(target=main) # ✗ 已废弃
# 表格边框使用BorderSide
ft.border.BorderSide(1, "#e0e0e0") # ✓ 正确
```
## 文件选择对话框
由于Flet的FilePicker在不同版本中存在兼容性问题本项目使用tkinter的filedialog作为替代
```python
import threading
from tkinter import filedialog
import tkinter as tk
def ask_file():
root = tk.Tk()
root.withdraw()
root.attributes('-topmost', True) # 置顶显示
file_path = filedialog.askopenfilename(
title="选择文件",
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
)
result['path'] = file_path
root.destroy()
thread = threading.Thread(target=ask_file)
thread.start()
thread.join()
file_path = result.get('path', '')
```
## 安装和运行
### 开发环境运行
```bash
pip install flet pandas openpyxl
python main.py
```
### 打包为exe
```batch
@echo off
pip install pyinstaller pandas openpyxl flet
pyinstaller --onefile --windowed main.py
```
### 打包配置优化
排除不必要的模块以减小打包体积:
```batch
pyinstaller --onefile --windowed ^
--exclude-module=torch ^
--exclude-module=torchvision ^
--exclude-module=transformers ^
--exclude-module=scipy ^
--exclude-module=matplotlib ^
--exclude-module=pandas.plotting ^
main.py
```
## 测试数据生成
```python
import pandas as pd
import random
random.seed(42)
days = ['1月1日', '1月2日', '1月3日', '1月4日', '1月5日', '1月6日', '1月7日']
time_slots = ['9:00-10:30', '10:30-12:00', '14:00-15:30', '15:30-17:00', '18:00-19:30']
# 生成10个老师5旧5新
teacher_names = [f"{i}老师" for i in range(1, 11)]
teacher_types = ["旧老师", "旧老师", "旧老师", "新老师", "新老师", "旧老师", "新老师", "旧老师", "新老师", "旧老师"]
teachers = []
for i, name in enumerate(teacher_names):
teacher = {"老师姓名": name}
teacher["老师类型"] = teacher_types[i]
available_days = random.sample(days, 2) # 每人随机2天空闲
for day in days:
if day in available_days:
num_slots = random.randint(2, 3) # 每天2-3个时间段
teacher[day] = '; '.join(random.sample(time_slots, num_slots))
else:
teacher[day] = ''
teacher["备注"] = ""
teachers.append(teacher)
df_teachers = pd.DataFrame(teachers)
df_teachers.to_excel('老师信息示例.xlsx', index=False)
# 生成20个学生
student_names = [f"学生{i}" for i in range(1, 21)]
students = []
for i, name in enumerate(student_names):
student = {"学生姓名": name}
available_days = random.sample(days, random.randint(3, 5)) # 3-5天空闲
for day in days:
if day in available_days:
num_slots = random.randint(2, 3)
student[day] = '; '.join(random.sample(time_slots, num_slots))
else:
student[day] = ''
# 每个学生有0-3个历史老师
history_count = min(3, i)
history_teachers = random.sample([t for t in teacher_names if t != name], history_count)
student["历史匹配老师"] = ', '.join(history_teachers)
student["备注"] = ""
students.append(student)
df_students = pd.DataFrame(students)
df_students.to_excel('学生信息示例.xlsx', index=False)
```
## 常见问题排查
### 1. 打包后文件选择对话框不显示
- 确保使用tkinter的filedialog而非Flet的FilePicker
- 在独立线程中运行对话框
### 2. SnackBar不显示
- 使用`page.snack_bar`属性而非`show_snack_bar()`方法
- 设置`open = True`来显示
### 3. 表格不显示数据
- 确保调用`page.update()`刷新界面
- 检查数据是否正确解析
### 4. 匹配结果不正确
- 检查时间段格式是否正确(使用分号分隔)
- 检查历史老师名称是否与老师姓名完全匹配
- 检查老师类型是否正确标记
## 项目交付清单
- [x] main.py - 主程序
- [x] build.bat - 打包脚本
- [x] 需求文档.md - 需求说明文档
- [x] 开发文档.md - 技术实现文档
- [x] 老师信息示例.xlsx - 老师测试数据
- [x] 学生信息示例.xlsx - 学生测试数据
- [x] generate_test_data.py - 测试数据生成脚本
- [x] dist/main.exe - 打包后的可执行文件
## 版本历史
| 版本 | 日期 | 更新内容 |
|------|------|----------|
| 1.0 | 2026-04-19 | 初始版本,实现核心匹配功能 |
| 1.1 | 2026-04-25 | 新增每日唯一性约束(老师每天只能接待一位学生) |
| 1.2 | 2026-04-28 | 新增老师类型标记、首次上课限制、交替匹配规则 |

BIN
老师信息示例.xlsx Normal file

Binary file not shown.

155
需求文档.md Normal file
View File

@@ -0,0 +1,155 @@
# 老师学员匹配系统需求文档
## 1. 项目概述
本系统旨在实现老师和学员的自动匹配功能,根据双方的可用时间进行智能匹配,并生成匹配结果。
## 2. 功能需求
### 2.1 基础功能
- **老师管理**支持通过Excel导入老师信息包含老师类型标记
- **时间数据导入**通过Excel文件导入老师和学生的可用时间
- **智能匹配**:根据时间兼容性自动匹配老师和学生
- **匹配结果导出**生成Excel格式的匹配结果
- **历史匹配记录**:记录学生与老师的历史匹配情况,避免重复匹配
### 2.2 核心匹配规则(按优先级)
1. **首次上课限制**:学生第一次上课只能匹配旧老师
2. **交替匹配规则**:后续上课按"新老师→旧老师→新老师→..."交替进行
3. **历史匹配规避**:学生不能匹配之前上过课的老师
4. **每日唯一性**:每位老师每天只能接待一位学生
5. **均衡分配**:优先匹配次数少的老师,让更多老师参与
### 2.3 核心流程
1. 导入老师信息(包含老师类型)和可用时间
2. 导入学生信息(包含历史匹配)和可用时间
3. 系统自动匹配老师和学生
4. 生成匹配结果并导出
5. 记录匹配历史
## 3. 数据结构
### 3.1 老师数据结构
| 字段名 | 数据类型 | 说明 |
|-------|---------|------|
| 老师ID | 字符串 | 唯一标识 |
| 姓名 | 字符串 | 老师姓名 |
| 老师类型 | 字符串 | 新老师/旧老师 |
| 可用时间 | 时间列表 | 每个日期的可用时间段 |
| 其他信息 | 字符串 | 可选的额外信息 |
### 3.2 学生数据结构
| 字段名 | 数据类型 | 说明 |
|-------|---------|------|
| 学生ID | 字符串 | 唯一标识 |
| 姓名 | 字符串 | 学生姓名 |
| 可用时间 | 时间列表 | 每个日期的可用时间段 |
| 历史匹配老师 | 老师ID列表 | 曾经匹配过的老师 |
| 其他信息 | 字符串 | 可选的额外信息 |
### 3.3 匹配结果数据结构
| 字段名 | 数据类型 | 说明 |
|-------|---------|------|
| 匹配ID | 字符串 | 唯一标识 |
| 学生ID | 字符串 | 学生标识 |
| 老师ID | 字符串 | 老师标识 |
| 匹配日期 | 日期 | 匹配的具体日期 |
| 匹配时段 | 时间段 | 具体上课时间段 |
| 状态 | 字符串 | 匹配状态(成功/未匹配) |
## 4. Excel格式设计
### 4.1 老师信息Excel格式
| 列名 | 说明 |
|-----|------|
| 老师姓名 | 唯一标识 |
| 老师类型 | 新老师/旧老师 |
| 备注 | 可选的额外信息 |
| 1月1日 | 可用时间段9:00-11:00;14:00-16:00 |
| 1月2日 | 可用时间段 |
| ... | ... |
### 4.2 学生信息Excel格式
| 列名 | 说明 |
|-----|------|
| 学生姓名 | 唯一标识 |
| 历史匹配老师 | 曾经匹配过的老师姓名,用逗号分隔 |
| 备注 | 可选的额外信息 |
| 1月1日 | 可用时间段 |
| 1月2日 | 可用时间段 |
| ... | ... |
### 4.3 匹配结果Excel格式
| 列名 | 说明 |
|-----|------|
| 学生 | 学生姓名 |
| 老师 | 匹配的老师姓名 |
| 日期 | 匹配日期 |
| 时段 | 匹配的时间段 |
| 状态 | 匹配状态 |
## 5. 技术要求
### 5.1 开发环境
- 操作系统Windows
- 开发语言Python打包为EXE
- 依赖库:
- pandas处理Excel文件
- openpyxlExcel文件读写
- FletGUI界面
- pyinstaller打包为EXE
### 5.2 性能要求
- 支持至少100名学生和20名老师的匹配
- 匹配过程响应时间不超过10秒
## 6. 界面设计
### 6.1 主界面
- 老师管理区域:显示老师列表(包含类型标识)
- 数据导入区域提供Excel文件选择和导入按钮
- 匹配控制区域:开始匹配按钮
- 结果显示区域:显示匹配结果
- 导出区域:导出匹配结果按钮
### 6.2 操作流程
1. 用户打开软件
2. 导入老师Excel文件包含类型信息
3. 导入学生Excel文件包含历史匹配
4. 点击开始匹配按钮
5. 查看匹配结果
6. 导出匹配结果到Excel文件
## 7. 其他需要讨论的点
1. **匹配算法**:具体的匹配规则和优先级如何确定?
2. **时间冲突处理**:如果多个学生同时匹配到同一个老师的同一天,如何处理?
3. **数据验证**如何验证导入的Excel数据格式是否正确
4. **错误处理**:当匹配失败或数据异常时,如何提示用户?
5. **历史数据存储**:历史匹配记录如何存储和管理?
6. **用户权限**:是否需要不同级别的用户权限?
7. **界面语言**:是否需要支持多语言?
8. **系统兼容性**支持的Windows版本范围
9. **安装部署**:是否需要安装程序或绿色版?
10. **更新机制**:如何进行系统更新?
## 8. 项目计划
1. **需求分析与设计**1天
2. **数据结构实现**1天
3. **Excel文件处理**1天
4. **匹配算法实现**2天
5. **GUI界面开发**2天
6. **测试与调试**2天
7. **打包与部署**1天
## 9. 验收标准
1. 系统能够正确导入老师和学生的Excel文件
2. 系统能够根据时间兼容性自动匹配老师和学生
3. 系统能够避免重复匹配历史上已经匹配过的老师和学生
4. 系统能够确保每位老师每天只接待一位学生
5. 系统能够按规则分配新/旧老师(首次→旧老师,后续交替)
6. 系统能够优先分配匹配次数少的老师
7. 系统能够生成正确的匹配结果Excel文件
8. 系统界面友好,操作简单
9. 系统运行稳定,无明显错误