style: normalize code formatting across the codebase

- Standardize quote style (single to double quotes)
- Improve code formatting consistency
- Apply formatting to utilities, GUI components, and tools
- Update imports and docstrings for consistency

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-02-05 14:56:35 +08:00
parent c34a300f0b
commit 2ca53f6a55
27 changed files with 693 additions and 385 deletions

View File

@@ -58,7 +58,7 @@ class ConfigManager:
Returns:
配置值
"""
keys = key.split('.')
keys = key.split(".")
value = self.config
try:
@@ -78,7 +78,7 @@ class ConfigManager:
key: 配置键
value: 配置值
"""
keys = key.split('.')
keys = key.split(".")
obj = self.config
# 导航到父对象

View File

@@ -78,12 +78,12 @@ class DataExtractionTab(ttk.Frame):
label_text="ProductionID 文件:",
file_type="file",
file_types=[("文本文件", "*.txt"), ("所有文件", "*.*")],
initial_dir="D:/python/playwrite/"
initial_dir="D:/python/playwrite/",
)
self.input_file_selector.pack(fill=tk.X)
# 设置默认文件
default_input = self.config.get('paths.production_id_file', 'ProductionID.txt')
default_input = self.config.get("paths.production_id_file", "ProductionID.txt")
if os.path.exists(default_input):
self.input_file_selector.set(default_input)
@@ -96,14 +96,14 @@ class DataExtractionTab(ttk.Frame):
label_text="保存为:",
file_type="file",
file_types=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
initial_dir=self.config.get('paths.data_dir', 'data/')
initial_dir=self.config.get("paths.data_dir", "data/"),
)
self.output_file_selector.pack(fill=tk.X)
# 设置默认输出文件
default_output = os.path.join(
self.config.get('paths.data_dir', 'data/'),
self.config.get('paths.default_output', '离散备料计划维护_合并.xlsx')
self.config.get("paths.data_dir", "data/"),
self.config.get("paths.default_output", "离散备料计划维护_合并.xlsx"),
)
self.output_file_selector.set(default_output)
@@ -111,30 +111,42 @@ class DataExtractionTab(ttk.Frame):
options_group = ttk.LabelFrame(parent, text="提取选项", padding=10)
options_group.pack(fill=tk.X, pady=5)
self.verbose_var = tk.BooleanVar(value=self.config.get('extraction.verbose', True))
ttk.Checkbutton(options_group, text="详细日志", variable=self.verbose_var).grid(row=0, column=0, sticky="w", padx=5)
self.verbose_var = tk.BooleanVar(
value=self.config.get("extraction.verbose", True)
)
ttk.Checkbutton(options_group, text="详细日志", variable=self.verbose_var).grid(
row=0, column=0, sticky="w", padx=5
)
self.headless_var = tk.BooleanVar(value=self.config.get('erp.headless', True))
ttk.Checkbutton(options_group, text="无头模式 (不显示浏览器)", variable=self.headless_var).grid(row=0, column=1, sticky="w", padx=5)
self.headless_var = tk.BooleanVar(value=self.config.get("erp.headless", True))
ttk.Checkbutton(
options_group, text="无头模式 (不显示浏览器)", variable=self.headless_var
).grid(row=0, column=1, sticky="w", padx=5)
# 进度显示
progress_group = ttk.LabelFrame(parent, text="进度", padding=10)
progress_group.pack(fill=tk.X, pady=5)
self.progress_bar = ttk.Progressbar(progress_group, mode='determinate')
self.progress_bar = ttk.Progressbar(progress_group, mode="determinate")
self.progress_bar.pack(fill=tk.X, pady=5)
self.status_label = ttk.Label(progress_group, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
self.status_label = ttk.Label(
progress_group, text="就绪", relief=tk.SUNKEN, anchor=tk.W
)
self.status_label.pack(fill=tk.X)
# 控制按钮
button_frame = ttk.Frame(parent)
button_frame.pack(fill=tk.X, pady=10)
self.start_button = ttk.Button(button_frame, text="开始提取", command=self.start_extraction)
self.start_button = ttk.Button(
button_frame, text="开始提取", command=self.start_extraction
)
self.start_button.pack(side=tk.LEFT, padx=5)
self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_extraction, state=tk.DISABLED)
self.stop_button = ttk.Button(
button_frame, text="停止", command=self.stop_extraction, state=tk.DISABLED
)
self.stop_button.pack(side=tk.LEFT, padx=5)
def _create_log_panel(self, parent):
@@ -169,16 +181,14 @@ class DataExtractionTab(ttk.Frame):
self.extracting = True
self.start_button.config(state=tk.DISABLED)
self.stop_button.config(state=tk.NORMAL)
self.progress_bar['value'] = 0
self.progress_bar["value"] = 0
self.status_label.config(text="正在登录...")
self.log_text.clear()
self.log_text.info("开始数据提取...")
# 在后台线程中执行提取
self.extraction_thread = threading.Thread(
target=self._extraction_worker,
args=(input_file, output_file),
daemon=True
target=self._extraction_worker, args=(input_file, output_file), daemon=True
)
self.extraction_thread.start()
@@ -197,20 +207,24 @@ class DataExtractionTab(ttk.Frame):
# 创建提取器实例
self.extractor = DiscreteMaterialPlanExtractor(
username=self.config.get('erp.username'),
password=self.config.get('erp.password'),
username=self.config.get("erp.username"),
password=self.config.get("erp.password"),
headless=self.headless_var.get(),
verbose=self.verbose_var.get(),
batch_size=self.config.get('extraction.batch_size', 100)
batch_size=self.config.get("extraction.batch_size", 100),
)
# 创建实时输出流,每次写入立即更新 GUI
realtime_output = RealtimeOutput(lambda line: self._update_log(line, "INFO"))
realtime_output = RealtimeOutput(
lambda line: self._update_log(line, "INFO")
)
# 创建进度回调函数
def progress_callback(progress_info: ProgressInfo):
# 计算总体进度百分比
overall_percent = self.progress_calculator.calculate_overall_percent(progress_info)
overall_percent = self.progress_calculator.calculate_overall_percent(
progress_info
)
self._update_progress(overall_percent, progress_info.message)
# 重定向 stdout 并执行提取(带进度回调)
@@ -218,7 +232,7 @@ class DataExtractionTab(ttk.Frame):
result = self.extractor.extract(
production_id_file=input_file,
output_file=output_file,
progress_callback=progress_callback
progress_callback=progress_callback,
)
if result and self.extracting:
@@ -249,7 +263,7 @@ class DataExtractionTab(ttk.Frame):
try:
progress_data = self.progress_queue.get_nowait()
value, message = progress_data
self.progress_bar['value'] = value
self.progress_bar["value"] = value
self.status_label.config(text=message)
except queue.Empty:
break
@@ -266,6 +280,7 @@ class DataExtractionTab(ttk.Frame):
def _update_log(self, message: str, level: str = "INFO"):
"""线程安全的日志更新"""
def update():
if self.extracting or level in ["ERROR", "WARNING", "SUCCESS"]:
if level == "INFO":

