import sysimport osimport jsonfrom PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QTextEdit, QFileDialog, QMessageBox, QGroupBox, QGridLayout, QCheckBox)from PyQt6.QtCore import Qtfrom PyQt6.QtGui import QTextCursorclass Config: """配置管理类""" CONFIG_FILE = "config.json" @classmethod def load(cls): """加载配置""" default_config = { "api_url": "", "token": "", "recursive": True, "output_file": "采购装箱单提取结果.xlsx" } try: if os.path.exists(cls.CONFIG_FILE): with open(cls.CONFIG_FILE, 'r', encoding='utf-8') as f: config = json.load(f) for key in default_config: if key not in config: config[key] = default_config[key] return config except Exception as e: print(f"加载配置文件失败: {e}") return default_config @classmethod def save(cls, api_url, token, recursive, output_file): """保存配置""" try: config = { "api_url": api_url, "token": token, "recursive": recursive, "output_file": output_file } with open(cls.CONFIG_FILE, 'w', encoding='utf-8') as f: json.dump(config, f, ensure_ascii=False, indent=2) return True except Exception as e: print(f"保存配置文件失败: {e}") return Falseclass MainWindow(QMainWindow): """主窗口""" def __init__(self): super().__init__() self.config = Config.load() self.init_ui() def init_ui(self): """初始化UI""" self.setWindowTitle("采购装箱单信息提取工具(欢迎关注微信公众号:码海听潮)") self.setMinimumSize(800, 650) self.setStyleSheet(""" QMainWindow { background-color: #f5f7fa; } QGroupBox { font-weight: bold; border: 2px solid #e1e9f0; border-radius: 8px; margin-top: 10px; padding-top: 10px; background-color: white; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 10px 0 10px; color: #2c3e50; } QPushButton { background-color: #3498db; color: white; border: none; padding: 8px 16px; border-radius: 5px; font-weight: bold; min-width: 100px; } QPushButton:hover { background-color: #2980b9; } QPushButton:pressed { background-color: #1c6ea4; } QPushButton:disabled { background-color: #bdc3c7; } QLineEdit { padding: 8px; border: 2px solid #e1e9f0; border-radius: 5px; background-color: white; selection-background-color: #3498db; } QLineEdit:focus { border-color: #3498db; } QTextEdit { border: 2px solid #e1e9f0; border-radius: 5px; background-color: white; font-family: Consolas, Monaco, monospace; font-size: 12px; } QCheckBox { spacing: 8px; } QCheckBox::indicator { width: 18px; height: 18px; border: 2px solid #e1e9f0; border-radius: 3px; background-color: white; } QCheckBox::indicator:checked { background-color: #3498db; border-color: #3498db; } QLabel { color: #2c3e50; } """) central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) main_layout.setSpacing(15) main_layout.setContentsMargins(20, 20, 20, 20) config_group = QGroupBox("配置参数") config_layout = QGridLayout(config_group) config_layout.setVerticalSpacing(12) config_layout.setHorizontalSpacing(10) config_layout.addWidget(QLabel("输入目录:"), 0, 0) self.input_dir_edit = QLineEdit() self.input_dir_edit.setPlaceholderText("请选择包含图片/PDF文件的目录") config_layout.addWidget(self.input_dir_edit, 0, 1) self.browse_input_btn = QPushButton("浏览...") self.browse_input_btn.clicked.connect(self.browse_input_dir) self.browse_input_btn.setFixedWidth(80) config_layout.addWidget(self.browse_input_btn, 0, 2) config_layout.addWidget(QLabel("输出Excel:"), 1, 0) self.output_file_edit = QLineEdit() self.output_file_edit.setText(self.config.get("output_file", "采购单提取结果.xlsx")) config_layout.addWidget(self.output_file_edit, 1, 1) self.browse_output_btn = QPushButton("浏览...") self.browse_output_btn.clicked.connect(self.browse_output_file) self.browse_output_btn.setFixedWidth(80) config_layout.addWidget(self.browse_output_btn, 1, 2) config_layout.addWidget(QLabel("API地址:"), 2, 0) self.api_url_edit = QLineEdit() self.api_url_edit.setText(self.config.get("api_url", "https://38.com/layout-parsing")) config_layout.addWidget(self.api_url_edit, 2, 1, 1, 2) config_layout.addWidget(QLabel("Token:"), 3, 0) self.token_edit = QLineEdit() self.token_edit.setText(self.config.get("token", "db65aec850709aa083c4")) self.token_edit.setEchoMode(QLineEdit.EchoMode.Password) config_layout.addWidget(self.token_edit, 3, 1, 1, 2) self.recursive_checkbox = QCheckBox("递归查找子目录") self.recursive_checkbox.setChecked(self.config.get("recursive", True)) config_layout.addWidget(self.recursive_checkbox, 4, 1) main_layout.addWidget(config_group) button_layout = QHBoxLayout() button_layout.setSpacing(15) self.start_btn = QPushButton("开始处理") self.start_btn.setMinimumHeight(40) self.start_btn.clicked.connect(self.start_processing) button_layout.addWidget(self.start_btn) self.clear_btn = QPushButton("清空日志") self.clear_btn.setMinimumHeight(40) self.clear_btn.clicked.connect(self.clear_log) button_layout.addWidget(self.clear_btn) self.save_config_btn = QPushButton("保存配置") self.save_config_btn.setMinimumHeight(40) self.save_config_btn.clicked.connect(self.save_configuration) self.save_config_btn.setStyleSheet("background-color: #2ecc71;") button_layout.addWidget(self.save_config_btn) main_layout.addLayout(button_layout) log_group = QGroupBox("处理日志") log_layout = QVBoxLayout(log_group) self.log_text = QTextEdit() self.log_text.setReadOnly(True) self.log_text.setMinimumHeight(350) log_layout.addWidget(self.log_text) main_layout.addWidget(log_group) self.status_label = QLabel("就绪") self.status_label.setStyleSheet("color: #27ae60; font-weight: bold; padding: 5px;") main_layout.addWidget(self.status_label) def browse_input_dir(self): """浏览输入目录""" directory = QFileDialog.getExistingDirectory( self, "选择输入目录", "", QFileDialog.Option.ShowDirsOnly ) if directory: self.input_dir_edit.setText(directory.replace('/', '\\')) def browse_output_file(self): """浏览输出文件""" file_path, _ = QFileDialog.getSaveFileName( self, "保存Excel文件", self.output_file_edit.text() or "采购单提取结果.xlsx", "Excel文件 (*.xlsx)" ) if file_path: self.output_file_edit.setText(file_path) def save_configuration(self): """保存配置到文件""" api_url = self.api_url_edit.text().strip() token = self.token_edit.text().strip() recursive = self.recursive_checkbox.isChecked() output_file = self.output_file_edit.text().strip() if Config.save(api_url, token, recursive, output_file): self.append_log("✓ 配置已保存") QMessageBox.information(self, "保存成功", "配置已成功保存!") else: QMessageBox.warning(self, "保存失败", "配置保存失败!") def start_processing(self): """开始处理""" input_dir = self.input_dir_edit.text().strip() if not input_dir: QMessageBox.warning(self, "警告", "请选择输入目录!") return if not os.path.exists(input_dir): QMessageBox.warning(self, "警告", "输入目录不存在!") return output_file = self.output_file_edit.text().strip() if not output_file: output_file = "采购单提取结果.xlsx" self.output_file_edit.setText(output_file) api_url = self.api_url_edit.text().strip() if not api_url: QMessageBox.warning(self, "警告", "请输入API地址!") return token = self.token_edit.text().strip() if not token: QMessageBox.warning(self, "警告", "请输入Token!") return self.save_configuration() self.status_label.setText("正在处理中...") self.status_label.setStyleSheet("color: #e67e22; font-weight: bold; padding: 5px;") self.append_log("开始批量处理...") self.append_log("=" * 50) QMessageBox.information( self, "提示", "处理功能已启动,请查看日志输出。\n\n(注意:实际处理功能需要集成API调用等业务逻辑)" ) def append_log(self, message): """追加日志""" self.log_text.append(message) cursor = self.log_text.textCursor() cursor.movePosition(QTextCursor.MoveOperation.End) self.log_text.setTextCursor(cursor) def clear_log(self): """清空日志""" self.log_text.clear()def main(): """主函数""" app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())if __name__ == "__main__": main()