119 lines
7.7 KiB
Python
119 lines
7.7 KiB
Python
"""Apply backed-up Qt bridge fixes; leave real pending queues untouched."""
|
|
import ast
|
|
from pathlib import Path
|
|
import shutil
|
|
import os
|
|
|
|
base = Path(__file__).parent
|
|
def replace_method(source, class_name, method_name, replacement):
|
|
tree = ast.parse(source)
|
|
cls = next(n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == class_name)
|
|
node = next(n for n in cls.body if isinstance(n, ast.FunctionDef) and n.name == method_name)
|
|
lines = source.splitlines(keepends=True)
|
|
return ''.join(lines[:node.lineno-1]) + replacement.rstrip() + '\n' + ''.join(lines[node.end_lineno:])
|
|
|
|
FILTER=''' def _apply_task_filter(self) -> None:
|
|
if not hasattr(self, "task_list"):
|
|
return
|
|
mode = getattr(self, "active_task_filter", "全部")
|
|
for row in range(self.task_list.count()):
|
|
item = self.task_list.item(row)
|
|
display = self._display_task_status(str(item.data(Qt.UserRole + 1) or ""))
|
|
item.setHidden(mode != "全部" and display != mode)
|
|
current = self.task_list.currentRow()
|
|
selected = self.task_list.item(current) if current >= 0 else None
|
|
if selected is None or selected.isHidden():
|
|
visible = next((row for row in range(self.task_list.count()) if not self.task_list.item(row).isHidden()), -1)
|
|
self.task_list.setCurrentRow(visible)
|
|
if visible >= 0:
|
|
self._select_visible_task(visible)
|
|
'''
|
|
DISPLAY=''' def _display_task_status(state: str) -> str:
|
|
if "审核" in state:
|
|
return "待审核"
|
|
if "人工" in state or "待核对" in state or "处理失败" in state:
|
|
return "需人工"
|
|
if state.startswith("正在"):
|
|
return "处理中"
|
|
if "重试" in state:
|
|
return "待重试"
|
|
return "等待中"
|
|
'''
|
|
STATE=''' def _state_text(state: dict) -> str:
|
|
review = task_review_state(state)
|
|
send_state = str(state.get("send_state") or "")
|
|
if send_state == "sending":
|
|
return "正在发送"
|
|
if review["deliveryUncertain"]:
|
|
return "发送待核对(需人工)"
|
|
if send_state == "sent_uncommitted":
|
|
return "已发送,待归档"
|
|
if review["needsHuman"]:
|
|
return "需要人工处理"
|
|
if review["awaitingReview"]:
|
|
return "等待人工审核"
|
|
stage = str(state.get("stage") or "")
|
|
if stage in QueuePage.STAGE_LABELS:
|
|
return QueuePage.STAGE_LABELS[stage]
|
|
if state.get("batch_ready"):
|
|
return "正在生成回复"
|
|
if state.get("confirmed_unread"):
|
|
return "等待处理"
|
|
return "排队中"
|
|
'''
|
|
|
|
for root in (Path('C:/kefu/wechat_rpa'),Path('C:/wechat_rpa')):
|
|
path=root/'wechat_gui_qt.py'
|
|
source=path.read_text(encoding='utf-8')
|
|
backup=root/'backups/review-visibility-20260916/qt'
|
|
backup.mkdir(parents=True,exist_ok=True)
|
|
if (backup/path.name).exists():
|
|
assert path.read_bytes() == (backup/path.name).read_bytes(), 'Source changed since backup'
|
|
else:
|
|
shutil.copy2(path,backup/path.name)
|
|
shutil.copy2(base/'review_state.py',root/'review_state.py')
|
|
source=source.replace('import json\n','import json\nfrom review_state import task_review_state\n',1)
|
|
source=source.replace('"manual_review": "等待人工审核",','"manual_review": "等待人工审核",\n "awaiting_review": "等待人工审核",',1)
|
|
source=replace_method(source,'QueuePage','_display_task_status',DISPLAY)
|
|
source=replace_method(source,'QueuePage','_state_text',STATE)
|
|
source=replace_method(source,'QueuePage','_apply_task_filter',FILTER)
|
|
source=source.replace('("全部", "处理中", "等待中", "待重试")','("全部", "待审核", "需人工", "处理中", "等待中", "待重试")')
|
|
source=source.replace('self.host.queue_page._set_task_filter(name or "全部")\n self.host._push_console_state()',
|
|
'self.host.queue_page._set_task_filter(name if name in {"全部", "待审核", "需人工", "处理中", "等待中", "待重试"} else "全部")\n self.host._console_selected_key = ""\n self.host._push_console_state(force=True)',1)
|
|
# Actual raw state, not a localized label, controls allowed buttons.
|
|
needle='"awaitingReview": bool(state.get("awaiting_review", False)),'
|
|
assert needle in source
|
|
source=source.replace(needle,'**task_review_state(state),\n "isProtocol": bool(state.get("detected_by") == "protocol_db" or state.get("conv_id")),',1)
|
|
source=source.replace('"reviewReason": str(state.get("review_reason") or ""),','"reviewReason": task_review_state(state)["reviewReason"],',1)
|
|
source=source.replace('state.get("staged_user_text") or table_message or ""','state.get("staged_user_text") or state.get("chat_text") or table_message or ""',1)
|
|
# Counts must include hidden rows, otherwise selecting another filter hides the alert.
|
|
needle=' processing = sum(1 for item in people if item.get("status") == "处理中")'
|
|
assert needle in source
|
|
source=source.replace(needle,' review_states = [task_review_state(value) for value in (getattr(self.queue_page, "pending_states", {}) or {}).values()]\n'+needle,1)
|
|
source=source.replace('"processing": str(processing),','"processing": str(processing),\n "review": str(sum(value["awaitingReview"] and not value["needsHuman"] for value in review_states)),\n "human": str(sum(value["needsHuman"] for value in review_states)),',1)
|
|
# Immediately re-read persisted state after approval rather than showing stale controls.
|
|
start=source.index(' def _approve_queue_tasks(')
|
|
end=source.index(' def _retry_queue_tasks(',start)
|
|
part=source[start:end]
|
|
part=part.replace(' self._schedule_console_push(urgent=True)',' self.queue_page.refresh_data()\n self._schedule_console_push(urgent=True)')
|
|
part=part.replace(' error = str(result.get("error") or "")',' if result.get("protected"):\n QMessageBox.information(self, "任务受保护", "当前账号不匹配或任务正在发送/核对回执,不能批准重发。请先核对后转人工处理。")\n error = str(result.get("error") or "")',1)
|
|
# Protocol startup may be async. Explicit approval is queued until startup succeeds.
|
|
needle=''' if thread is None or not thread.is_alive():
|
|
QMessageBox.warning('''
|
|
if 'if transport == PROTOCOL:' in source:
|
|
part=part.replace(needle,''' if (thread is None or not thread.is_alive()) and getattr(self, "_protocol_start_pending", False):
|
|
self._deferred_review_approvals = sorted(set(getattr(self, "_deferred_review_approvals", [])) | set(requested))
|
|
self.append_log("已登记审核操作,协议环境检查通过后将核对会话并继续。", "notify")
|
|
return
|
|
'''+needle,1)
|
|
source=source.replace(' self._thread.start()\n', ' self._thread.start()\n deferred = list(getattr(self, "_deferred_review_approvals", []))\n self._deferred_review_approvals = []\n if deferred:\n QTimer.singleShot(0, lambda keys=deferred: self._approve_queue_tasks(keys))\n',1)
|
|
source=source.replace(' def stop_monitoring(self) -> None:\n',' def stop_monitoring(self) -> None:\n self._deferred_review_approvals = []\n',1)
|
|
# Re-find after the prior source insertion.
|
|
start=source.index(' def _approve_queue_tasks(');end=source.index(' def _retry_queue_tasks(',start)
|
|
source=source[:start]+part+source[end:]
|
|
compile(source,str(path),'exec')
|
|
temporary = path.with_name(path.name + '.review-patch.tmp')
|
|
temporary.write_text(source,encoding='utf-8')
|
|
os.replace(temporary,path)
|
|
print(root)
|