View File

@@ -67,7 +67,7 @@ class DataQueryTab(ttk.Frame):
info_label = ttk.Label(
parent,
text="输入总排号列表(每行一个),查询对应的生产订单号信息",
foreground="#666666"
foreground="#666666",
)
info_label.pack(anchor=tk.W, pady=(0, 5))
@@ -82,7 +82,9 @@ class DataQueryTab(ttk.Frame):
self.input_text = tk.Text(text_frame, height=10, wrap=tk.WORD)
self.input_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
text_scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self.input_text.yview)
text_scrollbar = ttk.Scrollbar(
text_frame, orient=tk.VERTICAL, command=self.input_text.yview
)
text_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.input_text.configure(yscrollcommand=text_scrollbar.set)
@@ -102,20 +104,31 @@ class DataQueryTab(ttk.Frame):
# 快捷按钮
ttk.Separator(right_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
ttk.Button(right_frame, text="加载 ProductionID.txt", command=self._load_production_id).pack(fill=tk.X, pady=2)
ttk.Button(right_frame, text="清空输入", command=self._clear_input).pack(fill=tk.X, pady=2)
ttk.Button(
right_frame, text="加载 ProductionID.txt", command=self._load_production_id
).pack(fill=tk.X, pady=2)
ttk.Button(right_frame, text="清空输入", command=self._clear_input).pack(
fill=tk.X, pady=2
)
# 查询按钮
button_frame = ttk.Frame(parent)
button_frame.pack(fill=tk.X, pady=(10, 0))
self.query_button = ttk.Button(button_frame, text="执行查询", command=self.execute_query)
self.query_button = ttk.Button(
button_frame, text="执行查询", command=self.execute_query
)
self.query_button.pack(side=tk.LEFT, padx=5)
self.export_button = ttk.Button(button_frame, text="导出结果", command=self.export_results, state=tk.DISABLED)
self.export_button = ttk.Button(
button_frame,
text="导出结果",
command=self.export_results,
state=tk.DISABLED,
)
self.export_button.pack(side=tk.LEFT, padx=5)
self.progress = ttk.Progressbar(parent, mode='indeterminate')
self.progress = ttk.Progressbar(parent, mode="indeterminate")
self.progress.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
def _create_result_table(self, parent):
@@ -135,9 +148,13 @@ class DataQueryTab(ttk.Frame):
# 添加滚动条
scrollbar_y = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.tree.yview)
scrollbar_x = ttk.Scrollbar(parent, orient=tk.HORIZONTAL, command=self.tree.xview)
scrollbar_x = ttk.Scrollbar(
parent, orient=tk.HORIZONTAL, command=self.tree.xview
)
self.tree.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
self.tree.configure(
yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set
)
# 布局
self.tree.grid(row=0, column=0, sticky="nsew")
@@ -154,7 +171,7 @@ class DataQueryTab(ttk.Frame):
def _load_production_id(self):
"""加载 ProductionID.txt 文件"""
default_path = self.config.get('paths.production_id_file', 'ProductionID.txt')
default_path = self.config.get("paths.production_id_file", "ProductionID.txt")
# 检查默认路径
if os.path.exists(default_path):
@@ -162,16 +179,17 @@ class DataQueryTab(ttk.Frame):
else:
# 打开文件选择对话框
from tkinter import filedialog
file_path = filedialog.askopenfilename(
title="选择 ProductionID 文件",
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
)
if not file_path:
return
try:
with open(file_path, 'r', encoding='utf-8') as f:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
self.input_text.delete("1.0", tk.END)
@@ -196,7 +214,9 @@ class DataQueryTab(ttk.Frame):
return
# 解析总排号
production_ids = [line.strip() for line in input_text.split('\n') if line.strip()]
production_ids = [
line.strip() for line in input_text.split("\n") if line.strip()
]
if not production_ids:
messagebox.showwarning("警告", "没有有效的总排号")
@@ -215,9 +235,7 @@ class DataQueryTab(ttk.Frame):
# 在后台线程中执行查询
query_thread = threading.Thread(
target=self._query_worker,
args=(production_ids,),
daemon=True
target=self._query_worker, args=(production_ids,), daemon=True
)
query_thread.start()
@@ -253,6 +271,7 @@ class DataQueryTab(ttk.Frame):
def _display_results(self, results: list):
"""在主线程中显示结果"""
def update():
for 总排号, 生产订单号 in results:
self.tree.insert("", tk.END, values=(总排号, 生产订单号, ""))
@@ -265,6 +284,7 @@ class DataQueryTab(ttk.Frame):
def _update_log(self, message: str, level: str = "INFO"):
"""线程安全的日志更新"""
def update():
if level == "INFO":
self.log_text.info(message)
@@ -287,7 +307,7 @@ class DataQueryTab(ttk.Frame):
title="导出查询结果",
defaultextension=".xlsx",
filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
initialfile="生产订单号查询结果.xlsx"
initialfile="生产订单号查询结果.xlsx",
)
if not output_file:

