情况中的待执行优化好了

This commit is contained in:
27942
2026-01-29 14:04:56 +08:00
parent 9ab7eb2a9a
commit 57269bcd3b

View File

@@ -15,7 +15,7 @@ from PyQt5.QtWidgets import (
QStyle, QComboBox, QFrame, QShortcut, QMenu, QAbstractButton,
QAbstractItemView, QTableView, QStyledItemDelegate,
QStyleOptionProgressBar, QStyleOptionButton, QHeaderView,
QTabWidget, QSplitter, QSizePolicy
QTabWidget, QSplitter, QSizePolicy, QCheckBox
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QDateTime, QSize, QAbstractTableModel, QModelIndex, \
QSortFilterProxyModel, QRegularExpression, QSettings, QTimer, QEvent
@@ -1120,7 +1120,7 @@ class MainWindow(QMainWindow):
self.table_next_match_btn.clicked.connect(self.next_table_match)
search_row.addWidget(self.table_next_match_btn)
self.table_clear_btn = PushButton("清空筛选")
self.table_clear_btn.clicked.connect(lambda: self.table_search_input.setText(""))
self.table_clear_btn.clicked.connect(self._clear_filter_and_selection)
search_row.addWidget(self.table_clear_btn)
self.table_export_all_btn = PushButton("导出全部")
self.table_export_all_btn.clicked.connect(self.export_all_rows)
@@ -1154,15 +1154,16 @@ class MainWindow(QMainWindow):
'执行人', '情况', '文件路径', '进度', '操作'
])
self.table_column_filter.addItem("全部列")
# 第0列为勾选框排除"情况"列以多多ID等为筛选项记录下拉项对应的表格列索引及 Model 列索引
# 第0列为勾选框记录下拉项对应的表格列索引及 Model 列索引
self._filter_table_columns = []
self._filter_model_columns = [] # Model/View 无勾选列,情况=7 跳过
self._filter_model_columns = [] # Model/View 无勾选列
for col in range(1, 10):
header = self.config_table.horizontalHeaderItem(col)
if header and header.text() != "情况":
if header:
self.table_column_filter.addItem(header.text())
self._filter_table_columns.append(col)
self._filter_model_columns.append(8 if col == 9 else col - 1) # 1..7→0..6, 9→8
# Model/View 列映射:1..8→0..7, 9→8
self._filter_model_columns.append(8 if col == 9 else col - 1)
# 默认按多多ID筛选多多ID为下拉第2项index=1
if self._filter_table_columns and self._filter_table_columns[0] == 1:
self.table_column_filter.setCurrentIndex(1)
@@ -1191,12 +1192,10 @@ class MainWindow(QMainWindow):
self.config_table.horizontalHeader().sectionResized.connect(self.on_column_resized)
# 连接表格resize事件用于自动按比例调整列宽
self.config_table.horizontalHeader().geometriesChanged.connect(self.on_table_geometry_changed)
# 设置表格最小高度,确保显示更多行
self.config_table.setMinimumHeight(600) # 最小高度600像素
# 点击空白区域或按Esc键时退出编辑状态
self.config_table.viewport().installEventFilter(self)
self.config_table.installEventFilter(self)
table_layout.addWidget(self.config_table)
table_layout.addWidget(self.config_table, 1) # stretch=1占据剩余空间
# 大数据模式表格Model/View
self.table_view = QTableView()
@@ -1227,14 +1226,16 @@ class MainWindow(QMainWindow):
}
""")
self.table_view.setVisible(False)
table_layout.addWidget(self.table_view)
table_layout.addWidget(self.table_view, 1) # stretch=1占据剩余空间
self.table_empty_label = QLabel("暂无数据请先导入Excel配置")
self.table_empty_label.setStyleSheet("color: #999; font-size: 12px;")
self.table_empty_label.setAlignment(Qt.AlignCenter)
self.table_empty_label.setVisible(True)
table_layout.addWidget(self.table_empty_label)
# 分页控件行(不设置 stretch固定在底部
pagination_row = QHBoxLayout()
pagination_row.setContentsMargins(0, 8, 0, 0)
pagination_row.addStretch()
self.page_size_combo = QComboBox()
self.page_size_combo.addItems(["10", "20", "50", "100"])
@@ -1256,7 +1257,7 @@ class MainWindow(QMainWindow):
pagination_row.addWidget(self.page_prev_btn)
pagination_row.addWidget(self.page_next_btn)
pagination_row.addWidget(self.page_last_btn)
table_layout.addLayout(pagination_row)
table_layout.addLayout(pagination_row, 0) # stretch=0固定大小
self.table_group.setVisible(True)
self.table_group.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -1501,16 +1502,29 @@ class MainWindow(QMainWindow):
def _set_checkbox_item(self, row, config_index):
"""设置勾选框列第0列勾选框在单元格内水平、垂直居中"""
checkbox = CheckBox()
checkbox = QCheckBox()
checkbox.setChecked(self.configs[config_index].get('勾选', False)) # 默认不勾选
checkbox.stateChanged.connect(lambda state, idx=config_index: self._on_checkbox_changed(idx, state))
checkbox.setStyleSheet(
"QCheckBox { margin: 0px; padding: 0px; }"
"QCheckBox::indicator { width: 25px; height: 25px; }"
)
wrapper = QWidget()
layout = QHBoxLayout(wrapper)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addStretch()
layout.addWidget(checkbox, 0, Qt.AlignCenter)
layout.addStretch()
# 使用嵌套布局确保水平和垂直都居中
outer_layout = QVBoxLayout(wrapper)
outer_layout.setContentsMargins(0, 0, 0, 0)
outer_layout.setSpacing(0)
outer_layout.addStretch()
inner_layout = QHBoxLayout()
inner_layout.setContentsMargins(0, 0, 0, 0)
inner_layout.setSpacing(0)
inner_layout.addStretch()
inner_layout.addWidget(checkbox)
inner_layout.addStretch()
outer_layout.addLayout(inner_layout)
outer_layout.addStretch()
self.config_table.setCellWidget(row, 0, wrapper)
def _on_checkbox_changed(self, config_index, state):
@@ -1519,6 +1533,8 @@ class MainWindow(QMainWindow):
self.configs[config_index]['勾选'] = (state == Qt.Checked)
# 更新已选数量显示
self._update_checked_count()
# 更新状态统计
self._update_status_statistics()
def _update_checked_count(self):
"""更新已勾选的数量显示"""
@@ -1527,18 +1543,85 @@ class MainWindow(QMainWindow):
checked_count = sum(1 for config in self.configs if config.get('勾选', False))
self.table_select_count.setText(f"已选: {checked_count}")
def toggle_all_checkboxes(self):
"""全选/取消全选所有勾选"""
is_checked = self.table_select_all_checkbox.isChecked()
def _clear_filter_and_selection(self):
"""清空筛选并取消所有勾选"""
# 取消所有勾选
for config in self.configs:
config['勾选'] = is_checked
config['勾选'] = False
# 取消全选复选框
if hasattr(self, 'table_select_all_checkbox'):
self.table_select_all_checkbox.setChecked(False)
# 清空搜索框(会触发 filter_table 显示所有行)
self.table_search_input.setText("")
# 刷新表格显示
self.update_table()
self._update_checked_count()
if is_checked:
self._show_infobar("success", "提示", f"已全选 {len(self.configs)}")
self._show_infobar("info", "已清空", "筛选条件和勾选已清空")
def toggle_all_checkboxes(self):
"""全选/取消全选 - 跨页操作所有数据(考虑筛选条件)"""
is_checked = self.table_select_all_checkbox.isChecked()
visible_count = 0
# 检查是否有筛选条件(搜索关键词或状态筛选)
has_search_filter = hasattr(self, 'table_search_input') and self.table_search_input.text().strip()
has_status_filter = hasattr(self, '_current_status_filter') and self._current_status_filter
if has_search_filter or has_status_filter:
# 有筛选条件:只操作筛选后的数据
# 遍历所有配置,只操作符合筛选条件的
for config_index, config in enumerate(self.configs):
# 检查是否符合搜索筛选(支持多关键词,所有关键词都要匹配)
if has_search_filter:
search_text = self.table_search_input.text().strip()
terms_raw = [t for t in search_text.split() if t]
if terms_raw:
column_index = self._filter_column_index()
match = False
if column_index >= 0:
# 按指定列筛选
col_key_map = {0: '多多id', 1: '序号', 2: '话题', 3: '定时发布',
4: '间隔时间', 5: '达人链接', 6: '执行人', 7: '情况', 8: '文件路径'}
if column_index in col_key_map:
cell_value = str(config.get(col_key_map[column_index], '')).lower()
# 所有关键词都要在单元格中
if all(term.lower() in cell_value for term in terms_raw):
match = True
else:
# 全列搜索
all_text = ' '.join([str(config.get(k, '')) for k in
['多多id', '序号', '话题', '定时发布', '间隔时间',
'达人链接', '执行人', '情况', '文件路径']]).lower()
# 所有关键词都要在文本中
if all(term.lower() in all_text for term in terms_raw):
match = True
if not match:
continue
# 检查是否符合状态筛选
if has_status_filter:
config_status = config.get('情况', '待执行')
if config_status != self._current_status_filter:
continue
# 符合筛选条件,更新勾选状态
self.configs[config_index]['勾选'] = is_checked
visible_count += 1
else:
self._show_infobar("success", "提示", "已取消全选")
# 无筛选条件:操作所有数据(跨页)
for config_index in range(len(self.configs)):
self.configs[config_index]['勾选'] = is_checked
visible_count += 1
# 刷新表格显示
self.update_table()
self._update_checked_count()
# 更新状态统计
self._update_status_statistics()
if is_checked:
self._show_infobar("success", "提示", f"已勾选 {visible_count} 行(跨页操作)")
else:
self._show_infobar("success", "提示", f"已取消 {visible_count} 行勾选(跨页操作)")
def _create_centered_item(self, text):
"""创建居中对齐的表格单元格"""
@@ -1549,7 +1632,7 @@ class MainWindow(QMainWindow):
return item
def _set_status_item(self, row, text):
"""设置状态列图标与文本"""
"""设置状态列文本"""
try:
# 使用 blockSignals 临时阻止信号,防止递归
self.config_table.blockSignals(True)
@@ -1557,16 +1640,14 @@ class MainWindow(QMainWindow):
item = QTableWidgetItem(text)
item.setTextAlignment(Qt.AlignCenter) # 居中对齐
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
# 根据状态设置文字颜色
if "完成" in text or "成功" in text:
item.setIcon(self.style().standardIcon(QStyle.SP_DialogApplyButton))
item.setForeground(QColor("#155724")) # 绿色
elif "失败" in text or "错误" in text:
item.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxCritical))
item.setForeground(QColor("#721C24")) # 红色
elif "执行中" in text or "进行" in text:
item.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
elif "" in text:
item.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation))
else:
item.setIcon(self.style().standardIcon(QStyle.SP_FileDialogInfoView))
item.setForeground(QColor("#0C5460")) # 蓝色
self._apply_current_highlight_to_item(row, 8, item, text)
self.config_table.setItem(row, 8, item)
finally:
# 恢复信号
@@ -2181,27 +2262,32 @@ class MainWindow(QMainWindow):
match = False
for col in range(self.config_table.columnCount()):
if column_index >= 0 and col != column_index:
try:
item = self.config_table.item(row, col)
if item:
item.setBackground(self._default_color())
except RuntimeError:
pass
continue
try:
item = self.config_table.item(row, col)
if item:
item.setBackground(self._default_color())
continue
item = self.config_table.item(row, col)
if item:
cell_text = item.text()
cell_compare = cell_text.lower()
if keyword:
terms = [t.lower() for t in terms_raw]
term_hit = all(term in cell_compare for term in terms)
if term_hit:
match = True
if self.table_highlight.isChecked():
item.setBackground(self._highlight_color())
match_count += 1
cell_text = item.text()
cell_compare = cell_text.lower()
if keyword:
terms = [t.lower() for t in terms_raw]
term_hit = all(term in cell_compare for term in terms)
if term_hit:
match = True
if self.table_highlight.isChecked():
item.setBackground(self._highlight_color())
match_count += 1
else:
item.setBackground(self._default_color())
else:
item.setBackground(self._default_color())
else:
item.setBackground(self._default_color())
else:
except RuntimeError:
# item 已被删除,跳过
continue
only_match = self.table_only_match.isChecked() if hasattr(self, 'table_only_match') else False
self.config_table.setRowHidden(row, (not match) if (keyword and only_match) else False)
@@ -2413,24 +2499,17 @@ class MainWindow(QMainWindow):
# 使用 blockSignals 临时阻止信号,防止递归
self.config_table.blockSignals(True)
try:
# 第8列是"情况"列,颜色与图标与 _set_status_item 一致
# 第8列是"情况"列,只设置文字颜色,不设置背景色和图标
status_item = QTableWidgetItem(status)
status_item.setTextAlignment(Qt.AlignCenter)
status_item.setFlags(status_item.flags() & ~Qt.ItemIsEditable)
if status == "已完成":
status_item.setBackground(QColor("#D4EDDA"))
status_item.setForeground(QColor("#155724"))
status_item.setIcon(self.style().standardIcon(QStyle.SP_DialogApplyButton))
status_item.setForeground(QColor("#155724")) # 绿色
elif status == "失败":
status_item.setBackground(QColor("#F8D7DA"))
status_item.setForeground(QColor("#721C24"))
status_item.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxCritical))
status_item.setForeground(QColor("#721C24")) # 红色
elif status == "执行中":
status_item.setBackground(QColor("#D1ECF1"))
status_item.setForeground(QColor("#0C5460"))
status_item.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
else:
status_item.setIcon(self.style().standardIcon(QStyle.SP_FileDialogInfoView))
status_item.setForeground(QColor("#0C5460")) # 蓝色
self._apply_current_highlight_to_item(row_idx, 8, status_item, status)
self.config_table.setItem(row_idx, 8, status_item)
finally:
self.config_table.blockSignals(False)
@@ -2440,13 +2519,35 @@ class MainWindow(QMainWindow):
def _highlight_color(self):
"""高亮颜色"""
return self.config_table.palette().color(self.config_table.palette().Highlight).lighter(160)
"""高亮颜色 - 淡蓝色背景"""
return QColor(173, 216, 230) # 淡蓝色 (Light Blue)
def _default_color(self):
"""默认背景色"""
return self.config_table.palette().color(self.config_table.palette().Base)
def _apply_current_highlight_to_item(self, row, col, item, text=None):
"""根据当前筛选条件对单元格应用高亮"""
if not item or not hasattr(self, "table_search_input"):
return
if not self.table_highlight.isChecked():
return
keyword_raw = self.table_search_input.text().strip()
if not keyword_raw:
return
column_index = self._filter_column_index()
if column_index >= 0 and col != column_index:
return
terms = [t.lower() for t in keyword_raw.split() if t]
if not terms:
return
cell_text = text if text is not None else item.text()
cell_compare = (cell_text or "").lower()
if all(term in cell_compare for term in terms):
item.setBackground(self._highlight_color())
else:
item.setBackground(self._default_color())
def _filter_column_index(self):
"""筛选项下拉对应的表格列索引;-1 表示全部列。排除情况列以多多ID等为筛选项。"""
i = self.table_column_filter.currentIndex()
@@ -3139,7 +3240,7 @@ class MainWindow(QMainWindow):
status_value = '待执行'
config = {
'勾选': True, # 默认勾选,方便导入后直接操作
'勾选': False, # 导入后默认勾选,交由用户选择
'多多id': clean_str(row.get('多多id', '')),
'序号': clean_str(row.get('序号', '')),
'话题': str(row.get('话题', '')).strip() if pd.notna(row.get('话题')) else '',
@@ -3171,6 +3272,12 @@ class MainWindow(QMainWindow):
logger.error(f"更新表格失败: {e}")
return
# 导入后默认不勾选,确保全选状态为未选中
if hasattr(self, "table_select_all_checkbox"):
self.table_select_all_checkbox.blockSignals(True)
self.table_select_all_checkbox.setChecked(False)
self.table_select_all_checkbox.blockSignals(False)
# 显示表格
self.table_group.setVisible(True)
# 更新状态统计(基于新导入的配置重新计算)
@@ -3754,6 +3861,12 @@ class MainWindow(QMainWindow):
self._show_infobar("warning", "提示", "所选项已完成或数据不完整")
return
# 重置所有要处理的配置状态为"待执行"(确保第二次运行时清除旧状态)
for item in configs_to_process:
idx = item["config_index"]
self.configs[idx]['情况'] = '待执行'
self._update_table_status(idx, "待执行", is_config_index=True)
# 应用定时发布 + 间隔时间逻辑(跨分页全局应用)
self._apply_schedule_intervals(configs_to_process)