import sysfrom PyQt6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QPushButton, QLabel, QLineEdit, QTableWidget, QTableWidgetItem, QMessageBox, QFileDialog, QTabWidget, QGroupBox, QScrollArea, QStatusBar, QComboBox, QSpinBox, QTextEdit, QAbstractItemView, QDialog, QHeaderView)from PyQt6.QtCore import Qt, QTimerfrom PyQt6.QtGui import QColor# ============ 批量导入对话框 ============class BatchImportDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("批量导入快递单号") self.setFixedSize(600, 500) self.init_ui() def init_ui(self): layout = QVBoxLayout(self) # 说明标签 info_label = QLabel("批量导入快递单号") info_label.setStyleSheet("font-size: 14px; font-weight: bold;") layout.addWidget(info_label) # 格式说明 format_label = QLabel( "格式说明:每行一个快递,格式为:快递公司代码,快递单号,备注(可选)\n" "示例:\n" "jd,JDX057068322620,给老妈买的羽绒服\n" "shunfeng,SF1234567890,重要文件\n" "zhongtong,ZT1234567890" ) format_label.setStyleSheet("color: #666; font-size: 12px; padding: 10px; background: #f8f9fa; border-radius: 4px;") format_label.setWordWrap(True) layout.addWidget(format_label) # 文本框 self.text_edit = QTextEdit() self.text_edit.setPlaceholderText("请按格式输入快递信息,每行一个...") layout.addWidget(self.text_edit) # 按钮区域 btn_layout = QHBoxLayout() # 从文件导入按钮 import_file_btn = QPushButton("📂 从文件导入") import_file_btn.clicked.connect(self.import_from_file) btn_layout.addWidget(import_file_btn) # 清空按钮 clear_btn = QPushButton("🗑️ 清空") clear_btn.clicked.connect(self.text_edit.clear) btn_layout.addWidget(clear_btn) btn_layout.addStretch() # 确定和取消按钮 ok_btn = QPushButton("✅ 导入") ok_btn.clicked.connect(self.accept) ok_btn.setStyleSheet("background-color: #27ae60;") btn_layout.addWidget(ok_btn) cancel_btn = QPushButton("❌ 取消") cancel_btn.clicked.connect(self.reject) btn_layout.addWidget(cancel_btn) layout.addLayout(btn_layout) def import_from_file(self): """从文件导入""" file_path, _ = QFileDialog.getOpenFileName( self, "选择导入文件", "", "文本文件 (*.txt);;CSV文件 (*.csv);;所有文件 (*.*)" ) if file_path: try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() self.text_edit.setText(content) QMessageBox.information(self, "成功", f"已从文件导入内容") except Exception as e: QMessageBox.warning(self, "错误", f"读取文件失败:{str(e)}")# ============ 添加快递对话框 ============class AddTrackingDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("添加快递") self.setFixedSize(400, 250) self.init_ui() def init_ui(self): layout = QVBoxLayout(self) form = QFormLayout() form.setSpacing(12) # 快递公司 self.company_edit = QComboBox() self.company_edit.setEditable(True) companies = [ ("顺丰", "shunfeng"), ("中通", "zhongtong"), ("圆通", "yuantong"), ("申通", "shentong"), ("韵达", "yunda"), ("京东", "jd"), ("邮政", "youzhengguonei"), ("EMS", "ems"), ("德邦", "debang"), ("百世", "baishi"), ("天天", "tiantian"), ("极兔", "jitu"), ] for name, code in companies: self.company_edit.addItem(name, code) form.addRow(QLabel("快递公司:"), self.company_edit) # 单号 self.number_edit = QLineEdit() self.number_edit.setPlaceholderText("请输入快递单号") form.addRow(QLabel("快递单号:"), self.number_edit) # 备注 self.remark_edit = QLineEdit() self.remark_edit.setPlaceholderText("可选,如\"给老妈买的羽绒服\"") form.addRow(QLabel("备注:"), self.remark_edit) layout.addLayout(form) layout.addStretch() # 按钮 btn_layout = QHBoxLayout() btn_layout.addStretch() ok_btn = QPushButton("确定") ok_btn.clicked.connect(self.accept) cancel_btn = QPushButton("取消") cancel_btn.clicked.connect(self.reject) btn_layout.addWidget(ok_btn) btn_layout.addWidget(cancel_btn) layout.addLayout(btn_layout)# ============ 主窗口 ============class MainWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.apply_style() def init_ui(self): """初始化界面""" self.setWindowTitle("快递查询工具") self.setMinimumSize(700, 600) # 中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) main_layout.setSpacing(10) main_layout.setContentsMargins(15, 15, 15, 15) # ===== Tab 切换 ===== self.tab_widget = QTabWidget() main_layout.addWidget(self.tab_widget) # Tab 1: 快递列表 tracking_tab = QWidget() self.tab_widget.addTab(tracking_tab, "📋 快递列表") self.setup_tracking_tab(tracking_tab) # Tab 2: 设置 settings_tab = QWidget() self.tab_widget.addTab(settings_tab, "⚙️ 设置") self.setup_settings_tab(settings_tab) # ===== 底部状态栏 ===== self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) self.status_bar.showMessage("就绪") def setup_tracking_tab(self, parent): """设置快递列表标签页""" layout = QVBoxLayout(parent) # 工具栏 - 按钮居中,状态标签在右侧 toolbar = QHBoxLayout() # 创建按钮容器并居中 btn_container = QHBoxLayout() btn_container.setSpacing(8) self.add_btn = QPushButton("➕ 添加快递") self.add_btn.clicked.connect(self.add_tracking) btn_container.addWidget(self.add_btn) self.batch_btn = QPushButton("📥 批量导入") self.batch_btn.clicked.connect(self.batch_import) btn_container.addWidget(self.batch_btn) self.remove_btn = QPushButton("➖ 删除选中") self.remove_btn.clicked.connect(self.remove_tracking) btn_container.addWidget(self.remove_btn) self.clear_btn = QPushButton("🗑️ 清空全部") self.clear_btn.clicked.connect(self.clear_all) self.clear_btn.setObjectName("danger") btn_container.addWidget(self.clear_btn) self.refresh_btn = QPushButton("🔄 手动刷新") self.refresh_btn.clicked.connect(self.manual_refresh) btn_container.addWidget(self.refresh_btn) self.start_btn = QPushButton("▶ 启动追踪") self.start_btn.clicked.connect(self.toggle_tracking) btn_container.addWidget(self.start_btn) # 将按钮容器居中 toolbar.addStretch() toolbar.addLayout(btn_container) toolbar.addStretch() # 状态标签放在最右边(在第二个 stretch 之后) self.status_label = QLabel("● 已停止") self.status_label.setStyleSheet("color: #e74c3c; font-weight: bold;") toolbar.addWidget(self.status_label) layout.addLayout(toolbar) # 快递列表表格 self.table = QTableWidget() self.table.setColumnCount(5) self.table.setHorizontalHeaderLabels(["备注", "快递公司", "单号", "状态", "最新信息"]) self.table.horizontalHeader().setStretchLastSection(True) self.table.setAlternatingRowColors(True) self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) layout.addWidget(self.table) def setup_settings_tab(self, parent): """设置设置标签页""" layout = QVBoxLayout(parent) # 创建滚动区域 scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setFrameShape(QScrollArea.Shape.NoFrame) layout.addWidget(scroll) content = QWidget() scroll.setWidget(content) form = QFormLayout(content) form.setSpacing(12) form.setContentsMargins(10, 10, 10, 10) # 快递100 设置 group1 = QGroupBox("快递100 设置") group1.setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }") vbox1 = QVBoxLayout(group1) self.kuaidi100_key_edit = QLineEdit() self.kuaidi100_key_edit.setPlaceholderText("请输入快递100 Key") vbox1.addWidget(QLabel("Key:")) vbox1.addWidget(self.kuaidi100_key_edit) self.kuaidi100_customer_edit = QLineEdit() self.kuaidi100_customer_edit.setPlaceholderText("请输入快递100 Customer") vbox1.addWidget(QLabel("Customer:")) vbox1.addWidget(self.kuaidi100_customer_edit) vbox1.addWidget(QLabel("💡 在 kuaidi100.com 注册获取")) form.addRow(group1) # 查询间隔 group2 = QGroupBox("查询设置") group2.setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }") vbox2 = QVBoxLayout(group2) interval_layout = QHBoxLayout() self.interval_spin = QSpinBox() self.interval_spin.setRange(5, 1440) self.interval_spin.setSuffix(" 分钟") self.interval_spin.setValue(30) interval_layout.addWidget(QLabel("查询间隔:")) interval_layout.addWidget(self.interval_spin) interval_layout.addStretch() vbox2.addLayout(interval_layout) form.addRow(group2) # 导出功能 group3 = QGroupBox("数据管理") group3.setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }") vbox3 = QVBoxLayout(group3) export_layout = QHBoxLayout() export_btn = QPushButton("📤 导出快递列表") export_btn.clicked.connect(self.export_tracking_list) export_layout.addWidget(export_btn) export_layout.addStretch() vbox3.addLayout(export_layout) form.addRow(group3) # 底部留白 form.addRow(QLabel("")) def apply_style(self): """应用现代化样式""" style = """ QMainWindow { background-color: #f0f2f5; } QTableWidget { background-color: white; alternate-background-color: #f8f9fa; gridline-color: #e9ecef; border: 1px solid #dee2e6; border-radius: 4px; } QTableWidget::item { padding: 8px; } QTableWidget::item:selected { background-color: #4a90d9; color: white; } QHeaderView::section { background-color: #e9ecef; padding: 8px; border: none; font-weight: bold; } QPushButton { background-color: #4a90d9; color: white; border: none; padding: 8px 16px; border-radius: 4px; font-weight: bold; } QPushButton:hover { background-color: #357abd; } QPushButton:pressed { background-color: #2a6bb5; } QPushButton#danger { background-color: #e74c3c; } QPushButton#danger:hover { background-color: #c0392b; } QPushButton#success { background-color: #27ae60; } QPushButton#success:hover { background-color: #219a52; } QLineEdit, QSpinBox, QTextEdit { padding: 8px; border: 1px solid #ced4da; border-radius: 4px; } QLineEdit:focus, QSpinBox:focus, QTextEdit:focus { border-color: #4a90d9; } QGroupBox { border: 1px solid #dee2e6; border-radius: 4px; margin-top: 10px; padding-top: 10px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px; } QTabWidget::pane { border: 1px solid #dee2e6; border-radius: 4px; background-color: white; } QTabBar::tab { padding: 10px 20px; background-color: #f8f9fa; border: 1px solid #dee2e6; border-bottom: none; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { background-color: white; border-bottom: 2px solid #4a90d9; } QTabBar::tab:hover { background-color: #e9ecef; } QScrollArea { border: none; background-color: transparent; } QStatusBar { background-color: #f8f9fa; color: #6c757d; padding: 4px; } """ self.setStyleSheet(style) # ============ 槽函数(仅保留占位,无实际功能) ============ def add_tracking(self): """添加快递""" dialog = AddTrackingDialog(self) if dialog.exec() == QDialog.DialogCode.Accepted: QMessageBox.information(self, "提示", "添加快递功能") def batch_import(self): """批量导入""" dialog = BatchImportDialog(self) if dialog.exec() == QDialog.DialogCode.Accepted: QMessageBox.information(self, "提示", "批量导入功能") def remove_tracking(self): """删除选中的快递""" current_row = self.table.currentRow() if current_row < 0: QMessageBox.warning(self, "提示", "请先选中要删除的快递") return QMessageBox.information(self, "提示", "删除快递功能") def clear_all(self): """清空所有快递""" reply = QMessageBox.question( self, "确认清空", "确定要清空所有快递吗?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No ) if reply == QMessageBox.StandardButton.Yes: QMessageBox.information(self, "提示", "清空全部功能") def manual_refresh(self): """手动刷新快递状态""" QMessageBox.information(self, "提示", "手动刷新功能") def toggle_tracking(self): """切换追踪状态""" if self.start_btn.text() == "▶ 启动追踪": self.start_btn.setText("⏹ 停止追踪") self.start_btn.setStyleSheet("background-color: #e74c3c; color: white;") self.status_label.setText("● 运行中") self.status_label.setStyleSheet("color: #27ae60; font-weight: bold;") self.status_bar.showMessage("追踪服务已启动") else: self.start_btn.setText("▶ 启动追踪") self.start_btn.setStyleSheet("background-color: #27ae60; color: white;") self.status_label.setText("● 已停止") self.status_label.setStyleSheet("color: #e74c3c; font-weight: bold;") self.status_bar.showMessage("追踪服务已停止") def export_tracking_list(self): """导出快递列表""" file_path, _ = QFileDialog.getSaveFileName( self, "导出快递列表", "快递列表.txt", "文本文件 (*.txt);;CSV文件 (*.csv)" ) if file_path: QMessageBox.information(self, "成功", f"已导出到:{file_path}")# ============ 程序入口 ============def main(): app = QApplication(sys.argv) app.setStyle("Fusion") window = MainWindow() window.show() sys.exit(app.exec())if __name__ == "__main__": main()