commit 609a2d8254ad98a89ec2150581ab4f62c2769542 Author: ChengQiqian Date: Wed Jul 9 19:18:56 2025 +0800 上传文件至 / diff --git a/picture_upload.py b/picture_upload.py new file mode 100644 index 0000000..44fb09a --- /dev/null +++ b/picture_upload.py @@ -0,0 +1,498 @@ +import os +import sys +import requests +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, + QLabel, QLineEdit, QComboBox, QPushButton, QFileDialog, + QGroupBox, QDateTimeEdit, QDoubleSpinBox, QSpinBox, QTextEdit, + QTabWidget, QScrollArea, QMessageBox, QCalendarWidget,QGridLayout) +from PyQt5.QtCore import Qt, QDateTime, QTimer +from PyQt5.QtGui import QFont, QIcon + + +class NoWheelComboBox(QComboBox): + def wheelEvent(self, event): + event.ignore() + + +class NoWheelSpinBox(QSpinBox): + def wheelEvent(self, event): + event.ignore() + + +class NoWheelDoubleSpinBox(QDoubleSpinBox): + def wheelEvent(self, event): + event.ignore() + + +class ImageUploaderApp(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("图片批量上传工具") + self.setWindowIcon(QIcon("upload_icon.png")) # 替换为您自己的图标或删除此行 + self.setGeometry(100, 100, 850, 650) + + # 初始化参数 + self.base_url = "http://pms.dtyx.net:9158/image" + self.default_part_id = "a3b4b81c5973a1895a4d95d50dd8351c" + self.file_paths = [] + self.upload_in_progress = False + + # 初始化UI + self.init_ui() + + def init_ui(self): + # 创建主窗口部件 + main_widget = QWidget() + self.setCentralWidget(main_widget) + + # 主布局 + main_layout = QVBoxLayout() + main_widget.setLayout(main_layout) + + # 创建标签页 + tab_widget = QTabWidget() + main_layout.addWidget(tab_widget) + + # 基本参数标签页 + basic_tab = QWidget() + tab_widget.addTab(basic_tab, "基本参数") + self.setup_basic_tab(basic_tab) + + # 高级参数标签页 + advanced_tab = QWidget() + tab_widget.addTab(advanced_tab, "高级参数") + self.setup_advanced_tab(advanced_tab) + + # 底部按钮区域 + button_layout = QHBoxLayout() + + self.upload_btn = QPushButton("开始上传") + self.upload_btn.setFont(QFont("Arial", 12, QFont.Bold)) + self.upload_btn.setStyleSheet("background-color: #4CAF50; color: white; padding: 10px;") + self.upload_btn.clicked.connect(self.start_upload) + + self.clear_btn = QPushButton("清空选择") + self.clear_btn.setFont(QFont("Arial", 12)) + self.clear_btn.setStyleSheet("background-color: #f44336; color: white; padding: 10px;") + self.clear_btn.clicked.connect(self.clear_selection) + + button_layout.addWidget(self.upload_btn) + button_layout.addWidget(self.clear_btn) + main_layout.addLayout(button_layout) + + # 日志输出 + self.log_text = QTextEdit() + self.log_text.setReadOnly(True) + self.log_text.setFont(QFont("Consolas", 10)) + self.log_text.setStyleSheet("background-color: #f5f5f5;") + main_layout.addWidget(self.log_text) + + def setup_basic_tab(self, tab): + layout = QVBoxLayout() + tab.setLayout(layout) + + # Part ID设置 + part_id_group = QGroupBox("部件ID设置") + part_id_layout = QVBoxLayout() + + self.part_id_input = QLineEdit(self.default_part_id) + part_id_layout.addWidget(QLabel("部件ID:")) + part_id_layout.addWidget(self.part_id_input) + + part_id_group.setLayout(part_id_layout) + layout.addWidget(part_id_group) + + # 图片源选择 + source_group = QGroupBox("图片源设置") + source_layout = QVBoxLayout() + + self.source_combo = NoWheelComboBox() + self.source_combo.addItems(["图像采集", "外部工作", "内部工作", "防雷工作"]) + self.source_combo.setCurrentText("内部工作") + source_layout.addWidget(QLabel("图片源类型:")) + source_layout.addWidget(self.source_combo) + + source_group.setLayout(source_layout) + layout.addWidget(source_group) + + # 图片类型选择 + type_group = QGroupBox("图片类型设置") + type_layout = QVBoxLayout() + + self.type_combo = NoWheelComboBox() + self.type_combo.addItems(["", "缺陷影像", "典型影像", "其他影像"]) + type_layout.addWidget(QLabel("图片类型:")) + type_layout.addWidget(self.type_combo) + + type_group.setLayout(type_layout) + layout.addWidget(type_group) + + # 拍摄方式选择 + method_group = QGroupBox("拍摄方式设置") + method_layout = QVBoxLayout() + + self.method_combo = NoWheelComboBox() + self.method_combo.addItems(["", "无人机航拍", "手持相机拍摄"]) + method_layout.addWidget(QLabel("拍摄方式:")) + method_layout.addWidget(self.method_combo) + + method_group.setLayout(method_layout) + layout.addWidget(method_group) + + # 天气选择 + weather_group = QGroupBox("天气设置") + weather_layout = QVBoxLayout() + + self.weather_combo = NoWheelComboBox() + weather_options = [ + "", "晴天", "多云", "阴天", "小雨", "中雨", "大雨", "暴雨", + "阵雨", "雷阵雨", "雷电", "冰雹", "轻雾", "雾", "浓雾", + "霾", "雨夹雪", "小雪", "中雪", "大雪", "暴雪", "冻雨" + ] + self.weather_combo.addItems(weather_options) + weather_layout.addWidget(QLabel("天气情况:")) + weather_layout.addWidget(self.weather_combo) + + weather_group.setLayout(weather_layout) + layout.addWidget(weather_group) + + # 文件选择按钮 + self.select_files_btn = QPushButton("选择图片文件") + self.select_files_btn.setFont(QFont("Arial", 12)) + self.select_files_btn.setStyleSheet("background-color: #2196F3; color: white; padding: 8px;") + self.select_files_btn.clicked.connect(self.select_files) + layout.addWidget(self.select_files_btn) + + # 选中的文件列表 + self.file_list_label = QLabel("已选择 0 个文件") + self.file_list_label.setFont(QFont("Arial", 10)) + layout.addWidget(self.file_list_label) + + # 添加弹性空间 + layout.addStretch() + + def setup_advanced_tab(self, tab): + scroll = QScrollArea() + scroll.setWidgetResizable(True) + tab.layout = QVBoxLayout(tab) + tab.layout.addWidget(scroll) + + container = QWidget() + scroll.setWidget(container) + + layout = QVBoxLayout() + container.setLayout(layout) + + # 采集员信息 + collector_group = QGroupBox("采集员信息") + collector_layout = QVBoxLayout() + + self.collector_id_input = QLineEdit() + self.collector_name_input = QLineEdit() + collector_layout.addWidget(QLabel("采集员ID:")) + collector_layout.addWidget(self.collector_id_input) + collector_layout.addWidget(QLabel("采集员姓名:")) + collector_layout.addWidget(self.collector_name_input) + + collector_group.setLayout(collector_layout) + layout.addWidget(collector_group) + + # 拍摄时间 + time_group = QGroupBox("拍摄时间") + time_layout = QVBoxLayout() + + # 开始时间 + start_time_group = QGroupBox("开始时间") + start_time_layout = QVBoxLayout() + + self.start_calendar = QCalendarWidget() + self.start_time_edit = QDateTimeEdit() + self.start_time_edit.setDisplayFormat("HH:mm:ss") + self.start_time_edit.setTime(QDateTime.currentDateTime().time()) + + start_time_layout.addWidget(self.start_calendar) + start_time_layout.addWidget(self.start_time_edit) + start_time_group.setLayout(start_time_layout) + + # 结束时间 + end_time_group = QGroupBox("结束时间") + end_time_layout = QVBoxLayout() + + self.end_calendar = QCalendarWidget() + self.end_time_edit = QDateTimeEdit() + self.end_time_edit.setDisplayFormat("HH:mm:ss") + self.end_time_edit.setTime(QDateTime.currentDateTime().time()) + + end_time_layout.addWidget(self.end_calendar) + end_time_layout.addWidget(self.end_time_edit) + end_time_group.setLayout(end_time_layout) + + time_layout.addWidget(start_time_group) + time_layout.addWidget(end_time_group) + time_group.setLayout(time_layout) + layout.addWidget(time_group) + + # 环境参数 + env_group = QGroupBox("环境参数") + env_layout = QGridLayout() + + self.humidity_spin = NoWheelSpinBox() + self.humidity_spin.setRange(0, 100) + self.humidity_spin.setSpecialValueText("未设置") + self.humidity_spin.setValue(0) + + self.temp_min_spin = NoWheelDoubleSpinBox() + self.temp_min_spin.setRange(-50, 50) + self.temp_min_spin.setSpecialValueText("未设置") + self.temp_min_spin.setValue(-50) + + self.temp_max_spin = NoWheelDoubleSpinBox() + self.temp_max_spin.setRange(-50, 50) + self.temp_max_spin.setSpecialValueText("未设置") + self.temp_max_spin.setValue(-50) + + self.wind_level_spin = NoWheelSpinBox() + self.wind_level_spin.setRange(0, 12) + self.wind_level_spin.setSpecialValueText("未设置") + self.wind_level_spin.setValue(0) + + self.distance_spin = NoWheelSpinBox() + self.distance_spin.setRange(0, 1000) + self.distance_spin.setSpecialValueText("未设置") + self.distance_spin.setValue(0) + + env_layout.addWidget(QLabel("湿度(%):"), 0, 0) + env_layout.addWidget(self.humidity_spin, 0, 1) + env_layout.addWidget(QLabel("最低温度(℃):"), 1, 0) + env_layout.addWidget(self.temp_min_spin, 1, 1) + env_layout.addWidget(QLabel("最高温度(℃):"), 2, 0) + env_layout.addWidget(self.temp_max_spin, 2, 1) + env_layout.addWidget(QLabel("风力等级:"), 3, 0) + env_layout.addWidget(self.wind_level_spin, 3, 1) + env_layout.addWidget(QLabel("拍摄距离(m):"), 4, 0) + env_layout.addWidget(self.distance_spin, 4, 1) + + env_group.setLayout(env_layout) + layout.addWidget(env_group) + + # 添加弹性空间 + layout.addStretch() + + def select_files(self): + options = QFileDialog.Options() + files, _ = QFileDialog.getOpenFileNames( + self, "选择图片文件", "", + "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif)", + options=options + ) + + if files: + self.file_paths = files + self.file_list_label.setText(f"已选择 {len(files)} 个文件") + self.log_message(f"已选择 {len(files)} 个图片文件") + + def clear_selection(self): + self.file_paths = [] + self.file_list_label.setText("已选择 0 个文件") + self.log_message("已清空文件选择") + + def log_message(self, message): + self.log_text.append(f"[{QDateTime.currentDateTime().toString('yyyy-MM-dd hh:mm:ss')}] {message}") + + def start_upload(self): + if self.upload_in_progress: + QMessageBox.warning(self, "警告", "已有上传任务在进行中!") + return + + if not self.file_paths: + QMessageBox.warning(self, "警告", "请先选择要上传的图片文件!") + return + + self.upload_in_progress = True + self.upload_btn.setEnabled(False) + self.clear_btn.setEnabled(False) + + # 使用QTimer在事件循环中启动上传,避免界面卡住 + QTimer.singleShot(100, self.upload_images) + + def upload_images(self): + try: + # 准备参数 + part_id = self.part_id_input.text().strip() or self.default_part_id + + # 从日历和时间控件获取时间 + start_date = self.start_calendar.selectedDate() + start_time = self.start_time_edit.time() + start_datetime = QDateTime(start_date, start_time) + + end_date = self.end_calendar.selectedDate() + end_time = self.end_time_edit.time() + end_datetime = QDateTime(end_date, end_time) + + # 构建参数字典,只包含有值的参数 + params = { + "imageSource": ["collect", "out-work", "in-work", "lightning-protection-work"][ + self.source_combo.currentIndex()], + } + + # 添加可选参数 + if self.type_combo.currentIndex() > 0: + params["imageType"] = ["", "DEFECT", "TYPICAL", "OTHER"][self.type_combo.currentIndex()] + + if self.method_combo.currentIndex() > 0: + params["shootingMethod"] = ["", "UAV", "HANDHELD_CAMERA"][self.method_combo.currentIndex()] + + if self.weather_combo.currentIndex() > 0: + weather_options = [ + "", "SUNNY", "CLOUDY", "OVERCAST", "LIGHT_RAIN", "MODERATE_RAIN", "HEAVY_RAIN", + "CLOUDBURST", "SHOWER", "THUNDERSHOWER", "THUNDER", "HAIL", "LIGHT_FOG", + "FOG", "THICK_FOG", "HAZE", "SLEET", "LIGHT_SNOW", "MODERATE_SNOW", + "HEAVY_SNOW", "BLIZZARD", "FREEZING_RAIN" + ] + params["weather"] = weather_options[self.weather_combo.currentIndex()] + + collector_id = self.collector_id_input.text().strip() + if collector_id: + params["collectorId"] = collector_id + + collector_name = self.collector_name_input.text().strip() + if collector_name: + params["collectorName"] = collector_name + + params["shootingTimeBegin"] = start_datetime.toString("yyyy-MM-dd hh:mm:ss") + params["shootingTimeEnd"] = end_datetime.toString("yyyy-MM-dd hh:mm:ss") + + # 环境参数 + if self.humidity_spin.value() > 0: + params["humidness"] = self.humidity_spin.value() + + if self.temp_min_spin.value() > -50: + params["temperatureMin"] = self.temp_min_spin.value() + + if self.temp_max_spin.value() > -50: + params["temperatureMax"] = self.temp_max_spin.value() + + if self.wind_level_spin.value() > 0: + params["windLevel"] = self.wind_level_spin.value() + + if self.distance_spin.value() > 0: + params["shootingDistance"] = self.distance_spin.value() + + # 构建URL + url = f"{self.base_url}/{params['imageSource']}/upload-batch/{part_id}" + + # 准备图片列表参数 + for i, file_path in enumerate(self.file_paths): + file_name = os.path.basename(file_path) + params[f"imageList[{i}].imageName"] = file_name + params[f"imageList[{i}].imagePath"] = file_path + + if "imageType" in params: + params[f"imageList[{i}].imageType"] = params["imageType"] + if "shootingMethod" in params: + params[f"imageList[{i}].shootingMethod"] = params["shootingMethod"] + if "weather" in params: + params[f"imageList[{i}].weather"] = params["weather"] + + # 准备文件数据 + files = [] + for file_path in self.file_paths: + file_name = os.path.basename(file_path) + files.append(('files', (file_name, open(file_path, 'rb'), 'image/jpeg'))) + + self.log_message(f"开始上传 {len(self.file_paths)} 张图片...") + self.log_message(f"请求URL: {url}") + self.log_message(f"请求参数: {params}") + + # 显示上传进度对话框 + self.progress = QMessageBox(self) + self.progress.setWindowTitle("上传中") + self.progress.setText(f"正在上传 {len(self.file_paths)} 张图片,请稍候...") + self.progress.setStandardButtons(QMessageBox.Cancel) + self.progress.buttonClicked.connect(self.cancel_upload) + self.progress.show() + + # 确保UI更新 + QApplication.processEvents() + + response = requests.post( + url, + headers={"Authorization": "null"}, + params=params, + files=files + ) + + self.progress.close() + + if response.status_code == 200: + self.log_message("上传成功!") + self.log_message(f"响应数据: {response.text}") + QMessageBox.information(self, "成功", "图片上传成功!") + else: + self.log_message(f"上传失败,状态码: {response.status_code}") + self.log_message(f"响应内容: {response.text}") + QMessageBox.critical(self, "错误", f"上传失败: {response.text}") + + except Exception as e: + self.log_message(f"上传过程中发生错误: {str(e)}") + QMessageBox.critical(self, "错误", f"上传过程中发生错误: {str(e)}") + + finally: + # 确保所有文件都被关闭 + if 'files' in locals(): + for file in files: + file[1][1].close() + + self.upload_in_progress = False + self.upload_btn.setEnabled(True) + self.clear_btn.setEnabled(True) + + def cancel_upload(self): + self.upload_in_progress = False + self.log_message("用户取消了上传操作") + self.progress.close() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + # 设置全局样式 + app.setStyle("Fusion") + app.setStyleSheet(""" + QMainWindow { + background-color: #f5f5f5; + } + QGroupBox { + font-weight: bold; + border: 1px solid #ccc; + border-radius: 5px; + margin-top: 10px; + padding-top: 15px; + } + QGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 3px; + } + QLabel { + font-size: 12px; + } + QComboBox, QLineEdit, QDateTimeEdit, QSpinBox, QDoubleSpinBox { + padding: 5px; + border: 1px solid #ccc; + border-radius: 3px; + min-width: 200px; + } + QTextEdit { + border: 1px solid #ccc; + border-radius: 3px; + } + QCalendarWidget { + border: 1px solid #ccc; + border-radius: 3px; + } + """) + + window = ImageUploaderApp() + window.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/video_upload.py b/video_upload.py new file mode 100644 index 0000000..1d30513 --- /dev/null +++ b/video_upload.py @@ -0,0 +1,302 @@ +import os +import sys +import re +import requests +from datetime import datetime +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, + QLabel, QLineEdit, QPushButton, QListWidget, QMessageBox, + QProgressBar, QFileDialog, QGroupBox, QFormLayout) +from PyQt5.QtCore import Qt, QThread, pyqtSignal + + +class VideoUploadThread(QThread): + progress_updated = pyqtSignal(int, str) + upload_finished = pyqtSignal(int, int) + + def __init__(self, files, params, parent=None): + super().__init__(parent) + self.files = files + self.params = params + self.base_url = "http://pms.dtyx.net:9158" + self.upload_endpoint = "/video-file-info/batch-upload" + self.running = True + + def run(self): + successful_uploads = 0 + failed_uploads = 0 + + for index, file_path in enumerate(self.files): + if not self.running: + break + + try: + # 从文件名中提取拍摄时间 + shooting_time = self.extract_time_from_filename(file_path) + params = self.params.copy() + if shooting_time: + params["shootingTime"] = shooting_time.strftime("%Y-%m-%d %H:%M:%S") + else: + # 如果没有提取到时间,使用当前时间 + params["shootingTime"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 读取文件内容 + with open(file_path, 'rb') as f: + files = {'file': (os.path.basename(file_path), f, 'video/mp4')} + + # 发送请求 + response = requests.post( + url=f"{self.base_url}{self.upload_endpoint}", + params=params, + files=files, + headers={"Authorization": None} # token为null + ) + + # 处理响应 + if response.status_code == 200: + result = response.json() + if result.get("success"): + self.progress_updated.emit(index + 1, f"上传成功: {os.path.basename(file_path)}") + successful_uploads += 1 + else: + self.progress_updated.emit(index + 1, + f"上传失败: {os.path.basename(file_path)} - {result.get('msg', '未知错误')}") + failed_uploads += 1 + else: + self.progress_updated.emit(index + 1, + f"上传失败: {os.path.basename(file_path)} - HTTP状态码: {response.status_code}") + failed_uploads += 1 + + except Exception as e: + self.progress_updated.emit(index + 1, f"上传异常: {os.path.basename(file_path)} - {str(e)}") + failed_uploads += 1 + + self.upload_finished.emit(successful_uploads, failed_uploads) + + def extract_time_from_filename(self, file_path): + """从文件名中提取时间信息""" + filename = os.path.basename(file_path) + + # 匹配类似 VID_20250611_144614 的格式 + match = re.search(r'(?:VID|VIDEO|视频)_?(\d{4})(\d{2})(\d{2})_?(\d{2})(\d{2})(\d{2})', filename, re.IGNORECASE) + if match: + year, month, day, hour, minute, second = match.groups() + try: + return datetime( + year=int(year), + month=int(month), + day=int(day), + hour=int(hour), + minute=int(minute), + second=int(second) + ) + except: + pass + + # 匹配其他常见日期格式 + date_patterns = [ + r'(\d{4})-(\d{2})-(\d{2})[ _](\d{2})-(\d{2})-(\d{2})', # 2025-06-11 14-46-14 + r'(\d{4})(\d{2})(\d{2})[ _](\d{2})(\d{2})(\d{2})', # 20250611 144614 + r'(\d{4})_(\d{2})_(\d{2})[ _](\d{2})_(\d{2})_(\d{2})', # 2025_06_11 14_46_14 + ] + + for pattern in date_patterns: + match = re.search(pattern, filename) + if match: + year, month, day, hour, minute, second = match.groups() + try: + return datetime( + year=int(year), + month=int(month), + day=int(day), + hour=int(hour), + minute=int(minute), + second=int(second) + ) + except: + continue + + return None + + def stop(self): + self.running = False + + +class VideoUploaderApp(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("防雷工作视频批量上传工具") + self.setGeometry(100, 100, 800, 600) + + self.upload_thread = None + self.init_ui() + + def init_ui(self): + # 主窗口布局 + main_widget = QWidget() + main_layout = QVBoxLayout() + + # 参数设置区域 + params_group = QGroupBox("上传参数设置") + params_layout = QFormLayout() + + self.part_id_input = QLineEdit("81d2bcdf0db9b0e986b61f986c5d520d") + self.location_input = QLineEdit() + self.test_point_input = QLineEdit() + self.worker_id_input = QLineEdit() + + params_layout.addRow(QLabel("部件ID:"), self.part_id_input) + params_layout.addRow(QLabel("拍摄地点:"), self.location_input) + params_layout.addRow(QLabel("测试点:"), self.test_point_input) + params_layout.addRow(QLabel("作业人员ID:"), self.worker_id_input) + + params_group.setLayout(params_layout) + + # 文件选择区域 + file_group = QGroupBox("视频文件选择") + file_layout = QVBoxLayout() + + self.file_list = QListWidget() + self.select_btn = QPushButton("选择视频文件") + self.select_btn.clicked.connect(self.select_videos) + self.clear_btn = QPushButton("清空列表") + self.clear_btn.clicked.connect(self.clear_file_list) + + file_layout.addWidget(self.file_list) + file_btn_layout = QHBoxLayout() + file_btn_layout.addWidget(self.select_btn) + file_btn_layout.addWidget(self.clear_btn) + file_layout.addLayout(file_btn_layout) + + file_group.setLayout(file_layout) + + # 上传控制区域 + control_layout = QHBoxLayout() + self.upload_btn = QPushButton("开始上传") + self.upload_btn.clicked.connect(self.start_upload) + self.stop_btn = QPushButton("停止上传") + self.stop_btn.clicked.connect(self.stop_upload) + self.stop_btn.setEnabled(False) + + control_layout.addWidget(self.upload_btn) + control_layout.addWidget(self.stop_btn) + + # 进度显示区域 + self.progress_bar = QProgressBar() + self.progress_bar.setAlignment(Qt.AlignCenter) + self.status_label = QLabel("准备就绪") + self.status_label.setAlignment(Qt.AlignCenter) + + # 组装主布局 + main_layout.addWidget(params_group) + main_layout.addWidget(file_group) + main_layout.addLayout(control_layout) + main_layout.addWidget(self.progress_bar) + main_layout.addWidget(self.status_label) + + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + def select_videos(self): + """选择视频文件""" + file_dialog = QFileDialog() + file_dialog.setFileMode(QFileDialog.ExistingFiles) + file_dialog.setNameFilter("视频文件 (*.mp4 *.avi *.mov *.mkv)") + + if file_dialog.exec_(): + file_paths = file_dialog.selectedFiles() + for file_path in file_paths: + self.file_list.addItem(file_path) + + self.status_label.setText(f"已选择 {len(file_paths)} 个视频文件") + + def clear_file_list(self): + """清空文件列表""" + self.file_list.clear() + self.status_label.setText("文件列表已清空") + + def start_upload(self): + """开始上传视频""" + if self.file_list.count() == 0: + QMessageBox.warning(self, "警告", "请先选择要上传的视频文件!") + return + + # 获取参数 + params = { + "partId": self.part_id_input.text().strip(), + "qualified": 1, # 默认合格 + "location": self.location_input.text().strip() or None, + "testPoint": self.test_point_input.text().strip() or None, + "workerUserId": self.worker_id_input.text().strip() or None + } + + # 验证部件ID + if not params["partId"]: + QMessageBox.warning(self, "警告", "部件ID不能为空!") + return + + # 获取文件列表 + file_paths = [self.file_list.item(i).text() for i in range(self.file_list.count())] + + # 设置UI状态 + self.upload_btn.setEnabled(False) + self.stop_btn.setEnabled(True) + self.progress_bar.setMaximum(len(file_paths)) + self.progress_bar.setValue(0) + self.status_label.setText("开始上传...") + + # 创建并启动上传线程 + self.upload_thread = VideoUploadThread(file_paths, params) + self.upload_thread.progress_updated.connect(self.update_progress) + self.upload_thread.upload_finished.connect(self.upload_finished) + self.upload_thread.start() + + def stop_upload(self): + """停止上传""" + if self.upload_thread and self.upload_thread.isRunning(): + self.upload_thread.stop() + self.status_label.setText("上传已停止") + self.upload_btn.setEnabled(True) + self.stop_btn.setEnabled(False) + + def update_progress(self, value, message): + """更新上传进度""" + self.progress_bar.setValue(value) + self.status_label.setText(message) + + def upload_finished(self, success_count, fail_count): + """上传完成处理""" + self.upload_btn.setEnabled(True) + self.stop_btn.setEnabled(False) + + msg = f"上传完成! 成功: {success_count} 个, 失败: {fail_count} 个" + self.status_label.setText(msg) + QMessageBox.information(self, "上传完成", msg) + + # 重置进度条 + self.progress_bar.reset() + + def closeEvent(self, event): + """窗口关闭事件""" + if self.upload_thread and self.upload_thread.isRunning(): + reply = QMessageBox.question( + self, '确认退出', + '上传正在进行中,确定要退出吗?', + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No + ) + + if reply == QMessageBox.Yes: + self.upload_thread.stop() + self.upload_thread.wait() + event.accept() + else: + event.ignore() + else: + event.accept() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = VideoUploaderApp() + window.show() + sys.exit(app.exec_()) \ No newline at end of file