#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 测试结果视图,用于查看和筛选测试结果 """ from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTableWidget, QTableWidgetItem, QHeaderView, QLineEdit, QComboBox, QDateTimeEdit, QMessageBox, QGridLayout) from PyQt5.QtCore import Qt, QDateTime, QSize import requests from config import HTTP_API_BASE_URL class TestResultView(QWidget): def __init__(self): super().__init__() self.api_base_url = HTTP_API_BASE_URL # 分页参数 self.current_page = 1 self.page_size = 20 self.total_count = 0 # 所有数据(从后端获取) self.all_data = [] self.filtered_data = [] self.init_ui() self.load_data() def init_ui(self): """初始化界面""" layout = QVBoxLayout(self) layout.setContentsMargins(10, 10, 10, 10) layout.setSpacing(10) # 筛选栏 self._create_filter_bar(layout) # 数据表格 self._create_table(layout) # 分页控制栏 self._create_pagination_bar(layout) def _create_filter_bar(self, parent_layout): """创建筛选栏(自适应1行或2行)""" # 创建筛选容器 self.filter_container = QWidget() self.filter_layout = QGridLayout(self.filter_container) self.filter_layout.setSpacing(10) self.filter_layout.setContentsMargins(0, 0, 0, 0) # 样品编号 sn_label = QLabel("样品编号:") self.sn_input = QLineEdit() self.sn_input.setPlaceholderText("请输入编号") self.sn_input.setFixedWidth(150) # 工单 workorder_label = QLabel("工单:") self.workorder_input = QLineEdit() self.workorder_input.setPlaceholderText("请输入测试工单") self.workorder_input.setFixedWidth(200) # 测试人员 inspector_label = QLabel("测试人员:") self.inspector_input = QLineEdit() self.inspector_input.setPlaceholderText("请输入测试人员") self.inspector_input.setFixedWidth(150) # 开始时间 self.start_datetime_edit = QDateTimeEdit() self.start_datetime_edit.setCalendarPopup(True) self.start_datetime_edit.setDisplayFormat("yyyy-MM-dd HH:mm:ss") self.start_datetime_edit.setDateTime(QDateTime.currentDateTime().addMonths(-1)) # 至 to_label = QLabel("至") # 结束时间 self.end_datetime_edit = QDateTimeEdit() self.end_datetime_edit.setCalendarPopup(True) self.end_datetime_edit.setDisplayFormat("yyyy-MM-dd HH:mm:ss") self.end_datetime_edit.setDateTime(QDateTime.currentDateTime()) # 查询按钮 search_btn = QPushButton("查询") search_btn.clicked.connect(self.on_search) search_btn.setFixedWidth(80) # 导出结果按钮 export_btn = QPushButton("导出结果") export_btn.clicked.connect(self.on_export) export_btn.setFixedWidth(100) # 将所有控件存储为列表,方便动态调整布局 self.filter_widgets = [ (sn_label, self.sn_input), (workorder_label, self.workorder_input), (inspector_label, self.inspector_input), (self.start_datetime_edit, to_label, self.end_datetime_edit), (search_btn, export_btn) ] # 初始化为2行布局 self._arrange_filters_two_rows() parent_layout.addWidget(self.filter_container) def _arrange_filters_one_row(self): """将筛选条件排列为1行""" # 清空现有布局 for i in reversed(range(self.filter_layout.count())): widget = self.filter_layout.itemAt(i).widget() if widget: self.filter_layout.removeWidget(widget) # 1行布局:所有控件排在同一行 col = 0 # 样品编号 self.filter_layout.addWidget(self.filter_widgets[0][0], 0, col) # Label col += 1 self.filter_layout.addWidget(self.filter_widgets[0][1], 0, col) # Input col += 1 # 工单 self.filter_layout.addWidget(self.filter_widgets[1][0], 0, col) col += 1 self.filter_layout.addWidget(self.filter_widgets[1][1], 0, col) col += 1 # 测试人员 self.filter_layout.addWidget(self.filter_widgets[2][0], 0, col) col += 1 self.filter_layout.addWidget(self.filter_widgets[2][1], 0, col) col += 1 # 时间范围 self.filter_layout.addWidget(self.filter_widgets[3][0], 0, col) # start_datetime col += 1 self.filter_layout.addWidget(self.filter_widgets[3][1], 0, col) # "至" col += 1 self.filter_layout.addWidget(self.filter_widgets[3][2], 0, col) # end_datetime col += 1 # 按钮 self.filter_layout.addWidget(self.filter_widgets[4][0], 0, col) # 查询 col += 1 self.filter_layout.addWidget(self.filter_widgets[4][1], 0, col) # 导出 col += 1 # 添加弹性空间 self.filter_layout.setColumnStretch(col, 1) def _arrange_filters_two_rows(self): """将筛选条件排列为2行""" # 清空现有布局 for i in reversed(range(self.filter_layout.count())): widget = self.filter_layout.itemAt(i).widget() if widget: self.filter_layout.removeWidget(widget) # 第一行:样品编号、工单、测试人员 col = 0 self.filter_layout.addWidget(self.filter_widgets[0][0], 0, col) # 样品编号Label col += 1 self.filter_layout.addWidget(self.filter_widgets[0][1], 0, col) # 样品编号Input col += 1 self.filter_layout.addWidget(self.filter_widgets[1][0], 0, col) # 工单Label col += 1 self.filter_layout.addWidget(self.filter_widgets[1][1], 0, col) # 工单Input col += 1 self.filter_layout.addWidget(self.filter_widgets[2][0], 0, col) # 测试人员Label col += 1 self.filter_layout.addWidget(self.filter_widgets[2][1], 0, col) # 测试人员Input col += 1 self.filter_layout.setColumnStretch(col, 1) # 弹性空间 # 第二行:时间范围和按钮 col = 0 self.filter_layout.addWidget(self.filter_widgets[3][0], 1, col) # start_datetime col += 1 self.filter_layout.addWidget(self.filter_widgets[3][1], 1, col) # "至" col += 1 self.filter_layout.addWidget(self.filter_widgets[3][2], 1, col) # end_datetime col += 1 self.filter_layout.addWidget(self.filter_widgets[4][0], 1, col) # 查询按钮 col += 1 self.filter_layout.addWidget(self.filter_widgets[4][1], 1, col) # 导出按钮 col += 1 self.filter_layout.setColumnStretch(col, 1) # 弹性空间 def _create_table(self, parent_layout): """创建数据表格""" self.table = QTableWidget() self.table.setColumnCount(18) self.table.setHorizontalHeaderLabels([ "序号", "样品编号", "项目代码", "项目阶段", "项目方案", "测试周次", "工单名称", "产品序列号", "测试设备", "测试通道", "跌落方向", "跌落高度(mm)", "跌落速度(次/Min)", "样品跌落次数", "方向当前次数", "木板累计跌落次数", "试验开始时间", "试验结束时间" ]) # 表格样式 self.table.setSelectionBehavior(QTableWidget.SelectRows) self.table.setSelectionMode(QTableWidget.SingleSelection) self.table.setAlternatingRowColors(True) self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.table.verticalHeader().setVisible(False) self.table.setEditTriggers(QTableWidget.NoEditTriggers) parent_layout.addWidget(self.table) def _create_pagination_bar(self, parent_layout): """创建分页控制栏""" pager_layout = QHBoxLayout() pager_layout.setSpacing(10) self.page_info_label = QLabel("") pager_layout.addWidget(self.page_info_label) pager_layout.addStretch() # 每页行数选择 page_size_label = QLabel("每页行数:") pager_layout.addWidget(page_size_label) self.page_size_combo = QComboBox() self.page_size_combo.addItems(["10", "20", "50", "100"]) self.page_size_combo.setCurrentText(str(self.page_size)) self.page_size_combo.currentTextChanged.connect(self.on_page_size_changed) pager_layout.addWidget(self.page_size_combo) self.prev_btn = QPushButton("上一页") self.prev_btn.clicked.connect(self.go_prev_page) pager_layout.addWidget(self.prev_btn) self.next_btn = QPushButton("下一页") self.next_btn.clicked.connect(self.go_next_page) pager_layout.addWidget(self.next_btn) parent_layout.addLayout(pager_layout) def resizeEvent(self, event): """窗口大小变化时自动调整筛选栏布局""" super().resizeEvent(event) if hasattr(self, 'filter_container'): # 获取当前窗口宽度 width = self.width() # 根据宽度阈值决定布局: # 大于1400px时显示1行,否则显示2行 if width > 1400: if not hasattr(self, '_current_layout') or self._current_layout != 'one_row': self._arrange_filters_one_row() self._current_layout = 'one_row' else: if not hasattr(self, '_current_layout') or self._current_layout != 'two_rows': self._arrange_filters_two_rows() self._current_layout = 'two_rows' def on_search(self): """查询按钮点击事件""" self.current_page = 1 self.load_data() def load_data(self): """从后端加载数据""" try: # 构建请求URL url = f"{self.api_base_url}/dbTableAccess" # 构建查询参数 params = { 'table': 'testReqResult', 'pageSize': self.page_size, 'currentPage': self.current_page, } # 添加时间筛选参数(后端处理)- 格式:yyyy/MM/dd HH:mm:ss start_dt = self.start_datetime_edit.dateTime().toString("yyyy/MM/dd HH:mm:ss") end_dt = self.end_datetime_edit.dateTime().toString("yyyy/MM/dd HH:mm:ss") params['date1'] = start_dt params['date2'] = end_dt # 添加样品编号筛选(后端处理) sn_filter = self.sn_input.text().strip() if sn_filter: params['SN'] = sn_filter # 添加工单筛选(后端处理) workorder_filter = self.workorder_input.text().strip() if workorder_filter: params['dutWorkOrder'] = workorder_filter print(f"[测试结果] 请求参数: {params}") # 调试输出 # 调用后端API response = requests.get(url, params=params, timeout=10) response.raise_for_status() result = response.json() print(f"[测试结果] 返回数据量: {result.get('length', 0)}, 总数: {result.get('totalCount', 0)}") # 调试输出 if 'data' in result: self.all_data = result['data'] self.total_count = result.get('totalCount', len(self.all_data)) # 应用前端筛选(测试人员) self.apply_frontend_filter() else: QMessageBox.warning(self, "错误", "获取数据失败") except Exception as e: print(f"加载测试结果数据失败: {e}") QMessageBox.warning(self, "错误", f"加载数据失败:{str(e)}") def apply_frontend_filter(self): """应用前端筛选(测试人员) 注意:样品编号、工单已由后端筛选,这里不再处理 """ inspector_filter = self.inspector_input.text().strip().lower() # 筛选数据 filtered = [] for item in self.all_data: # 测试人员筛选 - 使用 tester 字段 if inspector_filter: inspector = str(item.get('tester', '')).lower() if inspector_filter not in inspector: continue filtered.append(item) self.filtered_data = filtered print(f"[测试结果] 筛选后数据量: {len(filtered)}") # 调试输出 self.refresh_table() self.update_pagination_info() def _format_cell_value(self, value): """格式化单元格值,将 None/null/空字符串显示为空白""" if value is None or value == 'None' or value == 'null' or str(value).strip() == '': return '' return str(value) def refresh_table(self): """刷新表格显示""" self.table.setRowCount(len(self.filtered_data)) for idx, item in enumerate(self.filtered_data): # 序号 - 使用后端返回的 mysequence self.table.setItem(idx, 0, QTableWidgetItem(self._format_cell_value(item.get('mysequence', idx + 1)))) # 样品编号 - 使用 SN dut_sn = self._format_cell_value(item.get('SN')) self.table.setItem(idx, 1, QTableWidgetItem(dut_sn)) # 项目代码 - 使用 dutProject self.table.setItem(idx, 2, QTableWidgetItem(self._format_cell_value(item.get('dutProject')))) # 项目阶段 - 使用 dutPhase self.table.setItem(idx, 3, QTableWidgetItem(self._format_cell_value(item.get('dutPhase')))) # 项目方案 - 使用 dutProjectType self.table.setItem(idx, 4, QTableWidgetItem(self._format_cell_value(item.get('dutProjectType')))) # 测试周次 - 使用 dutWeeks self.table.setItem(idx, 5, QTableWidgetItem(self._format_cell_value(item.get('dutWeeks')))) # 工单名称 - 使用 dutWorkOrder self.table.setItem(idx, 6, QTableWidgetItem(self._format_cell_value(item.get('dutWorkOrder')))) # 产品序列号 - 蓝色显示 SN product_sn = self._format_cell_value(item.get('SN')) product_sn_item = QTableWidgetItem(product_sn) if product_sn: # 只有有值时才设置蓝色 product_sn_item.setForeground(Qt.blue) self.table.setItem(idx, 7, product_sn_item) # 测试设备 - 使用 machine_sn self.table.setItem(idx, 8, QTableWidgetItem(self._format_cell_value(item.get('machine_sn')))) # 测试通道 - 使用 station_no self.table.setItem(idx, 9, QTableWidgetItem(self._format_cell_value(item.get('station_no')))) # 跌落方向 - 使用 dropDirection self.table.setItem(idx, 10, QTableWidgetItem(self._format_cell_value(item.get('dropDirection')))) # 跌落高度(mm) - 使用 dropHeight_int self.table.setItem(idx, 11, QTableWidgetItem(self._format_cell_value(item.get('dropHeight_int')))) # 跌落速度(次/Min) - 使用 dropSpeed self.table.setItem(idx, 12, QTableWidgetItem(self._format_cell_value(item.get('dropSpeed')))) # 样品跌落次数 - 使用 dropCycles self.table.setItem(idx, 13, QTableWidgetItem(self._format_cell_value(item.get('dropCycles')))) # 方向当前次数 - 使用 itemCurrentCycles self.table.setItem(idx, 14, QTableWidgetItem(self._format_cell_value(item.get('itemCurrentCycles')))) # 木板累计跌落次数 - 使用 stationDropCycles self.table.setItem(idx, 15, QTableWidgetItem(self._format_cell_value(item.get('stationDropCycles')))) # 试验开始时间 - 使用 startTime self.table.setItem(idx, 16, QTableWidgetItem(self._format_cell_value(item.get('startTime')))) # 试验结束时间 - 使用 endTime self.table.setItem(idx, 17, QTableWidgetItem(self._format_cell_value(item.get('endTime')))) self.table.resizeColumnsToContents() def update_pagination_info(self): """更新分页信息""" total_pages = max(1, (self.total_count + self.page_size - 1) // self.page_size) self.page_info_label.setText( f"共 {self.total_count} 条,第 {self.current_page}/{total_pages} 页,每页 {self.page_size} 条" ) self.prev_btn.setEnabled(self.current_page > 1) self.next_btn.setEnabled(self.current_page < total_pages) def on_page_size_changed(self, text): """每页行数改变""" try: self.page_size = int(text) except Exception: self.page_size = 10 self.current_page = 1 self.load_data() def go_prev_page(self): """上一页""" if self.current_page > 1: self.current_page -= 1 self.load_data() def go_next_page(self): """下一页""" total_pages = max(1, (self.total_count + self.page_size - 1) // self.page_size) if self.current_page < total_pages: self.current_page += 1 self.load_data() def on_export(self): """导出结果""" QMessageBox.information(self, "导出", "导出功能开发中...")