View File

@@ -92,13 +92,17 @@ class MainWindow:
# 状态文本
self.status_text = tk.StringVar()
self.status_text.set("就绪")
status_label = ttk.Label(self.status_bar, textvariable=self.status_text, anchor=tk.W)
status_label = ttk.Label(
self.status_bar, textvariable=self.status_text, anchor=tk.W
)
status_label.pack(side=tk.LEFT, padx=5)
# 配置状态指示
self.config_status = tk.StringVar()
self.config_status.set("配置已加载")
config_label = ttk.Label(self.status_bar, textvariable=self.config_status, anchor=tk.E)
config_label = ttk.Label(
self.status_bar, textvariable=self.config_status, anchor=tk.E
)
config_label.pack(side=tk.RIGHT, padx=5)
def _center_window(self):
@@ -113,6 +117,7 @@ class MainWindow:
def show_about(self):
"""显示关于对话框"""
from tkinter import messagebox
messagebox.showinfo(
"关于 ERP 自动化工具",
"ERP 自动化工具 v1.0\n\n"
@@ -121,5 +126,5 @@ class MainWindow:
"• 物料校验 - 校验物料状态并匹配待删除物料\n"
"• 数据查询 - 查询生产订单号等信息\n"
"• 设置管理 - 管理系统配置\n\n"
"基于 Playwright 和 Python 开发"
"基于 Playwright 和 Python 开发",
)

