Skip to content

Commit d0fcc49

Browse files
committed
完善CSES功能
1 parent 6dfa40e commit d0fcc49

10 files changed

Lines changed: 440 additions & 249 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,4 @@ cython_debug/
192192
/data/list
193193
/data/audio
194194
/data/TEMP
195+
/data/CSES

app/Language/modules/more_settings.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
},
3636
"import_from_file": {"name": "从文件导入"},
3737
"importing": {"name": "导入中..."},
38-
"view_template": {"name": "查看模板"},
38+
"view_current_config": {"name": "查看当前配置"},
3939
"no_schedule_imported": {"name": "未导入课程表"},
40-
"schedule_imported": {"name": "已导入 {} 个非上课时间段"},
40+
"schedule_imported": {"name": "已导入 {} 个上课时间段"},
4141
"copy_to_clipboard": {"name": "复制到剪贴板"},
4242
"save_as_file": {"name": "保存为文件"},
4343
"close": {"name": "关闭"},
@@ -60,6 +60,22 @@
6060
"cses_content_format_error": {"name": "CSES内容格式错误"},
6161
"no_valid_time_periods": {"name": "未能从课程表中提取有效的时间段信息"},
6262
"save_settings_failed": {"name": "保存设置失败"},
63+
"no_cses_folder": {"name": "未找到CSES文件夹"},
64+
"no_schedule_file": {"name": "未导入课程表文件"},
65+
"unknown": {"name": "未知"},
66+
"unknown_course": {"name": "未知课程"},
67+
"parse_failed": {"name": "解析失败"},
68+
"load_config_failed": {"name": "加载配置失败: {}"},
69+
"table_headers": {"name": ["星期", "课程名称", "开始时间", "结束时间", "老师"]},
70+
"day_map": {
71+
"1": "周一",
72+
"2": "周二",
73+
"3": "周三",
74+
"4": "周四",
75+
"5": "周五",
76+
"6": "周六",
77+
"7": "周日",
78+
},
6379
},
6480
"EN_US": {
6581
"title": {
@@ -84,7 +100,7 @@
84100
},
85101
"import_from_file": {"name": "Import from File"},
86102
"importing": {"name": "Importing..."},
87-
"view_template": {"name": "View Template"},
103+
"view_current_config": {"name": "View Current Config"},
88104
"no_schedule_imported": {"name": "No schedule imported"},
89105
"schedule_imported": {"name": "Imported {} non-class time periods"},
90106
"copy_to_clipboard": {"name": "Copy to Clipboard"},
@@ -113,6 +129,24 @@
113129
"name": "Failed to extract valid time periods from the schedule"
114130
},
115131
"save_settings_failed": {"name": "Failed to save settings"},
132+
"no_cses_folder": {"name": "CSES folder not found"},
133+
"no_schedule_file": {"name": "No schedule file imported"},
134+
"unknown": {"name": "Unknown"},
135+
"unknown_course": {"name": "Unknown course"},
136+
"parse_failed": {"name": "Parse failed"},
137+
"load_config_failed": {"name": "Failed to load config: {}"},
138+
"table_headers": {
139+
"name": ["Day", "Course Name", "Start Time", "End Time", "Teacher"]
140+
},
141+
"day_map": {
142+
"1": "Monday",
143+
"2": "Tuesday",
144+
"3": "Wednesday",
145+
"4": "Thursday",
146+
"5": "Friday",
147+
"6": "Saturday",
148+
"7": "Sunday",
149+
},
116150
},
117151
}
118152

