fix: update setting board in message turnnel page

This commit is contained in:
weaselkkk committed 2026-05-21 14:32:49 +08:00
1 parent 3fcf12e707
commit 7ce4778903
4 files changed
+124 -10

No files matched your search

+45 -3
View File
@@ -155,6 +155,8 @@ const gaServiceStore = {
return http(`/services/logs?id=${encodeURIComponent(id)}&tail=${encodeURIComponent(tail)}`);
}
case 'services/panel': return http('/services/panel');
case 'services/mykey/get': return http('/services/mykey');
case 'services/mykey/save': return http('/services/mykey', { method: 'POST', body: params || {} });
case 'app/path/selectGaRoot': return http('/config');
case 'list_continuable_sessions': return { sessions: [] };
case 'restore_session': throw new Error('restore_session is not implemented in web2 bridge');
@@ -194,6 +196,8 @@ const gaServiceStore = {
stopService,
getServiceLogs: (id, tail = 200) => rpc('services/logs', { id, tail }),
getServicePanel: () => rpc('services/panel', {}),
getMykeyContent: () => rpc('services/mykey/get', {}),
saveMykeyContent: (content) => rpc('services/mykey/save', { content }),
pollSession: (sessionId, afterId = 0) => rpc('session/poll', { sessionId, afterId }),
rpc,
onBridgeMessage: (cb) => on('bridge-message', cb),
@@ -254,6 +258,8 @@ const I18N = {
'err.channelNotConfigured': '请先在 mykey.py 中配置该平台',
'sys.channelStarted': '已启动', 'sys.channelStopped': '已停止',
'modal.channelLogs': '进程日志',
'modal.mykeyConfig': 'mykey.py 配置',
'sys.configSaved': '配置已保存',
'st.starting': '启动中…', 'st.stopping': '停止中…',
'st.online': '在线', 'st.offline': '离线', 'st.error': '错误', 'st.running': '运行', 'st.abnormal': '异常',
'act.configure': '配置', 'act.logs': '日志', 'act.restart': '重启', 'act.stop': '停止', 'act.start': '启动',
@@ -310,6 +316,8 @@ const I18N = {
'err.channelNotConfigured': 'Configure this platform in mykey.py first',
'sys.channelStarted': 'Started', 'sys.channelStopped': 'Stopped',
'modal.channelLogs': 'Process logs',
'modal.mykeyConfig': 'mykey.py',
'sys.configSaved': 'Configuration saved',
'st.starting': 'Starting…', 'st.stopping': 'Stopping…',
'st.online': 'Online', 'st.offline': 'Offline', 'st.error': 'Error', 'st.running': 'Running', 'st.abnormal': 'Error',
'act.configure': 'Configure', 'act.logs': 'Logs', 'act.restart': 'Restart', 'act.stop': 'Stop', 'act.start': 'Start',
@@ -960,6 +968,10 @@ const chanEmptyEl = document.getElementById('chan-empty');
const chanLogModal = document.getElementById('chan-log-modal');
const chanLogPre = document.getElementById('chan-log-pre');
const chanLogTitle = document.getElementById('chan-log-title');
const chanConfigModal = document.getElementById('chan-config-modal');
const chanConfigTitle = document.getElementById('chan-config-title');
const chanConfigEditor = document.getElementById('chan-config-editor');
const chanConfigSave = document.getElementById('chan-config-save');
let _chanLogId = null;
let _chanBusy = false;
let _chanToastTimer = null;
@@ -1103,13 +1115,43 @@ async function openChannelLogs(id) {
chanLogPre.textContent = t('err.channelLoad') + ': ' + (e.message || e);
}
}
async function openChannelMykey() {
async function openChannelMykey(channelId) {
if (!chanConfigModal || !chanConfigEditor) return;
const ch = gaServiceStore.get(channelId) || { id: channelId };
if (chanConfigTitle) {
chanConfigTitle.textContent = t('modal.mykeyConfig') + (channelId ? ' · ' + channelDisplayName(ch) : '');
}
chanConfigEditor.value = t('ch.loading');
chanConfigEditor.disabled = true;
if (chanConfigSave) chanConfigSave.disabled = true;
openModal('chan-config-modal');
try {
await window.ga.openMykey();
const res = await window.ga.getMykeyContent();
chanConfigEditor.value = res.content || '';
} catch (e) {
chanConfigEditor.value = t('err.channelLoad') + ': ' + (e.message || e);
} finally {
chanConfigEditor.disabled = false;
if (chanConfigSave) chanConfigSave.disabled = false;
chanConfigEditor.focus();
}
}
async function saveChannelMykey() {
if (!chanConfigEditor || !chanConfigSave) return;
chanConfigSave.disabled = true;
try {
await window.ga.saveMykeyContent(chanConfigEditor.value);
showChanToast(t('sys.configSaved'), '', 'ok');
chanConfigModal.hidden = true;
} catch (e) {
showChanToast(t('err.channelLoad'), e.message || String(e), 'err');
} finally {
chanConfigSave.disabled = false;
}
}
if (chanConfigSave) {
chanConfigSave.addEventListener('click', saveChannelMykey);
}
/* ═══════════════ 状态面板(复用 ServiceManager + 启停/日志) ═══════════════ */
const statusListEl = document.getElementById('status-list');
@@ -1228,7 +1270,7 @@ if (chanListEl) {
return;
}
if (act === 'configure') {
openChannelMykey();
openChannelMykey(id);
return;
}
if (act === 'toggle') {
+23 -4
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<title>GenericAgent</title>
<link rel="stylesheet" href="styles.css?v=4">
<link rel="stylesheet" href="styles.css?v=5">
<!-- DEV 脚手架(标注模式):删本行 + 下方 annot.js 一行即可彻底移除 -->
<link rel="stylesheet" href="annot.css">
</head>
@@ -297,19 +297,38 @@
<!-- 渠道日志 弹窗 -->
<div class="modal" id="chan-log-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card modal-card-wide" role="dialog">
<div class="modal-card modal-card-wide modal-card-inset" role="dialog">
<div class="modal-head">
<div class="modal-title" id="chan-log-title" data-i18n="modal.channelLogs"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
</button>
</div>
<div class="modal-body">
<div class="modal-body modal-body-inset">
<pre class="chan-log-pre" id="chan-log-pre"></pre>
</div>
</div>
</div>
<!-- mykey 配置 弹窗 -->
<div class="modal" id="chan-config-modal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card modal-card-wide modal-card-inset" role="dialog">
<div class="modal-head">
<div class="modal-title" id="chan-config-title" data-i18n="modal.mykeyConfig"></div>
<button class="modal-x" data-close data-i18n-title="common.close" title="">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
</button>
</div>
<div class="modal-body modal-body-inset chan-config-body">
<textarea id="chan-config-editor" class="mykey-editor" spellcheck="false"></textarea>
<div class="chan-config-foot">
<button type="button" class="chan-config-save" id="chan-config-save" data-i18n="common.save"></button>
</div>
</div>
</div>
</div>
<!-- 配置 弹窗 -->
<div class="modal" id="settings-modal" hidden>
<div class="modal-backdrop" data-close></div>
@@ -353,7 +372,7 @@
<div id="toast-root" class="toast-root" aria-live="polite"></div>
<script src="vendor/marked.min.js"></script>
<script src="app.js?v=6"></script>
<script src="app.js?v=7"></script>
<script src="annot.js"></script><!-- DEV 脚手架,可删 -->
</body>
</html>
+26 -3
View File
@@ -344,12 +344,35 @@ body{ background:var(--bg); color:var(--txt); font-size:13px; overflow:hidden; }
.toast-detail{ font-size:12px; opacity:.88; display:block; word-break:break-word; }
.chan-log-pre{
max-height:360px; overflow:auto; margin:0;
font-family:ui-monospace,Consolas,monospace; font-size:12px;
color:var(--txt-2); background:var(--field-bg);
font-family:inherit; font-size:13px; line-height:1.5;
color:var(--txt-2); background:#ffffff;
border:1px solid var(--line); border-radius:var(--radius-sm);
padding:12px; white-space:pre-wrap; word-break:break-word;
padding:14px 16px; white-space:pre-wrap; word-break:break-word;
}
.modal-card-wide{ width:min(720px,92vw); }
.modal-card-inset{ width:min(680px,calc(92vw - 48px)); }
.modal-body-inset{ padding:0 18px 18px; min-height:0; }
.chan-config-body{
display:flex; flex-direction:column; gap:8px;
}
.mykey-editor{
flex:1; min-height:420px; width:100%;
padding:0; margin:0;
font-family:inherit; font-size:13px; line-height:1.5;
color:var(--txt); background:#ffffff;
border:none; border-radius:0; resize:vertical; outline:none;
}
.mykey-editor:focus{ outline:none; }
.chan-config-foot{
display:flex; justify-content:flex-end;
}
.chan-config-save{
border:1px solid var(--line); background:var(--card); color:var(--txt-2);
border-radius:6px; padding:5px 12px; font-size:12px; font-weight:600;
font-family:inherit; cursor:pointer;
}
.chan-config-save:hover{ background:var(--hover-2); }
.chan-config-save:disabled{ opacity:.45; cursor:not-allowed; }
.chan-meta{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.chan-meta .chan-name{ font-size:14px; }
.chan-meta .chan-path{ font-size:11px; color:var(--muted); }
+30
View File
@@ -23,6 +23,8 @@ HTTP API:
POST /services/stop body: {"id":"frontends/qqapp.py"}
GET /services/logs?id=frontends/qqapp.py&tail=200
GET /services/panel
GET /services/mykey
POST /services/mykey body: {"content":"..."}
WS API (state sync):
GET /ws -> on connect sends services.snapshot; service.changed on updates
@@ -856,6 +858,32 @@ def _open_path_in_editor(target: Path) -> None:
subprocess.Popen(["xdg-open", path])
def _mykey_file() -> Path:
root = Path(manager.ga_root)
target = root / "mykey.py"
if not target.is_file():
template = root / "mykey_template.py"
if template.is_file():
target.write_text(template.read_text(encoding="utf-8"), encoding="utf-8")
return target
async def mykey_get_handler(request):
target = _mykey_file()
content = target.read_text(encoding="utf-8") if target.is_file() else ""
return json_ok({"content": content, "path": str(target)})
async def mykey_save_handler(request):
data = await read_json(request)
content = data.get("content")
if content is None:
return json_ok({"ok": False, "error": "missing_content"}, status=400)
target = _mykey_file()
target.write_text(str(content), encoding="utf-8")
return json_ok({"ok": True, "path": str(target)})
async def service_start_handler(request):
body = await read_json(request)
sid = body.get("id") or request.query.get("id")
@@ -928,6 +956,8 @@ def create_app():
app.router.add_post("/services/stop", service_stop_handler)
app.router.add_get("/services/logs", service_logs_handler)
app.router.add_get("/services/panel", service_panel_handler)
app.router.add_get("/services/mykey", mykey_get_handler)
app.router.add_post("/services/mykey", mykey_save_handler)
# Serve static frontend (desktop/static/)
static_dir = APP_DIR / "desktop" / "static"