Files
kefu/deploy/loading-performance-20260917/frontend_patch.py
T
2026-09-21 10:34:06 +08:00

103 lines
6.4 KiB
Python

from pathlib import Path
import hashlib,json,shutil,re
ROOTS=[Path('C:/wechat_rpa'),Path('C:/kefu/wechat_rpa')]
HELPERS='''const loadingActionLocks = new Set();
const recentDbSelections = new Map();
function isLoadingActionPending(method){ return loadingActionLocks.has(method); }
function callLoadingAction(method, action, label){
const serverBusy = method === "refreshWeChatDatabase" ? (STATE.wechatDb || {}).loading
: (((STATE.automation || {}).protocol || {}).status === "checking");
if (serverBusy || loadingActionLocks.has(method)) return;
loadingActionLocks.add(method);
const selector = `[data-action="${action}"]`;
const button = document.querySelector(selector);
if (button){ button.disabled = true; button.innerHTML = icon("refresh") + label; }
if (!callBridge(method)) {
loadingActionLocks.delete(method);
if (button) button.disabled = false;
toast("界面尚未连接后台,请稍后重试。");
if (STATE.view) render(STATE.view);
return;
}
// Qt owns long-running work. This short local lock covers the bridge round trip.
setTimeout(()=>{
loadingActionLocks.delete(method);
const current = document.querySelector(selector);
const busy = method === "refreshWeChatDatabase" ? (STATE.wechatDb || {}).loading
: (((STATE.automation || {}).protocol || {}).status === "checking");
if (current && !busy){
current.disabled = false;
current.innerHTML = icon("refresh") + (method === "refreshWeChatDatabase" ? "刷新消息库" : "检测本机协议");
}
}, 800);
}
function selectDbItem(method, key, selected){
const last = recentDbSelections.get(method);
const recent = last && performance.now() - last.at < 800;
if ((recent && last.key === key) || (!recent && String(selected || "") === key)) return;
recentDbSelections.set(method, {key, at:performance.now()});
callBridge(method, key);
}
'''
def once(s,old,new):
assert s.count(old)==1,(old[:100],s.count(old))
return s.replace(old,new,1)
manifest=[]
for root in ROOTS:
backup=root/'backups/loading-performance-20260917/frontend'
for rel in ['assets/ui/console-app.js','assets/ui/zhenyang-ai-console.html']:
src=root/rel;dst=backup/rel
assert not dst.exists(),dst
dst.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(src,dst)
js=root/'assets/ui/console-app.js';s=js.read_text(encoding='utf-8')
s=once(s,'const _queueList = queueList;',HELPERS+'const _queueList = queueList;')
s=once(s,'"wechat-db-refresh": () => callBridge("refreshWeChatDatabase") || toast("正在刷新消息库"),','"wechat-db-refresh": () => callLoadingAction("refreshWeChatDatabase", "wechat-db-refresh", "正在读取…"),')
s=once(s,'"wechat-db-account": () => callBridge("selectWeChatAccount", key),','"wechat-db-account": () => selectDbItem("selectWeChatAccount", key, (STATE.wechatDb || {}).selectedAccount),')
s=once(s,'"wechat-db-conversation": () => callBridge("selectWeChatConversation", key),','"wechat-db-conversation": () => selectDbItem("selectWeChatConversation", key, (STATE.wechatDb || {}).selectedConversation),')
s=once(s,'data-action="wechat-db-refresh" ${db.loading ? "disabled" : ""}','data-action="wechat-db-refresh" ${db.loading || isLoadingActionPending("refreshWeChatDatabase") ? "disabled" : ""}')
s=once(s,'const patientControl = !currentConversation ? "" : !canSearchPatient','const patientControl = !currentConversation ? "" : patientContext.loading\n ? `<span class="badge" data-patient-loading="1">${icon("refresh")} 患者关联加载中</span>`\n : !canSearchPatient')
if root==ROOTS[0]:
s=once(s,'const checking = p.status === "checking";', 'const checking = p.status === "checking" || isLoadingActionPending("probeProtocol");')
s=once(s,'"probe-protocol": () => callBridge("probeProtocol"),','"probe-protocol": () => callLoadingAction("probeProtocol", "probe-protocol", "检测中…"),')
else:
s=once(s,'let searchTimer = 0;', '''let searchTimer = 0;
let dbSearchComposing = false;
document.addEventListener("compositionstart", event=>{
if (event.target && event.target.id === "wechat-db-search") {
dbSearchComposing = true;
clearTimeout(searchTimer);
}
});
document.addEventListener("compositionend", event=>{
if (event.target && event.target.id === "wechat-db-search") {
dbSearchComposing = false;
event.target.dispatchEvent(new Event("input", {bubbles:true}));
}
});''')
s=once(s,' const value = e.target.value || "";\n if (["ai-name"', ' const value = e.target.value || "";\n if (id === "wechat-db-search" && (e.isComposing || dbSearchComposing)) { clearTimeout(searchTimer); return; }\n if (["ai-name"')
s=once(s,' const sameView = STATE.view === name;\n STATE.view = name;', ''' const sameView = STATE.view === name;
const active = document.activeElement;
const keepSearch = sameView && active && active.id === "wechat-db-search"
? {element:active, start:active.selectionStart, end:active.selectionEnd} : null;
STATE.view = name;''')
s=once(s,' main.innerHTML = html;\n normalizeReferenceView();', ''' main.innerHTML = html;
if (keepSearch){
const placeholder=document.getElementById("wechat-db-search");
if (placeholder){
placeholder.replaceWith(keepSearch.element);
keepSearch.element.focus({preventScroll:true});
if (keepSearch.start != null) keepSearch.element.setSelectionRange(keepSearch.start,keepSearch.end);
}
}
normalizeReferenceView();''')
s=once(s,' const prev = STATE.view;\n Object.assign(STATE, data);', ' const prev = STATE.view;\n Object.assign(STATE, data);')
s=once(s,' if (typing && (STATE.view || prev) === prev && ["ai"', ' if (dbSearchComposing && prev === "wechatdb" && (STATE.view || prev) === prev) return;\n if (typing && (STATE.view || prev) === prev && ["ai"')
js.write_text(s,encoding='utf-8',newline='\n')
html=root/'assets/ui/zhenyang-ai-console.html';s=html.read_text(encoding='utf-8')
s,n=re.subn(r'console-app\.js\?v=[^"\s]+','console-app.js?v=loading1',s);assert n==1
html.write_text(s,encoding='utf-8',newline='\n')
manifest.append({'root':str(root),'files':[{'path':rel,'sha256':hashlib.sha256((root/rel).read_bytes()).hexdigest()} for rel in ['assets/ui/console-app.js','assets/ui/zhenyang-ai-console.html']]})
Path('C:/kefu/deploy/loading-performance-20260917/frontend-files.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
print('Saved JS-only loading improvements and HTML cache keys in both directories.')