app/Language/obtain_language.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,17 @@ def get_content_name(first_level_key: str, second_level_key: str):
221221
second_level_key: 第二层的键
222222
223223
Returns:
224-
内容文本项的名称,如果不存在则返回None
224+
内容文本项的名称,如果不存在则返回该内容本身或None
225225
"""
226226
if first_level_key in Language:
227227
if second_level_key in Language[first_level_key]:
228228
# logger.debug(f"获取内容文本项: {first_level_key}.{second_level_key}")
229-
return Language[first_level_key][second_level_key]["name"]
229+
content = Language[first_level_key][second_level_key]
230+
# 如果是字典类型,尝试获取name属性
231+
if isinstance(content, dict):
232+
return content.get("name") or content
233+
# 否则直接返回内容
234+
return content
230235
return None
231236

232237

app/common/extraction/cses_parser.py

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,21 @@ def _validate_schedule(self) -> bool:
5757
return False
5858

5959
# 基本结构验证
60-
if "schedule" not in self.schedule_data:
60+
schedule = self.schedule_data.get("schedule")
61+
if not schedule:
6162
logger.error("缺少'schedule'字段")
6263
return False
6364

64-
schedule = self.schedule_data["schedule"]
6565
if not isinstance(schedule, dict):
6666
logger.error("'schedule'字段必须是字典类型")
6767
return False
6868

6969
# 验证时间段配置
70-
if "timeslots" not in schedule:
70+
timeslots = schedule.get("timeslots")
71+
if timeslots is None:
7172
logger.error("缺少'timeslots'字段")
7273
return False
7374

74-
timeslots = schedule["timeslots"]
7575
if not isinstance(timeslots, list):
7676
logger.error("'timeslots'字段必须是列表类型")
7777
return False
@@ -93,6 +93,11 @@ def _validate_timeslot(self, timeslot: dict, index: int) -> bool:
9393
Returns:
9494
bool: 有效返回True,否则返回False
9595
"""
96+
# 检查timeslot是否为字典类型
97+
if not isinstance(timeslot, dict):
98+
logger.error(f"时间段{index}必须是字典类型")
99+
return False
100+
96101
required_fields = ["name", "start_time", "end_time"]
97102
for field in required_fields:
98103
if field not in timeslot:
@@ -150,17 +155,26 @@ def get_non_class_times(self) -> Dict[str, str]:
150155
return {}
151156

152157
non_class_times = {}
153-
schedule = self.schedule_data["schedule"]
154-
timeslots = schedule["timeslots"]
158+
schedule = self.schedule_data.get("schedule", {})
159+
timeslots = schedule.get("timeslots", [])
155160

156-
# 按开始时间排序
157-
sorted_timeslots = sorted(timeslots, key=lambda x: x["start_time"])
161+
# 过滤并排序有效的时间段
162+
valid_timeslots = [
163+
slot
164+
for slot in timeslots
165+
if isinstance(slot, dict)
166+
and slot.get("start_time")
167+
and slot.get("end_time")
168+
]
169+
sorted_timeslots = sorted(
170+
valid_timeslots, key=lambda x: x.get("start_time", "")
171+
)
158172

159173
# 构建上课时间段列表
160174
class_periods = []
161175
for timeslot in sorted_timeslots:
162-
start_time = self._format_time_for_secrandom(timeslot["start_time"])
163-
end_time = self._format_time_for_secrandom(timeslot["end_time"])
176+
start_time = self._format_time_for_secrandom(timeslot.get("start_time", ""))
177+
end_time = self._format_time_for_secrandom(timeslot.get("end_time", ""))
164178
class_periods.append((start_time, end_time))
165179

166180
# 生成非上课时间段
@@ -209,20 +223,21 @@ def get_class_info(self) -> List[Dict]:
209223
if not self.schedule_data:
210224
return []
211225

212-
schedule = self.schedule_data["schedule"]
226+
schedule = self.schedule_data.get("schedule", {})
213227
timeslots = schedule.get("timeslots", [])
214228

215229
class_info = []
216230
for timeslot in timeslots:
217-
info = {
218-
"name": timeslot.get("name", ""),
219-
"start_time": timeslot.get("start_time", ""),
220-
"end_time": timeslot.get("end_time", ""),
221-
"teacher": timeslot.get("teacher", ""),
222-
"location": timeslot.get("location", ""),
223-
"day_of_week": timeslot.get("day_of_week", ""),
224-
}
225-
class_info.append(info)
231+
if isinstance(timeslot, dict):
232+
info = {
233+
"name": timeslot.get("name", ""),
234+
"start_time": timeslot.get("start_time", ""),
235+
"end_time": timeslot.get("end_time", ""),
236+
"teacher": timeslot.get("teacher", ""),
237+
"location": timeslot.get("location", ""),
238+
"day_of_week": timeslot.get("day_of_week", ""),
239+
}
240+
class_info.append(info)
226241

227242
return class_info
228243

@@ -235,15 +250,26 @@ def get_summary(self) -> str:
235250
if not self.schedule_data:
236251
return "未加载课程表"
237252

238-
schedule = self.schedule_data["schedule"]
253+
schedule = self.schedule_data.get("schedule", {})
239254
timeslots = schedule.get("timeslots", [])
240255

241256
if not timeslots:
242257
return "课程表为空"
243258

