44import os
55import json
66from typing import Dict , List , Any
7+ from concurrent .futures import ThreadPoolExecutor
78
89from loguru import logger
910from PySide6 .QtWidgets import *
2324class ImportPrizeNameWindow (QWidget ):
2425 """奖品名称导入窗口"""
2526
27+ # 定义信号,用于后台加载文件完成后通知UI线程
28+ fileLoaded = Signal (object , list ) # 参数:数据,列名列表
29+ fileLoadError = Signal (str ) # 参数:错误信息
30+
2631 def __init__ (self , parent = None ):
2732 """初始化奖品名称导入窗口"""
2833 # 调用父类初始化方法
@@ -34,6 +39,8 @@ def __init__(self, parent=None):
3439 self .columns = []
3540 self .column_mapping = {}
3641 self .preview_data = []
42+ # 线程池用于后台加载文件
43+ self .executor = ThreadPoolExecutor (max_workers = 2 )
3744
3845 # 创建UI
3946 self .__init_ui ()
@@ -46,7 +53,7 @@ def __init_ui(self):
4653 # 创建主布局
4754 self .main_layout = QVBoxLayout (self )
4855 self .main_layout .setContentsMargins (20 , 20 , 20 , 20 )
49- self .main_layout .setSpacing (15 )
56+ self .main_layout .setSpacing (5 )
5057
5158 # 创建标题
5259 self .title_label = TitleLabel (
@@ -210,6 +217,10 @@ def __create_preview_area(self):
210217 self .preview_table = TableWidget ()
211218 self .preview_table .setWordWrap (True )
212219 self .preview_table .verticalHeader ().setVisible (False )
220+ # 限制预览表格高度
221+ self .preview_table .setMaximumHeight (150 )
222+ # 设置固定行数显示
223+ self .preview_table .setRowCount (0 )
213224 preview_layout .addWidget (self .preview_table )
214225
215226 # 添加到主布局
@@ -253,6 +264,10 @@ def __connect_signals(self):
253264 # 按钮事件
254265 self .import_btn .clicked .connect (self .__import_data )
255266
267+ # 后台文件加载完成信号
268+ self .fileLoaded .connect (self .__on_file_loaded )
269+ self .fileLoadError .connect (self .__on_file_load_error )
270+
256271 def __update_ui_state (self ):
257272 """更新UI状态"""
258273 has_file = self .file_path is not None
@@ -319,73 +334,18 @@ def __select_file(self):
319334 )
320335
321336 if file_path :
322- try :
323- # 加载文件
324- self .__load_file (file_path )
325-
326- # 更新文件路径标签
327- self .file_path_label .setText (os .path .basename (file_path ))
328-
329- # 显示成功消息
330- config = NotificationConfig (
331- title = get_content_name_async (
332- "import_prize_name" , "file_loaded_notification_title"
333- ),
334- content = get_content_name_async (
335- "import_prize_name" , "file_loaded_notification_content"
336- ),
337- duration = 3000 ,
338- )
339- show_notification (NotificationType .SUCCESS , config , parent = self )
340-
341- except Exception as e :
342- # 显示错误消息
343- config = NotificationConfig (
344- title = get_content_name_async (
345- "import_prize_name" , "load_failed_notification_title"
346- ),
347- content = get_content_name_async (
348- "import_prize_name" , "load_failed_notification_content"
349- ),
350- duration = 3000 ,
351- )
352- show_notification (NotificationType .ERROR , config , parent = self )
353- logger .error (f"加载文件失败: { e } " )
354-
355- def __load_file (self , file_path : str ):
356- """加载文件"""
357- self .file_path = file_path
358-
359- # 根据文件扩展名选择加载方法
360- file_ext = os .path .splitext (file_path )[1 ].lower ()
361-
362- if file_ext in [".xlsx" , ".xls" ]:
363- # 延迟导入 pandas,避免在模块导入时加载大型 C 扩展
364- try :
365- import pandas as pd
366- except Exception as e :
367- logger .error (f"加载 Excel 需要 pandas 库,但导入失败: { e } " )
368- raise
369-
370- # 加载Excel文件
371- self .data = pd .read_excel (file_path )
372- elif file_ext == ".csv" :
373- # 延迟导入 pandas,避免在模块导入时加载大型 C 扩展
374- try :
375- import pandas as pd
376- except Exception as e :
377- logger .error (f"加载 CSV 需要 pandas 库,但导入失败: { e } " )
378- raise
337+ # 更新文件路径标签
338+ self .file_path_label .setText (os .path .basename (file_path ))
379339
380- # 加载CSV文件
381- self .data = pd .read_csv (file_path )
382- else :
383- raise ValueError (
384- get_content_name_async ("import_prize_name" , "unsupported_format" )
385- )
340+ # 使用线程池在后台加载文件
341+ self .executor .submit (self .__load_file , file_path )
386342
387- # 获取列名
388- self .columns = list (self .data .columns )
343+ def __on_file_loaded (self , data , columns ):
344+ """文件加载完成后的处理"""
345+ # 更新UI数据
346+ self .data = data
347+ self .columns = columns
348+ self .file_path = self .file_path_label .text ()
389349
390350 # 更新列映射下拉框
391351 self .__update_column_combos ()
@@ -399,6 +359,73 @@ def __load_file(self, file_path: str):
399359 # 更新UI状态
400360 self .__update_ui_state ()
401361
362+ # 显示成功消息
363+ config = NotificationConfig (
364+ title = get_content_name_async (
365+ "import_prize_name" , "file_loaded_notification_title"
366+ ),
367+ content = get_content_name_async (
368+ "import_prize_name" , "file_loaded_notification_content"
369+ ),
370+ duration = 3000 ,
371+ )
372+ show_notification (NotificationType .SUCCESS , config , parent = self )
373+
374+ def __on_file_load_error (self , error_msg ):
375+ """文件加载失败后的处理"""
376+ # 隐藏加载动画
377+ self .__hide_loading_animation ()
378+
379+ # 显示错误消息
380+ config = NotificationConfig (
381+ title = get_content_name_async (
382+ "import_prize_name" , "load_failed_notification_title"
383+ ),
384+ content = get_content_name_async (
385+ "import_prize_name" , "load_failed_notification_content"
386+ )
387+ + f": { error_msg } " ,
388+ duration = 3000 ,
389+ )
390+ show_notification (NotificationType .ERROR , config , parent = self )
391+
392+ def __load_file (self , file_path : str ):
393+ """加载文件 - 在后台线程中执行"""
394+ try :
395+ # 根据文件扩展名选择加载方法
396+ file_ext = os .path .splitext (file_path )[1 ].lower ()
397+ data = None
398+
399+ if file_ext in [".xlsx" , ".xls" ]:
400+ # 延迟导入 pandas,避免在模块导入时加载大型 C 扩展
401+ import pandas as pd
402+
403+ # 加载Excel文件,使用更高效的引擎
404+ data = pd .read_excel (
405+ file_path , engine = "openpyxl" if file_ext == ".xlsx" else "xlrd"
406+ )
407+ elif file_ext == ".csv" :
408+ # 延迟导入 pandas,避免在模块导入时加载大型 C 扩展
409+ import pandas as pd
410+
411+ # 加载CSV文件,使用更高效的参数
412+ data = pd .read_csv (file_path , engine = "c" , low_memory = False )
413+ else :
414+ raise ValueError (
415+ get_content_name_async ("import_prize_name" , "unsupported_format" )
416+ )
417+
418+ # 获取列名
419+ columns = list (data .columns )
420+
421+ # 通过信号通知UI线程文件加载完成
422+ self .fileLoaded .emit (data , columns )
423+
424+ except Exception as e :
425+ logger .error (f"加载文件失败: { e } " )
426+ # 通过信号通知UI线程文件加载失败
427+ self .fileLoadError .emit (str (e ))
428+
402429 def __update_column_combos (self ):
403430 """更新列映射下拉框"""
404431 # 清空现有选项
@@ -527,7 +554,7 @@ def __update_preview(self):
527554 )
528555
529556 # 限制预览行数
530- max_rows = min (10 , len (self .data ))
557+ max_rows = min (3 , len (self .data ))
531558 preview_df = self .data [preview_columns ].head (max_rows ).reset_index (drop = True )
532559
533560 # 更新表格
0 commit comments