Add render_window.js: Python-driven incremental pagination with id+chainIndex state, anchor restore, batch guard and streaming auto-detect; wired through chat_bridge and the page shell.
86 lines
3.7 KiB
HTML
86 lines
3.7 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
||
<!-- Markdown 库 -->
|
||
<script src="marked.min.js"></script>
|
||
|
||
<!-- 代码高亮 -->
|
||
<link rel="stylesheet" href="highlight/atom-one-dark.min.css">
|
||
<script src="highlight/highlight.min.js"></script>
|
||
|
||
<!-- 🌟 HTML 消毒(防 XSS / 防 HTML 穿透的纵深防御) -->
|
||
<script src="dompurify.min.js"></script>
|
||
|
||
<!-- 🌟 KaTeX 公式渲染(本地离线资产;须在 app.js 之前) -->
|
||
<link rel="stylesheet" href="katex/katex.min.css">
|
||
<script src="katex/katex.min.js"></script>
|
||
|
||
<!-- 自定义样式 -->
|
||
<link rel="stylesheet" href="style.css">
|
||
|
||
<!-- 🌟 Qt WebChannel 支持(用于前端与 Python 通信) -->
|
||
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||
</head>
|
||
<body>
|
||
<!--🌟 会话加载界面(进入新会话时的统一加载:居中图标 + 从左到右扫描条) -->
|
||
<div class="session-loading" id="session-loading" style="display:none;">
|
||
<div class="session-loading-box">
|
||
<img class="session-loading-icon" src="../../svg/main.svg" alt="haocode">
|
||
<div class="session-loading-bar">
|
||
<div class="session-loading-bar-fill"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!--🌟 欢迎界面 -->
|
||
<div class="welcome-screen">
|
||
<div class="welcome-content">
|
||
<img class="welcome-icon" src="../../svg/main.svg" alt="haocode">
|
||
<h1 class="brand-name">haocode</h1>
|
||
<p class="brand-tagline">探索未至之境</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 聊天容器(🆕 P1-01:顶部/底部加载入口由 app.js 按需插入 chat-container 首/尾) -->
|
||
<div id="chat-container"></div>
|
||
|
||
<div id="scroll-anchor" style="height: 1px; margin-bottom: 150px;"></div>
|
||
|
||
<!-- 🌟 桥接初始化脚本(必须在 app.js 之前执行)
|
||
双协议:WebView2(window.chrome.webview.postMessage)/ QtWebEngine(QWebChannel) -->
|
||
<script>
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
if (window.chrome && window.chrome.webview) {
|
||
// ---- WebView2 路径:JSON 消息协议,方法名与 QWebChannel slot 一一对应 ----
|
||
const post = (m, a) => {
|
||
try { window.chrome.webview.postMessage({ m: m, a: a }); } catch (e) { console.warn("[JS] postMessage 失败:", e); }
|
||
};
|
||
window.bridge = {
|
||
onRegenerateClicked: (x) => post("onRegenerateClicked", [x]),
|
||
onBranchSwitch: (x, d) => post("onBranchSwitch", [x, d]),
|
||
onDeleteMessageClicked: (x) => post("onDeleteMessageClicked", [x]),
|
||
onAttachmentClicked: (x) => post("onAttachmentClicked", [x]),
|
||
onScrollChanged: (y, h, c) => post("onScrollChanged", [y, h, c]),
|
||
onRequestWindowPage: (s, d, b, g) => post("onRequestWindowPage", [s, d, b, g])
|
||
};
|
||
console.log("[JS] WebView2 桥接就绪,window.bridge 可用");
|
||
} else {
|
||
// ---- QtWebEngine 路径:原有 QWebChannel ----
|
||
new QWebChannel(qt.webChannelTransport, function (channel) {
|
||
window.bridge = channel.objects.bridge;
|
||
console.log("[JS] QWebChannel 已连接,window.bridge 就绪");
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<!-- 🌟 主逻辑脚本 -->
|
||
<!-- 🆕 P1-01 渲染窗口状态机(DOM 无关;须在 app.js 之前) -->
|
||
<script src="render_window.js"></script>
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|