Files
kefu/deploy/review-visibility-20260916/fix_qt_review.py
T
2026-09-21 10:34:06 +08:00

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)