View File

@@ -76,7 +76,7 @@ class MaterialValidationTab(ttk.Frame):
text="使用现有 Excel 文件",
variable=self.source_mode,
value="existing",
command=self._on_source_mode_change
command=self._on_source_mode_change,
).grid(row=0, column=0, sticky="w", padx=5)
ttk.Radiobutton(
@@ -84,7 +84,7 @@ class MaterialValidationTab(ttk.Frame):
text="完整工作流 (提取 + 校验)",
variable=self.source_mode,
value="full",
command=self._on_source_mode_change
command=self._on_source_mode_change,
).grid(row=0, column=1, sticky="w", padx=5)
# 文件选择
@@ -100,7 +100,7 @@ class MaterialValidationTab(ttk.Frame):
label_text="现有 Excel 文件:",
file_type="file",
file_types=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
initial_dir=self.config.get('paths.data_dir', 'data/')
initial_dir=self.config.get("paths.data_dir", "data/"),
)
self.existing_excel_selector.pack(fill=tk.X)
@@ -113,7 +113,7 @@ class MaterialValidationTab(ttk.Frame):
label_text="ProductionID 文件:",
file_type="file",
file_types=[("文本文件", "*.txt"), ("所有文件", "*.*")],
initial_dir="D:/python/playwrite/"
initial_dir="D:/python/playwrite/",
)
self.production_id_selector.pack(fill=tk.X)
@@ -126,14 +126,14 @@ class MaterialValidationTab(ttk.Frame):
label_text="输出文件:",
file_type="file",
file_types=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
initial_dir=self.config.get('paths.data_dir', 'data/')
initial_dir=self.config.get("paths.data_dir", "data/"),
)
self.output_file_selector.pack(fill=tk.X)
# 设置默认输出
default_output = os.path.join(
self.config.get('paths.data_dir', 'data/'),
self.config.get('paths.validation_output', '物料状态校验结果.xlsx')
self.config.get("paths.data_dir", "data/"),
self.config.get("paths.validation_output", "物料状态校验结果.xlsx"),
)
self.output_file_selector.set(default_output)
@@ -141,10 +141,17 @@ class MaterialValidationTab(ttk.Frame):
button_frame = ttk.Frame(parent)
button_frame.pack(fill=tk.X, pady=10)
self.start_button = ttk.Button(button_frame, text="开始校验", command=self.start_validation)
self.start_button = ttk.Button(
button_frame, text="开始校验", command=self.start_validation
)
self.start_button.pack(side=tk.LEFT, padx=5)
self.export_button = ttk.Button(button_frame, text="导出结果", command=self.export_results, state=tk.DISABLED)
self.export_button = ttk.Button(
button_frame,
text="导出结果",
command=self.export_results,
state=tk.DISABLED,
)
self.export_button.pack(side=tk.LEFT, padx=5)
def _create_result_table(self, parent):
@@ -166,9 +173,13 @@ class MaterialValidationTab(ttk.Frame):
# 添加滚动条
scrollbar_y = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.tree.yview)
scrollbar_x = ttk.Scrollbar(parent, orient=tk.HORIZONTAL, command=self.tree.xview)
scrollbar_x = ttk.Scrollbar(
parent, orient=tk.HORIZONTAL, command=self.tree.xview
)
self.tree.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
self.tree.configure(
yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set
)
# 布局
self.tree.grid(row=0, column=0, sticky="nsew")
@@ -239,11 +250,13 @@ class MaterialValidationTab(ttk.Frame):
validation_thread = threading.Thread(
target=self._validation_worker,
args=(input_file, production_id_file, output_file),
daemon=True
daemon=True,
)
validation_thread.start()
def _validation_worker(self, input_file: str, production_id_file: str, output_file: str):
def _validation_worker(
self, input_file: str, production_id_file: str, output_file: str
):
"""校验工作线程"""
try:
# 导入校验器
@@ -251,10 +264,10 @@ class MaterialValidationTab(ttk.Frame):
# 创建校验器实例(需要 ERP 凭据,因为可能需要登录系统)
validator = MaterialStatusValidator(
username=self.config.get('erp.username'),
password=self.config.get('erp.password'),
headless=self.config.get('erp.headless', True),
verbose=True
username=self.config.get("erp.username"),
password=self.config.get("erp.password"),
headless=self.config.get("erp.headless", True),
verbose=True,
)
# 捕获 stdout 输出
@@ -264,20 +277,19 @@ class MaterialValidationTab(ttk.Frame):
with redirect_stdout(captured_output):
if self.source_mode.get() == "existing":
result = validator.validate_from_existing_excel(
excel_file=input_file,
output_file=output_file
excel_file=input_file, output_file=output_file
)
else:
result = validator.validate(
production_id_file=production_id_file,
merged_excel_file=None, # 将在内部生成
output_file=output_file
output_file=output_file,
)
# 获取捕获的输出并显示到日志
output_text = captured_output.getvalue()
if output_text:
for line in output_text.split('\n'):
for line in output_text.split("\n"):
if line.strip():
self._update_log(line, "INFO")
@@ -307,12 +319,16 @@ class MaterialValidationTab(ttk.Frame):
# 在主线程中更新表格
def update_table():
for _, row in df.iterrows():
self.tree.insert("", tk.END, values=(
row.get('材料名称', ''),
row.get('匹配的MaterialName', ''),
row.get('负责人', ''),
row.get('匹配状态', '')
))
self.tree.insert(
"",
tk.END,
values=(
row.get("材料名称", ""),
row.get("匹配的MaterialName", ""),
row.get("负责人", ""),
row.get("匹配状态", ""),
),
)
if len(df) > 0:
self.export_button.config(state=tk.NORMAL)
@@ -325,6 +341,7 @@ class MaterialValidationTab(ttk.Frame):
def _update_log(self, message: str, level: str = "INFO"):
"""线程安全的日志更新"""
def update():
if level == "INFO":
self.log_text.info(message)
@@ -345,7 +362,7 @@ class MaterialValidationTab(ttk.Frame):
output_file = filedialog.asksaveasfilename(
title="保存结果",
defaultextension=".xlsx",
filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")]
filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
)
if not output_file:
@@ -355,7 +372,7 @@ class MaterialValidationTab(ttk.Frame):
# 收集表格数据
data = []
for item in self.tree.get_children():
values = self.tree.item(item)['values']
values = self.tree.item(item)["values"]
data.append(values)
if not data:
@@ -363,7 +380,9 @@ class MaterialValidationTab(ttk.Frame):
return
# 创建 DataFrame 并保存
df = pd.DataFrame(data, columns=["材料名称", "匹配的MaterialName", "负责人", "匹配状态"])
df = pd.DataFrame(
data, columns=["材料名称", "匹配的MaterialName", "负责人", "匹配状态"]
)
df.to_excel(output_file, index=False)
messagebox.showinfo("成功", f"结果已导出到:{output_file}")

