from UI.workloadinfos import Ui_workloadinfos from .LogerinTxt import app_logger from PyQt6.QtCore import Qt,QTimer from PyQt6.QtWidgets import QWidget,QMessageBox,QTableWidgetItem,QFileDialog,QStyledItemDelegate,QStyle,QMenu from PyQt6 import QtCore from PyQt6.QtGui import QTextDocument, QTextCursor, QTextCharFormat, QColor, QTextOption, QPalette import requests import os import json import openpyxl import datetime import time filename = "D:\\flightinfo\\logs\\peoples.json" class Workloadinfos(Ui_workloadinfos, QWidget): def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) self.ipinfo = None self.user = None self.selectedbc=None self.selectedtime=None self.doubleclickLock = 0 self.headerLabel = ["序号", "交", "姓名", "备", "角色", "备", "授权", "备", "工作量", "备", "当前工作量", "备", "总工作量", "备", "总工时", "备", "当前工作", "备", "修正工时", "备", "修正详情", "备注信息", "备", "备", "备", "备", "备", "备", "1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"] self.tableWidgetWorkload.setSortingEnabled(True) self.tableWidgetWorkload.setColumnCount(len(self.headerLabel)) self.tableWidgetWorkload.verticalHeader().setVisible(False) self.tableWidgetWorkload.setHorizontalHeaderLabels(self.headerLabel) self.refresh.clicked.connect(self.refreshnow) self.changeupdate.clicked.connect(self.update) self.clear.clicked.connect(self.clearselect) self.autoupdateMode=False self.autoupdate_check.stateChanged.connect(self.on_checkbox_changed) # 保存当前排序状态 self.current_sort_column = -1 self.current_sort_order = Qt.SortOrder.AscendingOrder self.searchinfo.returnPressed.connect(self.search_table) self.searchinfo.textChanged.connect(self.search_table_empty) self.selectall.clicked.connect(self.selectall_funciton) self.load_pushbutton.clicked.connect(self.get_load) self.tableWidgetWorkload.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.tableWidgetWorkload.customContextMenuRequested.connect(self.generateMenu) self.tableWidgetWorkload.horizontalHeader().sortIndicatorChanged.connect(self.on_sort_changed) self.changeupdate.clicked.connect(self.changeupdate_Function) self.tableWidgetWorkload.cellDoubleClicked.connect(self.itemclick2) def start(self): self.show() self.peopleresold = self.read_json_to_list() try: ip = "http://" + str(self.ipinfo) + "/static/getPglistInDatabase" self.peopleres = requests.get(url=ip, timeout=30).json()['返回值'] #print(self.peopleres) except Exception as e: QMessageBox.warning(self, "提示", "服务器连接超时,请联系管理员检查服务器!") app_logger.log_error(e) self.peopleres = [] self.peopleselect=self.peopleresold if self.peopleresold else self.peopleres self.comboBox_peoplelist.addItems(self.peopleres) self.set_initial_selection() self.refreshnow() self.serchTimer = QTimer() self.serchTimer.start(120 * 1000) self.serchTimer.timeout.connect(self.autoupdate) def itemclick2(self, row, column): try: # print(self.doubleclickLock) if column == 21 and self.doubleclickLock == 0: self.doubleclickLockUpdate=1 self.clickrow = row self.clickcolumn = column self.olditem = self.tableWidgetWorkload.item(row, column).text() item = self.tableWidgetWorkload.item(row, column) # 如果单元格对象不存在,则返回默认的背景色 if not item: self.color=self.tableWidgetWorkload.palette().color(QPalette.Base) else: # 获取并返回单元格的背景色 self.color = item.background() self.tableWidgetWorkload.cellChanged.connect(self.cellchanged) else: self.doubleclickLockUpdate = 0 except Exception as e: app_logger.log_error(e) def cellchanged(self, row, column): if self.clickrow == row and self.clickcolumn == column : self.clickrow = None self.clickcolumn = None try: self.doubleclickLock = 1 self.newitem = self.tableWidgetWorkload.item(row, column).text().replace("\"","*").replace("\\",";").replace("\'","*").replace("/","、").replace("#","*") name = self.tableWidgetWorkload.item(row, 2).text() if column == 21 and self.olditem != self.newitem: item = self.tableWidgetWorkload.item(row, column) if item.text() != "": text = item.text().replace("\"", "*").replace("\\", ";").replace("\'", "*").replace("/", "、").replace("#", "*") else: text = "清空项目12345678987654321" ip = "http://" + str(self.ipinfo) + "/static/updateNoteItem/" + "%s/" % str(text) + "%s" % str(name) # print(ip) ip2 = "http://" + str(self.ipinfo) + "/static/insertLogs2/" + "排班辅助%s的备注模块:由%s变更为%s/" % (name,self.olditem, self.newitem) + "%s/" % str(self.user) + "%s" % str(datetime.datetime.now()) try: requests.get(url=ip, timeout=30).json() requests.get(url=ip2, timeout=30).json() self.tableWidgetWorkload.setItem(int(row), column, QTableWidgetItem(str(self.newitem))) self.tableWidgetWorkload.item(int(row), column).setBackground(QColor("yellow")) self.tableWidgetWorkload.item(int(row), column).setTextAlignment(Qt.AlignmentFlag.AlignCenter) except Exception as e: app_logger.log_error(e) QMessageBox.warning(self, "提示", "服务器连接超时,请联系管理员检查服务器!") self.doubleclickLockUpdate = 0 self.doubleclickLock = 0 self.tableWidgetWorkload.cellChanged.disconnect(self.cellchanged) except Exception as e: self.doubleclickLockUpdate = 0 self.clickrow = None self.clickcolumn = None app_logger.log_error(e) try: self.tableWidgetWorkload.cellChanged.disconnect(self.cellchanged) except: pass self.tableWidgetWorkload.setItem(int(row), column, QTableWidgetItem(str(self.olditem))) self.tableWidgetWorkload.item(int(row), column).setBackground(QColor(self.color)) self.tableWidgetWorkload.item(int(row), column).setTextAlignment(Qt.AlignmentFlag.AlignCenter) app_logger.log_error(e) self.doubleclickLock = 0 def changeupdate_Function(self): day=datetime.datetime.now().strftime("%Y%m%d") info = self.changeinfo.text().strip().lower() people = self.changepeople.text().strip() costtime = self.changevalue.text().strip().lower() try: costtime = float(costtime) if info and people and costtime: timestr=str(int(time.time()*1000)) id= f"人工修正-{info}-{timestr}-{people}" data0={ "id": id, 'people':people, 'costtime':costtime, 'info':info, 'day':day } try: ip = "http://" + str(self.ipinfo) + "/static/manchangecosttime" data = json.dumps(data0) res = requests.post(url=ip, data=data, timeout=30).json() if res["返回值"] == "ok": QMessageBox.information(self, "提示", "操作成功!") self.refreshnow() else: QMessageBox.warning(self, "提示", "操作失败!") except Exception as e: QMessageBox.warning(self, "提示", "服务器连接超时,请联系管理员检查服务器!") app_logger.log_error(e) else: QMessageBox.warning(self,"警告", "请填写完整信息!!!") except ValueError: QMessageBox.warning(self,"警告", "工时内请填写数字!!!") def generateMenu(self, pos): try: nowDay = datetime.date.today().strftime("%Y%m%d") a_str = nowDay + " 09:00:00" b_str = nowDay + " 20:30:00" a = datetime.datetime.strptime(a_str, "%Y%m%d %H:%M:%S") b = datetime.datetime.strptime(b_str, "%Y%m%d %H:%M:%S") nowtime = datetime.datetime.now() passday = (nowtime - datetime.timedelta(days=4)).strftime("%Y%m%d") if a < nowtime < b: for i in self.tableWidgetWorkload.selectionModel().selection().indexes(): menu = QMenu() item = menu.addAction('上个班未交班') item2 = menu.addAction('上个班交班') screenPos = self.tableWidgetWorkload.mapToGlobal(pos) action = menu.exec(screenPos) rowIndex = i.row() taskids = self.tableWidgetWorkload.item(rowIndex, 3).text() handstsNow=self.tableWidgetWorkload.item(rowIndex, 1).text() name=self.tableWidgetWorkload.item(rowIndex, 2).text() data={ "ids":taskids, "type":handstsNow, "name":name, "date":passday, } if action == item: if handstsNow == "Y": self.handoverflight(data) self.refreshnow() else: QMessageBox.warning(self, "警告", f"未查询到{name}交班记录,无需取消交班") return elif action == item2: if handstsNow != "Y": self.handoverflight(data) self.refreshnow() else: QMessageBox.warning(self, "警告", f"经查询{name}已被记录交班,不用重复记录") return else: return except Exception as e: app_logger.log_error(e) def get_load(self): try: peoples = [] fileName, _ = QFileDialog.getOpenFileName(self, '打开文件', '/') ext = os.path.splitext(fileName)[1].lower() if ext == ".xlsx": workbook = openpyxl.load_workbook(filename=fileName) mysheet = workbook.active myrows = list(mysheet.values) if myrows[0][0] != ""and myrows[0][0] != None: for i in myrows: if i[0] != ""and i[0] != None: peoples.append(i[0]) if peoples: self.peopleselect=peoples self.write_list_to_json(peoples) self.set_initial_selection() self.refreshnow() else: QMessageBox.information(self, "提示", "人员名单导入为空,请重新录入") else: QMessageBox.warning(self, "警告", "请使用xlsx文件,在第一列输入人名再导入,人名需要带字母") return except Exception as e: app_logger.log_error(e) def selectall_funciton(self): self.peopleselect=self.peopleres self.write_list_to_json(self.peopleselect) self.set_initial_selection() def search_table_empty(self): """根据搜索框内容过滤表格数据""" search_text = self.searchinfo.text().strip().lower() if not search_text: # 如果搜索框为空,显示所有行 for row in range(self.tableWidgetWorkload.rowCount()): self.tableWidgetWorkload.setRowHidden(row, False) return def search_table(self): """根据搜索框内容过滤表格数据""" search_text = self.searchinfo.text().strip().lower() if not search_text: # 如果搜索框为空,显示所有行 for row in range(self.tableWidgetWorkload.rowCount()): self.tableWidgetWorkload.setRowHidden(row, False) return # 遍历表格所有单元格进行搜索 for row in range(self.tableWidgetWorkload.rowCount()): row_hidden = True for col in range(self.tableWidgetWorkload.columnCount()): item = self.tableWidgetWorkload.item(row, col) if item and search_text in item.text().lower(): row_hidden = False break self.tableWidgetWorkload.setRowHidden(row, row_hidden) def on_sort_changed(self, logicalIndex, order): """记录当前的排序状态""" self.current_sort_column = logicalIndex self.current_sort_order = order def on_checkbox_changed(self, state): if state != 0: self.autoupdateMode = True else: self.autoupdateMode = False def ensure_file_exists(self): """确保文件存在,不存在则创建空文件""" directory = os.path.dirname(filename) # 如果目录不存在,则创建目录 if directory and not os.path.exists(directory): os.makedirs(directory) # 如果文件不存在,则创建空文件 if not os.path.exists(filename): with open(filename, 'w', encoding='utf-8') as f: f.write("[]") # def write_list_to_json(self,data_list): """将 Python 列表写入 JSON 文件""" try: self.ensure_file_exists() # 确保文件存在 with open(filename, 'w', encoding='utf-8') as f: json.dump(data_list, f, ensure_ascii=False) #print(f"数据已成功写入 {filename}") except Exception as e: app_logger.log_error(e) #print(f"写入文件时出错: {e}") def read_json_to_list(self): """从 JSON 文件读取数据并转换为 Python 列表""" try: self.ensure_file_exists() # 确保文件存在 with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) return data except json.JSONDecodeError: #print(f"文件 {filename} 格式不是有效的 JSON,将重置为空列表") # 重置文件为空白列表 self.write_list_to_json([]) return None except Exception as e: return None def set_initial_selection(self): """设置多选ComboBox的初始选中值""" for i in range(self.comboBox_peoplelist.model().rowCount()): item = self.comboBox_peoplelist.model().item(i) if item.text() in self.peopleselect: item.setCheckState(QtCore.Qt.CheckState.Checked) else: item.setCheckState(QtCore.Qt.CheckState.Unchecked) self.comboBox_peoplelist.update_text() def getdatas(self): try: ip = "http://" + str(self.ipinfo) + "/static/getworkload" data = json.dumps(self.peopleselect) res = requests.post(url=ip, data=data, timeout=30).json() return res except Exception as e: QMessageBox.warning(self, "提示", "服务器连接超时,请联系管理员检查服务器!") app_logger.log_error(e) def handoverflight(self,data0): try: ip = "http://" + str(self.ipinfo) + "/static/handoverflight" data = json.dumps(data0) res = requests.post(url=ip, data=data, timeout=30).json() if res["返回值"] == "ok": QMessageBox.information(self, "提示", "操作成功!") else: QMessageBox.warning(self, "提示", "操作失败!") except Exception as e: QMessageBox.warning(self, "提示", "服务器连接超时,请联系管理员检查服务器!") app_logger.log_error(e) def autoupdate(self): if self.autoupdateMode: res = self.getdatas() self.tableDisplay(res) if self.searchinfo.text(): self.search_table() def tableDisplay(self,displaydata): try: if displaydata: self.tableWidgetWorkload.setSortingEnabled(False) # 清除原有数据 self.tableWidgetWorkload.setRowCount(0) # 设置列数(假设数据是二维列表,第一行为表头) self.tableWidgetWorkload.setRowCount(len(displaydata)) for row in range(len(displaydata)): for col in range(len(self.headerLabel)): item = QTableWidgetItem(str(displaydata[str(row)][str(col)])) self.tableWidgetWorkload.setItem(row, col, item) if col == 16 and "无" not in str(displaydata[str(row)][str(col)]): item.setForeground(QColor("red")) font = item.font() item.setFont(font) elif col == 8 : item.setForeground(QColor("green")) font = item.font() font.setBold(True) item.setFont(font) elif col == 21 and str(displaydata[str(row)][str(col)]) != "" : item.setBackground(QColor("yellow")) elif col == 1 and str(displaydata[str(row)][str(col)]) == "Y": item.setBackground(QColor("yellow")) if col not in [5]: self.tableWidgetWorkload.item(int(row), col).setTextAlignment(Qt.AlignmentFlag.AlignCenter) else: self.tableWidgetWorkload.item(int(row), col).setTextAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignCenter) self.tableWidgetWorkload.setRowHeight(int(row), 35) settips = {1: "3", 14: "20"} for key, value in settips.items(): if self.tableWidgetWorkload.item(int(row), key): self.tableWidgetWorkload.item(int(row), key).setToolTip("%s" % (str(displaydata[str(row)][str(value)]))) self.tableWidgetWorkload.setItemDelegate(ColoredTextDelegate()) self.tableWidgetWorkload.resizeColumnsToContents() self.tableWidgetWorkload.setWordWrap(True) self.tableWidgetWorkload.setColumnWidth(6, 100) for i in range(len(self.headerLabel)): if i in [3,5,7,9,11,13,15,17,19,22,23,24,25,26,27,10,12,18,20]: self.tableWidgetWorkload.setColumnHidden(i, True) else: self.tableWidgetWorkload.setColumnHidden(i, False) self.tableWidgetWorkload.setSortingEnabled(True) except Exception as e: app_logger.log_error(e) self.tableWidgetWorkload.setSortingEnabled(True) def refreshnow(self): self.peopleselect = self.comboBox_peoplelist.get_selected_items() self.write_list_to_json(self.peopleselect) res=self.getdatas() self.tableDisplay(res) if self.searchinfo.text(): self.search_table() def clearselect(self): self.peopleselect=[] self.write_list_to_json(self.peopleselect) self.set_initial_selection() class ColoredTextDelegate(QStyledItemDelegate): def paint(self, painter, option, index):# 保存painter状态 painter.save() # 设置交替行颜色 palette = option.palette if index.row() % 2 == 1: bg_color = palette.color(QPalette.ColorRole.AlternateBase) else: bg_color = palette.color(QPalette.ColorRole.Base) # 绘制背景(考虑选中状态) if option.state & QStyle.StateFlag.State_Selected: painter.fillRect(option.rect, palette.highlight()) else: painter.fillRect(option.rect, bg_color) if index.column() in [28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47]: # 获取单元格文本 text = index.data(Qt.ItemDataRole.DisplayRole) or "" if "预排" in text: painter.fillRect(option.rect, QColor("yellow")) # 设置文本绘制选项 painter.save() text_option = QTextOption() text_option.setAlignment(Qt.AlignmentFlag.AlignCenter) doc = QTextDocument() doc.setDefaultTextOption(text_option) doc.setTextWidth(option.rect.width()) default_format = QTextCharFormat() default_format.setForeground(QColor("gray")) font = default_format.font() font.setPointSize(8) default_format.setFont(font) balck_format = QTextCharFormat() balck_format.setForeground(QColor("balck")) font = balck_format.font() font.setPointSize(10) balck_format.setFont(font) # 插入带格式文本 cursor = QTextCursor(doc) cursor.insertText(text[:5], balck_format) cursor.insertText(text[5:], default_format) # 绘制文档 painter.save() painter.translate(option.rect.topLeft()) doc.drawContents(painter) painter.restore() elif index.column() == 8: text = index.data(Qt.ItemDataRole.DisplayRole) or "" start = text.find("(") end = text.find(")") # 设置文本绘制选项 painter.save() text_option = QTextOption() text_option.setAlignment(Qt.AlignmentFlag.AlignCenter) doc = QTextDocument() doc.setDefaultTextOption(text_option) doc.setTextWidth(option.rect.width()) default_format = QTextCharFormat() default_format.setForeground(QColor("red")) font = default_format.font() font.setBold(True) default_format.setFont(font) balck_format = QTextCharFormat() balck_format.setForeground(QColor("balck")) # 插入带格式文本 cursor = QTextCursor(doc) cursor.insertText(text[:start+1], balck_format) cursor.insertText(text[start+1:end], default_format) cursor.insertText(text[end:], balck_format) # 计算垂直居中位置 text_height = doc.size().height() y_offset = (option.rect.height() - text_height) / 2 # 绘制文本 painter.translate(option.rect.x(), option.rect.y() + y_offset) doc.drawContents(painter) painter.restore() else: # 其他单元格使用默认绘制 super().paint(painter, option, index) def sizeHint(self, option, index): # 确保单元格有合适的大小 if index.column() == 8: text = index.data(Qt.ItemDataRole.DisplayRole) or "" doc = QTextDocument() doc.setPlainText(text) doc.setTextWidth(option.rect.width()) return doc.size().toSize() return super().sizeHint(option, index)