244259
# 获取最早和最晚时间
245-
start_times = [slot["start_time"] for slot in timeslots]
246-
end_times = [slot["end_time"] for slot in timeslots]
260+
start_times = [
261+
slot.get("start_time", "")
262+
for slot in timeslots
263+
if isinstance(slot, dict) and slot.get("start_time")
264+
]
265+
end_times = [
266+
slot.get("end_time", "")
267+
for slot in timeslots
268+
if isinstance(slot, dict) and slot.get("end_time")
269+
]
270+
271+
if not start_times or not end_times:
272+
return f"课程表包含{len(timeslots)}个时间段"
247273

248274
summary = f"课程表包含{len(timeslots)}个时间段,"
249275
summary += f"最早开始时间:{min(start_times)},"

app/common/extraction/extract.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import json
1111
from typing import Dict
1212
from loguru import logger
13+
import shutil
14+
from pathlib import Path
1315
from PySide6.QtCore import QDateTime
1416

1517
from app.tools.path_utils import *
@@ -199,6 +201,13 @@ def import_cses_schedule(file_path: str) -> tuple[bool, str]:
199201
"time_settings", "no_valid_time_periods"
200202
)
201203

204+
# 保存原始文件到data/CSES文件夹
205+
original_file_name = Path(file_path).name
206+
cses_data_path = get_data_path("CSES", original_file_name)
207+
ensure_dir(get_data_path("CSES"))
208+
shutil.copy2(file_path, cses_data_path)
209+
logger.info(f"已将CSES文件保存到: {cses_data_path}")
210+
202211
# 保存到设置文件
203212
success = _save_non_class_times_to_settings(non_class_times)
204213
if not success:

app/page_building/another_window.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from app.view.another_window.prize.prize_name_setting import PrizeNameSettingWindow
1414
from app.view.another_window.prize.prize_weight_setting import PrizeWeightSettingWindow
1515
from app.view.another_window.remaining_list import RemainingListPage
16-
from app.view.another_window.cses_template_viewer import CsesTemplateViewerWindow
16+
from app.view.another_window.current_config_viewer import CurrentConfigViewerWindow
1717
from app.Language.obtain_language import *
1818
from app.tools.variable import *
1919

@@ -49,38 +49,6 @@ def create_set_class_name_window():
4949
return
5050

5151

52-
# ==================================================
53-
# CSES模板查看窗口
54-
# ==================================================
55-
class cses_template_viewer_window_template(PageTemplate):
56-
"""CSES模板查看窗口类
57-
使用PageTemplate创建CSES模板查看页面"""
58-
59-
def __init__(self, parent=None):
60-
super().__init__(content_widget_class=CsesTemplateViewerWindow, parent=parent)
61-
62-
63-
def create_cses_template_viewer_window():
64-
"""
65-
创建CSES模板查看窗口
66-
67-
Returns:
68-
创建的窗口实例
69-
"""
70-
title = get_content_name_async("time_settings", "template_title")
71-
window = SimpleWindowTemplate(title, width=700, height=500)
72-
window.add_page_from_template(
73-
"cses_template_viewer", cses_template_viewer_window_template
74-
)
75-
window.switch_to_page("cses_template_viewer")
76-
_window_instances["cses_template_viewer"] = window
77-
window.windowClosed.connect(
78-
lambda: _window_instances.pop("cses_template_viewer", None)
79-
)
80-
window.show()
81-
return
82-
83-
8452
# ==================================================
8553
# 导入学生名单导入窗口
8654
# ==================================================
@@ -508,3 +476,35 @@ def check_page():
508476
check_page()
509477

510478
return window, get_page_callback
479+
480+
481+
# ==================================================
482+
# 当前配置查看窗口
483+
# ==================================================
484+
class current_config_viewer_window_template(PageTemplate):
485+
"""当前配置查看窗口类
486+
使用PageTemplate创建当前配置查看页面"""
487+
488+
def __init__(self, parent=None):
489+
super().__init__(content_widget_class=CurrentConfigViewerWindow, parent=parent)
490+
491+
492+
def create_current_config_viewer_window():
493+
"""
494+
创建当前配置查看窗口
495+
496+
Returns:
497+
创建的窗口实例
498+
"""
499+
title = get_content_name_async("time_settings", "cses_import_settings", "name")
500+
window = SimpleWindowTemplate(title, width=800, height=600)
501+
window.add_page_from_template(
502+
"current_config_viewer", current_config_viewer_window_template
503+
)
504+
window.switch_to_page("current_config_viewer")
505+
_window_instances["current_config_viewer"] = window
506+
window.windowClosed.connect(
507+
lambda: _window_instances.pop("current_config_viewer", None)
508+
)
509+
window.show()
510+
return

0 commit comments

Comments
 (0)