View File

@@ -17,7 +17,10 @@ class ProgressInfo:
用于在后台任务和 GUI 之间传递进度信息。
"""
stage: str # 阶段标识: 'login', 'query', 'download', 'logout', 'convert', 'complete'
stage: (
str # 阶段标识: 'login', 'query', 'download', 'logout', 'convert', 'complete'
)
current: int # 当前进度值
total: int # 总量
message: str # 显示给用户的消息
@@ -43,12 +46,12 @@ class ProgressCalculator:
# 各阶段在总进度中的占比
STAGE_WEIGHTS = {
'login': 5, # 登录: 0-5%
'query': 5, # 查询: 5-10%
'download': 65, # 下载: 10-75%
'logout': 5, # 注销: 75-80%
'convert': 15, # 转换: 80-95%
'complete': 5, # 完成: 95-100%
"login": 5, # 登录: 0-5%
"query": 5, # 查询: 5-10%
"download": 65, # 下载: 10-75%
"logout": 5, # 注销: 75-80%
"convert": 15, # 转换: 80-95%
"complete": 5, # 完成: 95-100%
}
def __init__(self):
@@ -76,7 +79,7 @@ class ProgressCalculator:
"""
stage = progress.stage
if stage == 'complete':
if stage == "complete":
return 100
if stage not in self._stage_offsets:

View File

@@ -36,8 +36,7 @@ class SettingsTab(ttk.Frame):
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
"<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
@@ -62,10 +61,18 @@ class SettingsTab(ttk.Frame):
button_frame = ttk.Frame(scrollable_frame)
button_frame.grid(row=5, column=0, columnspan=2, pady=20, sticky="ew")
ttk.Button(button_frame, text="测试 ERP 连接", command=self.test_erp_connection).pack(side="left", padx=5)
ttk.Button(button_frame, text="测试数据库连接", command=self.test_db_connection).pack(side="left", padx=5)
ttk.Button(button_frame, text="保存设置", command=self.save_settings).pack(side="left", padx=5)
ttk.Button(button_frame, text="恢复默认", command=self.reset_defaults).pack(side="left", padx=5)
ttk.Button(
button_frame, text="测试 ERP 连接", command=self.test_erp_connection
).pack(side="left", padx=5)
ttk.Button(
button_frame, text="测试数据库连接", command=self.test_db_connection
).pack(side="left", padx=5)
ttk.Button(button_frame, text="保存设置", command=self.save_settings).pack(
side="left", padx=5
)
ttk.Button(button_frame, text="恢复默认", command=self.reset_defaults).pack(
side="left", padx=5
)
# 布局
canvas.grid(row=0, column=0, sticky="nsew")
@@ -82,12 +89,16 @@ class SettingsTab(ttk.Frame):
# URL
ttk.Label(group, text="ERP URL:").grid(row=0, column=0, sticky="w", pady=5)
self.erp_url_var = tk.StringVar()
ttk.Entry(group, textvariable=self.erp_url_var, width=50).grid(row=0, column=1, pady=5, sticky="ew")
ttk.Entry(group, textvariable=self.erp_url_var, width=50).grid(
row=0, column=1, pady=5, sticky="ew"
)
# 用户名
ttk.Label(group, text="用户名:").grid(row=1, column=0, sticky="w", pady=5)
self.erp_username_var = tk.StringVar()
ttk.Entry(group, textvariable=self.erp_username_var, width=50).grid(row=1, column=1, pady=5, sticky="ew")
ttk.Entry(group, textvariable=self.erp_username_var, width=50).grid(
row=1, column=1, pady=5, sticky="ew"
)
# 密码
ttk.Label(group, text="密码:").grid(row=2, column=0, sticky="w", pady=5)
@@ -105,17 +116,23 @@ class SettingsTab(ttk.Frame):
# 服务器
ttk.Label(group, text="服务器:").grid(row=0, column=0, sticky="w", pady=5)
self.db_server_var = tk.StringVar()
ttk.Entry(group, textvariable=self.db_server_var, width=50).grid(row=0, column=1, pady=5, sticky="ew")
ttk.Entry(group, textvariable=self.db_server_var, width=50).grid(
row=0, column=1, pady=5, sticky="ew"
)
# 数据库名
ttk.Label(group, text="数据库:").grid(row=1, column=0, sticky="w", pady=5)
self.db_name_var = tk.StringVar()
ttk.Entry(group, textvariable=self.db_name_var, width=50).grid(row=1, column=1, pady=5, sticky="ew")
ttk.Entry(group, textvariable=self.db_name_var, width=50).grid(
row=1, column=1, pady=5, sticky="ew"
)
# 用户名
ttk.Label(group, text="用户名:").grid(row=2, column=0, sticky="w", pady=5)
self.db_username_var = tk.StringVar()
ttk.Entry(group, textvariable=self.db_username_var, width=50).grid(row=2, column=1, pady=5, sticky="ew")
ttk.Entry(group, textvariable=self.db_username_var, width=50).grid(
row=2, column=1, pady=5, sticky="ew"
)
# 密码
ttk.Label(group, text="密码:").grid(row=3, column=0, sticky="w", pady=5)
@@ -131,13 +148,19 @@ class SettingsTab(ttk.Frame):
group.grid(row=2, column=0, pady=10, padx=10, sticky="ew")
self.browser_headless_var = tk.BooleanVar()
ttk.Checkbutton(group, text="无头模式 (不显示浏览器)", variable=self.browser_headless_var).grid(row=0, column=0, sticky="w", pady=5)
ttk.Checkbutton(
group, text="无头模式 (不显示浏览器)", variable=self.browser_headless_var
).grid(row=0, column=0, sticky="w", pady=5)
self.browser_ignore_https_var = tk.BooleanVar()
ttk.Checkbutton(group, text="忽略 HTTPS 错误", variable=self.browser_ignore_https_var).grid(row=1, column=0, sticky="w", pady=5)
ttk.Checkbutton(
group, text="忽略 HTTPS 错误", variable=self.browser_ignore_https_var
).grid(row=1, column=0, sticky="w", pady=5)
self.browser_auto_close_var = tk.BooleanVar()
ttk.Checkbutton(group, text="操作完成后自动关闭浏览器", variable=self.browser_auto_close_var).grid(row=2, column=0, sticky="w", pady=5)
ttk.Checkbutton(
group, text="操作完成后自动关闭浏览器", variable=self.browser_auto_close_var
).grid(row=2, column=0, sticky="w", pady=5)
def _create_paths_group(self, parent):
"""创建路径配置组"""
@@ -152,14 +175,16 @@ class SettingsTab(ttk.Frame):
group,
label_text="",
file_type="directory",
initial_dir="D:/python/playwrite/data/"
initial_dir="D:/python/playwrite/data/",
)
self.data_dir_selector.grid(row=1, column=0, columnspan=2, sticky="ew", pady=5)
# 默认输出文件
ttk.Label(group, text="默认输出文件:").grid(row=2, column=0, sticky="w", pady=5)
self.default_output_var = tk.StringVar()
ttk.Entry(group, textvariable=self.default_output_var, width=40).grid(row=3, column=0, columnspan=2, sticky="ew", pady=5)
ttk.Entry(group, textvariable=self.default_output_var, width=40).grid(
row=3, column=0, columnspan=2, sticky="ew", pady=5
)
group.columnconfigure(0, weight=1)
@@ -171,75 +196,85 @@ class SettingsTab(ttk.Frame):
# 批次大小
ttk.Label(group, text="批次大小:").grid(row=0, column=0, sticky="w", pady=5)
self.batch_size_var = tk.IntVar(value=100)
ttk.Spinbox(group, from_=10, to=500, textvariable=self.batch_size_var, width=10).grid(row=0, column=1, sticky="w", pady=5)
ttk.Spinbox(
group, from_=10, to=500, textvariable=self.batch_size_var, width=10
).grid(row=0, column=1, sticky="w", pady=5)
# 详细日志
self.verbose_var = tk.BooleanVar()
ttk.Checkbutton(group, text="启用详细日志", variable=self.verbose_var).grid(row=1, column=0, columnspan=2, sticky="w", pady=5)
ttk.Checkbutton(group, text="启用详细日志", variable=self.verbose_var).grid(
row=1, column=0, columnspan=2, sticky="w", pady=5
)
# 自动转换
self.auto_convert_var = tk.BooleanVar()
ttk.Checkbutton(group, text="自动转换 Excel 格式", variable=self.auto_convert_var).grid(row=2, column=0, columnspan=2, sticky="w", pady=5)
ttk.Checkbutton(
group, text="自动转换 Excel 格式", variable=self.auto_convert_var
).grid(row=2, column=0, columnspan=2, sticky="w", pady=5)
# 合并批次
self.merge_batches_var = tk.BooleanVar()
ttk.Checkbutton(group, text="自动合并批次数据", variable=self.merge_batches_var).grid(row=3, column=0, columnspan=2, sticky="w", pady=5)
ttk.Checkbutton(
group, text="自动合并批次数据", variable=self.merge_batches_var
).grid(row=3, column=0, columnspan=2, sticky="w", pady=5)
def load_settings(self):
"""从配置加载设置到界面"""
# ERP 设置
self.erp_url_var.set(self.config.get('erp.url', ''))
self.erp_username_var.set(self.config.get('erp.username', ''))
self.erp_password_var.set(self.config.get('erp.password', ''))
self.erp_url_var.set(self.config.get("erp.url", ""))
self.erp_username_var.set(self.config.get("erp.username", ""))
self.erp_password_var.set(self.config.get("erp.password", ""))
# 数据库设置
self.db_server_var.set(self.config.get('database.server', ''))
self.db_name_var.set(self.config.get('database.database', ''))
self.db_username_var.set(self.config.get('database.username', ''))
self.db_password_var.set(self.config.get('database.password', ''))
self.db_server_var.set(self.config.get("database.server", ""))
self.db_name_var.set(self.config.get("database.database", ""))
self.db_username_var.set(self.config.get("database.username", ""))
self.db_password_var.set(self.config.get("database.password", ""))
# 浏览器设置(已合并到 ERP 配置中)
self.browser_headless_var.set(self.config.get('erp.headless', True))
self.browser_ignore_https_var.set(self.config.get('erp.ignore_https_errors', True))
self.browser_auto_close_var.set(self.config.get('erp.auto_close_browser', True))
self.browser_headless_var.set(self.config.get("erp.headless", True))
self.browser_ignore_https_var.set(
self.config.get("erp.ignore_https_errors", True)
)
self.browser_auto_close_var.set(self.config.get("erp.auto_close_browser", True))
# 路径设置
self.data_dir_selector.set(self.config.get('paths.data_dir', ''))
self.default_output_var.set(self.config.get('paths.default_output', ''))
self.data_dir_selector.set(self.config.get("paths.data_dir", ""))
self.default_output_var.set(self.config.get("paths.default_output", ""))
# 处理设置
self.batch_size_var.set(self.config.get('extraction.batch_size', 100))
self.verbose_var.set(self.config.get('extraction.verbose', True))
self.auto_convert_var.set(self.config.get('extraction.auto_convert', True))
self.merge_batches_var.set(self.config.get('extraction.merge_batches', True))
self.batch_size_var.set(self.config.get("extraction.batch_size", 100))
self.verbose_var.set(self.config.get("extraction.verbose", True))
self.auto_convert_var.set(self.config.get("extraction.auto_convert", True))
self.merge_batches_var.set(self.config.get("extraction.merge_batches", True))
def save_settings(self):
"""保存界面设置到配置"""
# ERP 设置
self.config.set('erp.url', self.erp_url_var.get())
self.config.set('erp.username', self.erp_username_var.get())
self.config.set('erp.password', self.erp_password_var.get())
self.config.set("erp.url", self.erp_url_var.get())
self.config.set("erp.username", self.erp_username_var.get())
self.config.set("erp.password", self.erp_password_var.get())
# 数据库设置
self.config.set('database.server', self.db_server_var.get())
self.config.set('database.database', self.db_name_var.get())
self.config.set('database.username', self.db_username_var.get())
self.config.set('database.password', self.db_password_var.get())
self.config.set("database.server", self.db_server_var.get())
self.config.set("database.database", self.db_name_var.get())
self.config.set("database.username", self.db_username_var.get())
self.config.set("database.password", self.db_password_var.get())
# 浏览器设置(已合并到 ERP 配置中)
self.config.set('erp.headless', self.browser_headless_var.get())
self.config.set('erp.ignore_https_errors', self.browser_ignore_https_var.get())
self.config.set('erp.auto_close_browser', self.browser_auto_close_var.get())
self.config.set("erp.headless", self.browser_headless_var.get())
self.config.set("erp.ignore_https_errors", self.browser_ignore_https_var.get())
self.config.set("erp.auto_close_browser", self.browser_auto_close_var.get())
# 路径设置
self.config.set('paths.data_dir', self.data_dir_selector.get())
self.config.set('paths.default_output', self.default_output_var.get())
self.config.set("paths.data_dir", self.data_dir_selector.get())
self.config.set("paths.default_output", self.default_output_var.get())
# 处理设置
self.config.set('extraction.batch_size', self.batch_size_var.get())
self.config.set('extraction.verbose', self.verbose_var.get())
self.config.set('extraction.auto_convert', self.auto_convert_var.get())
self.config.set('extraction.merge_batches', self.merge_batches_var.get())
self.config.set("extraction.batch_size", self.batch_size_var.get())
self.config.set("extraction.verbose", self.verbose_var.get())
self.config.set("extraction.auto_convert", self.auto_convert_var.get())
self.config.set("extraction.merge_batches", self.merge_batches_var.get())
# 保存到文件
if self.config.save():

View File

@@ -24,7 +24,7 @@ class RealtimeOutput:
"""写入文本"""
if text:
# 将文本按行分割,逐行回调
lines = text.split('\n')
lines = text.split("\n")
for line in lines:
if line: # 忽略空行(由 split 产生)
self.callback(line)