qq-bot-roost 0.8.2 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/markdown.js +65 -0
- package/src/message.js +35 -5
- package/src/plugin/context.js +171 -1
- package/src/plugin/subprocess.js +10 -0
- package/src/plugin/testkit.js +46 -3
- package/src/plugin/tools.js +101 -0
- package/src/qq/qrlogin.js +151 -0
- package/src/qq/qrsvg.js +39 -0
- package/src/web/server.js +76 -0
- package/src/webhook.js +21 -1
- package/web/app.js +92 -0
- package/web/index.html +815 -801
- package/web/style.css +53 -0
- package/web/vendor/qrcode.js +2302 -0
package/web/index.html
CHANGED
|
@@ -1,801 +1,815 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>栖 Roost · 控制台</title>
|
|
7
|
-
<script>
|
|
8
|
-
// 在样式加载前定好主题,避免刷新时闪一下白
|
|
9
|
-
(function () {
|
|
10
|
-
try {
|
|
11
|
-
var t = localStorage.getItem('qqbot_theme');
|
|
12
|
-
if (!t) t = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
13
|
-
document.documentElement.dataset.theme = t;
|
|
14
|
-
} catch (e) {}
|
|
15
|
-
})();
|
|
16
|
-
</script>
|
|
17
|
-
<link rel="stylesheet" href="/style.css">
|
|
18
|
-
</head>
|
|
19
|
-
<body>
|
|
20
|
-
|
|
21
|
-
<header class="topbar">
|
|
22
|
-
<div class="brand" title="栖 Roost · 倦飞之鸟,终有一栖">
|
|
23
|
-
<span class="logo" aria-hidden="true">栖</span>
|
|
24
|
-
<div>
|
|
25
|
-
<div class="title">栖<span class="brand-en">Roost</span></div>
|
|
26
|
-
<div class="sub" id="botName">未连接</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
<div class="bot-switch" id="botSwitch">
|
|
30
|
-
<button class="bot-trigger" id="botTrigger" aria-haspopup="listbox" aria-expanded="false">
|
|
31
|
-
<span class="bot-dot" id="botDot"></span>
|
|
32
|
-
<span class="bot-name" id="botNameLabel">加载中…</span>
|
|
33
|
-
<svg class="bot-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
34
|
-
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
35
|
-
<path d="M6 9l6 6 6-6"/>
|
|
36
|
-
</svg>
|
|
37
|
-
</button>
|
|
38
|
-
<div class="bot-menu" id="botMenu" hidden role="listbox">
|
|
39
|
-
<input class="bot-search" id="botSearch" placeholder="搜索机器人" hidden>
|
|
40
|
-
<div class="bot-list" id="botList"></div>
|
|
41
|
-
<div class="bot-empty" id="botEmpty" hidden>没有匹配的机器人</div>
|
|
42
|
-
<div class="bot-menu-foot">
|
|
43
|
-
<button type="button" id="botAddBtn">
|
|
44
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
45
|
-
<path d="M12 5v14M5 12h14"/>
|
|
46
|
-
</svg>
|
|
47
|
-
新建机器人
|
|
48
|
-
</button>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<nav class="tabs">
|
|
54
|
-
<button class="tab active" data-tab="overview">概览</button>
|
|
55
|
-
|
|
56
|
-
<div class="tab-group" data-group="data">
|
|
57
|
-
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
58
|
-
数据
|
|
59
|
-
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
60
|
-
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
61
|
-
<path d="M6 9l6 6 6-6"/>
|
|
62
|
-
</svg>
|
|
63
|
-
</button>
|
|
64
|
-
<div class="tab-menu" hidden>
|
|
65
|
-
<button class="tab-item" data-tab="stats">统计</button>
|
|
66
|
-
<button class="tab-item" data-tab="events">事件</button>
|
|
67
|
-
<button class="tab-item" data-tab="logs">日志</button>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<div class="tab-group" data-group="settings">
|
|
72
|
-
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
73
|
-
设置
|
|
74
|
-
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
75
|
-
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
76
|
-
<path d="M6 9l6 6 6-6"/>
|
|
77
|
-
</svg>
|
|
78
|
-
</button>
|
|
79
|
-
<div class="tab-menu" hidden>
|
|
80
|
-
<button class="tab-item" data-tab="config">配置</button>
|
|
81
|
-
<button class="tab-item" data-tab="groups">群组</button>
|
|
82
|
-
<button class="tab-item" data-tab="roles">权限</button>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<div class="tab-group" data-group="plugins">
|
|
87
|
-
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
88
|
-
插件
|
|
89
|
-
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
90
|
-
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
91
|
-
<path d="M6 9l6 6 6-6"/>
|
|
92
|
-
</svg>
|
|
93
|
-
</button>
|
|
94
|
-
<div class="tab-menu" hidden>
|
|
95
|
-
<button class="tab-item" data-tab="plugins">插件管理</button>
|
|
96
|
-
<!-- 插件注册的页面挂到这里,见 loadPluginPages() -->
|
|
97
|
-
<div class="tab-menu-sep" id="pluginPageSep" hidden></div>
|
|
98
|
-
<div class="tab-menu-label" id="pluginPageLabel" hidden>插件页面</div>
|
|
99
|
-
<div class="tab-menu-sub" id="pluginPageItems"></div>
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<button class="tab" data-tab="about">关于</button>
|
|
104
|
-
</nav>
|
|
105
|
-
<button class="icon-btn" id="btnTheme" title="切换日间 / 夜间" aria-label="切换主题">
|
|
106
|
-
<svg class="ic-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
107
|
-
stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
|
108
|
-
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/>
|
|
109
|
-
</svg>
|
|
110
|
-
<svg class="ic-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
111
|
-
stroke-width="1.8" stroke-linecap="round">
|
|
112
|
-
<circle cx="12" cy="12" r="4.2"/>
|
|
113
|
-
<path d="M12 2.5v2M12 19.5v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M2.5 12h2M19.5 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/>
|
|
114
|
-
</svg>
|
|
115
|
-
</button>
|
|
116
|
-
|
|
117
|
-
<button class="icon-btn icon-btn-danger" id="btnShutdown" title="关闭程序" aria-label="关闭程序">
|
|
118
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
119
|
-
stroke-width="1.8" stroke-linecap="round">
|
|
120
|
-
<path d="M12 3.2v8.4"/>
|
|
121
|
-
<path d="M6.6 6.6a8 8 0 1 0 10.8 0"/>
|
|
122
|
-
</svg>
|
|
123
|
-
</button>
|
|
124
|
-
|
|
125
|
-
<button class="status-pill" id="connPill" title="点击上线 / 下线">
|
|
126
|
-
<span class="dot" id="connDot"></span>
|
|
127
|
-
<span id="connText">连接中</span>
|
|
128
|
-
<span class="pill-sep"></span>
|
|
129
|
-
<span id="connAction">上线</span>
|
|
130
|
-
</button>
|
|
131
|
-
</header>
|
|
132
|
-
|
|
133
|
-
<main>
|
|
134
|
-
<!-- 概览 -->
|
|
135
|
-
<section id="tab-overview" class="panel active">
|
|
136
|
-
<div class="cards">
|
|
137
|
-
<div class="card"><div class="k">连接状态</div><div class="v" id="c-conn">-</div></div>
|
|
138
|
-
<div class="card"><div class="k">运行时长</div><div class="v" id="c-uptime">-</div></div>
|
|
139
|
-
<div class="card"><div class="k">凭证有效期</div><div class="v" id="c-cred">-</div></div>
|
|
140
|
-
<div class="card"><div class="k">内存占用</div><div class="v" id="c-mem">-</div></div>
|
|
141
|
-
<div class="card"><div class="k">收到消息</div><div class="v" id="c-recv">0</div></div>
|
|
142
|
-
<div class="card"><div class="k">发出消息</div><div class="v" id="c-sent">0</div></div>
|
|
143
|
-
<div class="card"><div class="k">命令命中</div><div class="v" id="c-cmd">0</div></div>
|
|
144
|
-
<div class="card"><div class="k">错误 / 拦截</div><div class="v" id="c-err">0</div></div>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div class="row">
|
|
148
|
-
<div class="box grow">
|
|
149
|
-
<div class="box-hd">
|
|
150
|
-
<h3>活跃会话</h3>
|
|
151
|
-
<span class="hint">按消息数排序,最多 20 条</span>
|
|
152
|
-
</div>
|
|
153
|
-
<div class="table-wrap">
|
|
154
|
-
<table>
|
|
155
|
-
<thead><tr><th>openid</th><th>类型</th><th class="num">消息数</th><th>最后活跃</th></tr></thead>
|
|
156
|
-
<tbody id="chatBody"><tr><td colspan="4" class="empty">暂无数据</td></tr></tbody>
|
|
157
|
-
</table>
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
160
|
-
|
|
161
|
-
<div class="box">
|
|
162
|
-
<div class="box-hd"><h3>运行信息</h3></div>
|
|
163
|
-
<dl class="kv">
|
|
164
|
-
<dt>机器人 ID</dt><dd id="i-botid">-</dd>
|
|
165
|
-
<dt>网关</dt><dd id="i-gw" class="mono">-</dd>
|
|
166
|
-
<dt>会话 ID</dt><dd id="i-session" class="mono">-</dd>
|
|
167
|
-
<dt>intents</dt><dd id="i-intents">-</dd>
|
|
168
|
-
<dt>命令前缀</dt><dd id="i-prefix">-</dd>
|
|
169
|
-
<dt>重连次数</dt><dd id="i-reconn">0</dd>
|
|
170
|
-
<dt>事件统计</dt><dd id="i-events">-</dd>
|
|
171
|
-
<dt>Node</dt><dd id="i-node">-</dd>
|
|
172
|
-
</dl>
|
|
173
|
-
<div class="btn-row">
|
|
174
|
-
<button class="btn" id="btnReconnect">重连网关</button>
|
|
175
|
-
<button class="btn" id="btnRefreshCred">刷新凭证</button>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div class="box">
|
|
181
|
-
<div class="box-hd"><h3>发送消息(调试)</h3></div>
|
|
182
|
-
<div class="form-inline">
|
|
183
|
-
<select id="sendScene"><option value="group">群聊</option><option value="c2c">私聊</option></select>
|
|
184
|
-
<input id="sendTarget" placeholder="群 openid 或用户 openid">
|
|
185
|
-
<input id="sendContent" placeholder="要发送的内容">
|
|
186
|
-
<button class="btn primary" id="btnSend">发送</button>
|
|
187
|
-
</div>
|
|
188
|
-
<div class="hint" id="sendHint">主动消息有频次限制,仅建议调试用。</div>
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
<div class="box">
|
|
192
|
-
<div class="box-hd">
|
|
193
|
-
<h3>后台服务</h3>
|
|
194
|
-
<span class="hint">健康巡检、文件清理、配置热加载、定时重启、检查更新</span>
|
|
195
|
-
</div>
|
|
196
|
-
<div id="serviceList" class="service-list">
|
|
197
|
-
<div class="empty">加载中…</div>
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
|
|
201
|
-
<!-- 体检:放最后。它是排查工具,不是每次都要看的指标 -->
|
|
202
|
-
<div class="box" id="doctorBox">
|
|
203
|
-
<div class="box-hd">
|
|
204
|
-
<h3>体检</h3>
|
|
205
|
-
<span class="hint" id="doctorSummary">点一下,看看哪里还没通</span>
|
|
206
|
-
<button class="btn small" id="btnDoctor">检查</button>
|
|
207
|
-
</div>
|
|
208
|
-
<div id="doctorList" class="doctor-list" hidden></div>
|
|
209
|
-
</div>
|
|
210
|
-
</section>
|
|
211
|
-
|
|
212
|
-
<!-- 关于 -->
|
|
213
|
-
<section id="tab-about" class="panel">
|
|
214
|
-
<div class="box">
|
|
215
|
-
<div class="about-hero">
|
|
216
|
-
<span class="logo about-logo" aria-hidden="true">栖</span>
|
|
217
|
-
<div>
|
|
218
|
-
<div class="about-name">栖 Roost</div>
|
|
219
|
-
<div class="hint">倦飞之鸟,终有一栖 · 零依赖的 QQ 官方机器人框架</div>
|
|
220
|
-
<div class="hint">当前版本 v<span id="updCurrent">-</span></div>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<div class="box">
|
|
226
|
-
<div class="box-hd">
|
|
227
|
-
<h3>版本更新</h3>
|
|
228
|
-
<div class="box-hd-right">
|
|
229
|
-
<button class="btn small" id="btnCheckUpdate">检查更新</button>
|
|
230
|
-
<button class="btn small primary" id="btnApplyUpdate" hidden>立即更新</button>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
<div class="hint" id="updMsg">
|
|
234
|
-
从 GitHub 检查新版本。更新只替换代码目录,<strong>配置、存档、日志、插件都不会动</strong>,更新后需重启程序。
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
<div class="box">
|
|
239
|
-
<div class="box-hd">
|
|
240
|
-
<h3>联系方式</h3>
|
|
241
|
-
<span class="hint">反馈问题、提建议都欢迎</span>
|
|
242
|
-
</div>
|
|
243
|
-
<dl class="kv">
|
|
244
|
-
<dt>QQ</dt><dd class="mono">2014433751</dd>
|
|
245
|
-
<dt>邮箱</dt><dd class="mono">jfzn9594@outlook.com</dd>
|
|
246
|
-
<dt>项目主页</dt>
|
|
247
|
-
<dd>
|
|
248
|
-
<a href="https://github.com/tdcq9594/qq-bot-roost" target="_blank" rel="noopener">GitHub</a>
|
|
249
|
-
·
|
|
250
|
-
<a href="https://gitee.com/tdcq9594/qq-bot-roost" target="_blank" rel="noopener">Gitee</a>
|
|
251
|
-
</dd>
|
|
252
|
-
</dl>
|
|
253
|
-
</div>
|
|
254
|
-
|
|
255
|
-
<div class="box">
|
|
256
|
-
<div class="box-hd"><h3>许可</h3></div>
|
|
257
|
-
<div class="hint">永久免费、禁止任何收费、禁止商业使用(source-available)。详见项目根目录 LICENSE。</div>
|
|
258
|
-
</div>
|
|
259
|
-
</section>
|
|
260
|
-
|
|
261
|
-
<!-- 配置 -->
|
|
262
|
-
<section id="tab-config" class="panel">
|
|
263
|
-
<form id="cfgForm">
|
|
264
|
-
<div class="box">
|
|
265
|
-
<div class="box-hd"><h3>连接凭证</h3>
|
|
266
|
-
<span class="hint">AppID 或 intents 变化会自动重连</span>
|
|
267
|
-
</div>
|
|
268
|
-
<div class="grid2">
|
|
269
|
-
<label>AppID<input name="appId" placeholder="机器人 AppID"></label>
|
|
270
|
-
<label>AppSecret<input name="appSecret" type="password" placeholder="留空则不修改"></label>
|
|
271
|
-
<label>API 地址<input name="baseUrl"></label>
|
|
272
|
-
<label>命令前缀<input name="commandPrefix" maxlength="3"></label>
|
|
273
|
-
<label>收事件方式
|
|
274
|
-
<select name="connectionMode">
|
|
275
|
-
<option value="websocket">WebSocket 长连接(本地推荐)</option>
|
|
276
|
-
<option value="webhook">Webhook 回调(公网 / Serverless)</option>
|
|
277
|
-
</select>
|
|
278
|
-
</label>
|
|
279
|
-
</div>
|
|
280
|
-
<div class="cred-actions">
|
|
281
|
-
<span class="hint" id="cfgMsgTop"></span>
|
|
282
|
-
<button type="submit" class="btn primary">保存配置</button>
|
|
283
|
-
</div>
|
|
284
|
-
<div class="full intents-block">
|
|
285
|
-
<div class="intents-head">
|
|
286
|
-
<span class="intents-title">事件订阅(intents)</span>
|
|
287
|
-
<span class="hint">勾选/取消后<strong>立即生效</strong>,不用点保存。会短暂重连一次。</span>
|
|
288
|
-
</div>
|
|
289
|
-
|
|
290
|
-
<div class="intent-group">
|
|
291
|
-
<div class="intent-group-title">群聊 / 私聊</div>
|
|
292
|
-
<div id="intentGroupChat" class="intent-list"></div>
|
|
293
|
-
</div>
|
|
294
|
-
|
|
295
|
-
<div class="intent-group">
|
|
296
|
-
<div class="intent-group-title">频道(guild)</div>
|
|
297
|
-
<div id="intentGroupGuild" class="intent-list"></div>
|
|
298
|
-
</div>
|
|
299
|
-
|
|
300
|
-
<div class="intents-summary">
|
|
301
|
-
<span>当前值 <b id="intentsValue">33554432</b></span>
|
|
302
|
-
<span class="hint" id="intentsDesc">群聊与私聊</span>
|
|
303
|
-
</div>
|
|
304
|
-
|
|
305
|
-
<div class="btn-row">
|
|
306
|
-
<button type="button" class="btn small" data-preset="chat">群聊 + 私聊(推荐)</button>
|
|
307
|
-
<button type="button" class="btn small" data-preset="guild">频道基础</button>
|
|
308
|
-
<button type="button" class="btn small" data-preset="all">全部基础</button>
|
|
309
|
-
<button type="button" class="btn small" data-preset="none">清空</button>
|
|
310
|
-
</div>
|
|
311
|
-
|
|
312
|
-
<label class="switch small" style="margin-top:12px">
|
|
313
|
-
<input type="checkbox" id="intentsAdvanced"> 高级:手动填写数值
|
|
314
|
-
</label>
|
|
315
|
-
<input name="intents" id="intentsManual" type="number" style="display:none;margin-top:8px">
|
|
316
|
-
|
|
317
|
-
<div class="intent-warn" id="intentsWarn"></div>
|
|
318
|
-
</div>
|
|
319
|
-
</div>
|
|
320
|
-
|
|
321
|
-
<div class="box">
|
|
322
|
-
<div class="box-hd"><h3>行为控制</h3></div>
|
|
323
|
-
<div class="grid2">
|
|
324
|
-
<label class="switch"><input type="checkbox" name="whitelistEnabled"> 启用白名单</label>
|
|
325
|
-
<label class="switch"><input type="checkbox" name="rateLimitEnabled"> 启用限流</label>
|
|
326
|
-
<label>每分钟每会话上限<input name="perChatPerMinute" type="number" min="1"></label>
|
|
327
|
-
<label>去重窗口(秒)<input name="dedupWindowSec" type="number" min="0"></label>
|
|
328
|
-
</div>
|
|
329
|
-
<div class="divider"></div>
|
|
330
|
-
<div class="intent-group-title">消息日志</div>
|
|
331
|
-
<label class="switch">
|
|
332
|
-
<input type="checkbox" name="messageLogEnabled">
|
|
333
|
-
把收到的每一条消息写进日志(便于排查"为什么没反应")
|
|
334
|
-
</label>
|
|
335
|
-
<div class="mute-row">
|
|
336
|
-
<span class="hint">屏蔽以下来源,不记录也不显示:</span>
|
|
337
|
-
<label class="switch small"><input type="checkbox" name="muteGroup"> 群聊</label>
|
|
338
|
-
<label class="switch small"><input type="checkbox" name="muteC2c"> 私聊</label>
|
|
339
|
-
<label class="switch small"><input type="checkbox" name="muteGuild"> 频道</label>
|
|
340
|
-
<label class="switch small"><input type="checkbox" name="muteDm"> 频道私信</label>
|
|
341
|
-
</div>
|
|
342
|
-
|
|
343
|
-
<label class="full">白名单群 openid(每行一个)
|
|
344
|
-
<textarea name="whitelistGroups" rows="2"></textarea>
|
|
345
|
-
</label>
|
|
346
|
-
<label class="full">白名单用户 openid(每行一个)
|
|
347
|
-
<textarea name="whitelistUsers" rows="2"></textarea>
|
|
348
|
-
</label>
|
|
349
|
-
</div>
|
|
350
|
-
|
|
351
|
-
<div class="box">
|
|
352
|
-
<div class="box-hd"><h3>群管能力</h3><span class="hint">禁言 / 撤回已开放;群成员与踢人需官方白名单</span></div>
|
|
353
|
-
<label class="switch">
|
|
354
|
-
<input type="checkbox" name="groupInvited">
|
|
355
|
-
我已申请到群管内邀资格(群成员列表 / 踢人 / 群黑名单)
|
|
356
|
-
</label>
|
|
357
|
-
<div class="hint" style="margin-top:8px">
|
|
358
|
-
官方群管理接口分两档:<b>禁言、撤回、群基本信息</b>对所有机器人开放;
|
|
359
|
-
<b>群成员列表、批量移除(踢人)、群黑名单</b>只对白名单机器人开放,
|
|
360
|
-
没申请就调会返回 <code>11253</code>。<br>
|
|
361
|
-
所以这里默认关闭。去开放平台申请通过后再勾上,勾选后立即生效、不用重启。
|
|
362
|
-
没申请而勾上,只会让机器人每次调用都白跑一趟报错。
|
|
363
|
-
</div>
|
|
364
|
-
</div>
|
|
365
|
-
|
|
366
|
-
<div class="box">
|
|
367
|
-
<div class="box-hd"><h3>面板与日志</h3></div>
|
|
368
|
-
<div class="grid2">
|
|
369
|
-
<label>监听地址<input name="webuiHost" placeholder="127.0.0.1"></label>
|
|
370
|
-
<label>端口<input name="webuiPort" type="number"></label>
|
|
371
|
-
<label>面板访问密钥(留空则不校验;已设置时不会回显,想改就重填)<input name="webuiAccessKey" type="password" autocomplete="new-password"></label>
|
|
372
|
-
<label>日志级别
|
|
373
|
-
<select name="logLevel">
|
|
374
|
-
<option value="debug">debug</option>
|
|
375
|
-
<option value="info">info</option>
|
|
376
|
-
<option value="warn">warn</option>
|
|
377
|
-
<option value="error">error</option>
|
|
378
|
-
</select>
|
|
379
|
-
</label>
|
|
380
|
-
</div>
|
|
381
|
-
<div class="hint">修改监听地址或端口需要重启进程才生效。</div>
|
|
382
|
-
</div>
|
|
383
|
-
|
|
384
|
-
<div class="sticky-actions">
|
|
385
|
-
<span id="cfgMsg" class="hint"></span>
|
|
386
|
-
<button type="submit" class="btn primary">保存配置</button>
|
|
387
|
-
</div>
|
|
388
|
-
</form>
|
|
389
|
-
</section>
|
|
390
|
-
|
|
391
|
-
<!-- 统计 -->
|
|
392
|
-
<section id="tab-stats" class="panel">
|
|
393
|
-
<div class="box">
|
|
394
|
-
<div class="box-hd">
|
|
395
|
-
<h3>消息统计</h3>
|
|
396
|
-
<div class="plugin-tools">
|
|
397
|
-
<select id="statsDays" class="mini-select" aria-label="统计范围">
|
|
398
|
-
<option value="7">最近 7 天</option>
|
|
399
|
-
<option value="14">最近 14 天</option>
|
|
400
|
-
<option value="30">最近 30 天</option>
|
|
401
|
-
</select>
|
|
402
|
-
<button class="btn small" id="btnRefreshStats">刷新</button>
|
|
403
|
-
<button class="btn small" id="btnExportStats" title="导出汇总 CSV(不含消息正文)">导出</button>
|
|
404
|
-
</div>
|
|
405
|
-
</div>
|
|
406
|
-
<div id="statsUnavailable" class="empty" hidden></div>
|
|
407
|
-
<div class="cards" id="statsCards"></div>
|
|
408
|
-
<div class="stat-chart" id="statsChart"></div>
|
|
409
|
-
<div class="hint" id="statsFoot"></div>
|
|
410
|
-
</div>
|
|
411
|
-
|
|
412
|
-
<div class="row">
|
|
413
|
-
<div class="box grow">
|
|
414
|
-
<div class="box-hd">
|
|
415
|
-
<h3>命令排行</h3>
|
|
416
|
-
<span class="hint">按调用次数</span>
|
|
417
|
-
</div>
|
|
418
|
-
<div id="statsTopCommands" class="stat-list"></div>
|
|
419
|
-
</div>
|
|
420
|
-
<div class="box grow">
|
|
421
|
-
<div class="box-hd">
|
|
422
|
-
<h3>会话排行</h3>
|
|
423
|
-
<span class="hint">按消息数</span>
|
|
424
|
-
</div>
|
|
425
|
-
<div id="statsTopChats" class="stat-list"></div>
|
|
426
|
-
</div>
|
|
427
|
-
</div>
|
|
428
|
-
</section>
|
|
429
|
-
|
|
430
|
-
<!-- 插件 -->
|
|
431
|
-
<section id="tab-plugins" class="panel">
|
|
432
|
-
<div class="box">
|
|
433
|
-
<div class="box-hd">
|
|
434
|
-
<h3>已安装插件</h3>
|
|
435
|
-
<div class="plugin-tools">
|
|
436
|
-
<span class="hint">往 plugins/ 里放了新插件,点「刷新」即可加载,不用重启</span>
|
|
437
|
-
<button class="btn small" id="btnRescanPlugins">刷新</button>
|
|
438
|
-
<button class="btn small" id="btnLoadMarket">插件市场</button>
|
|
439
|
-
</div>
|
|
440
|
-
</div>
|
|
441
|
-
<div class="upd-tip" id="pluginUpdateTip"></div>
|
|
442
|
-
<div id="pluginList" class="plugin-list"></div>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<div class="box" id="marketBox" hidden>
|
|
446
|
-
<div class="box-hd">
|
|
447
|
-
<h3>插件市场</h3>
|
|
448
|
-
<div class="plugin-tools">
|
|
449
|
-
<span class="hint" id="marketMeta">加载中…</span>
|
|
450
|
-
<button class="btn small" id="btnRefreshMarket">重新获取</button>
|
|
451
|
-
</div>
|
|
452
|
-
</div>
|
|
453
|
-
|
|
454
|
-
<!-- 下载源:国内直连 GitHub 经常超时,这里可以换镜像 -->
|
|
455
|
-
<div class="mirror-bar">
|
|
456
|
-
<span class="hint">下载源</span>
|
|
457
|
-
<select id="mirrorSelect" class="mini-select" aria-label="下载源"></select>
|
|
458
|
-
<input
|
|
459
|
-
id="mirrorCustom"
|
|
460
|
-
class="mini-input"
|
|
461
|
-
placeholder="自定义前缀,如 https://gh.example/"
|
|
462
|
-
hidden
|
|
463
|
-
/>
|
|
464
|
-
<input
|
|
465
|
-
id="mirrorGiteeToken"
|
|
466
|
-
class="mini-input"
|
|
467
|
-
type="password"
|
|
468
|
-
placeholder="Gitee 私人令牌(选填,留空走匿名)"
|
|
469
|
-
hidden
|
|
470
|
-
/>
|
|
471
|
-
<button class="btn small" id="btnMirrorTest" title="并发测一遍,按你这边实际网络选">测速</button>
|
|
472
|
-
<span class="hint" id="mirrorTip"></span>
|
|
473
|
-
</div>
|
|
474
|
-
|
|
475
|
-
<!-- 插件一多就得能找 -->
|
|
476
|
-
<div class="market-filter">
|
|
477
|
-
<input id="marketSearch" class="mini-input" placeholder="搜索插件名 / 描述 / 标签" />
|
|
478
|
-
<select id="marketCat" class="mini-select" aria-label="分类"></select>
|
|
479
|
-
</div>
|
|
480
|
-
|
|
481
|
-
<div id="marketList" class="plugin-list"></div>
|
|
482
|
-
</div>
|
|
483
|
-
</section>
|
|
484
|
-
|
|
485
|
-
<!-- 事件 -->
|
|
486
|
-
<section id="tab-events" class="panel">
|
|
487
|
-
<div class="box">
|
|
488
|
-
<div class="box-hd">
|
|
489
|
-
<h3>事件订阅与接收</h3>
|
|
490
|
-
<span class="hint">
|
|
491
|
-
官方事件全部可接收并转交插件。灰掉的是当前 intents 没订阅,
|
|
492
|
-
去「配置 → 事件订阅」勾上才会推送
|
|
493
|
-
</span>
|
|
494
|
-
</div>
|
|
495
|
-
<div id="eventSummary" class="event-summary"></div>
|
|
496
|
-
<div class="event-legend">
|
|
497
|
-
<span><b class="ev-dot on"></b>已订阅</span>
|
|
498
|
-
<span><b class="ev-dot off"></b>未订阅</span>
|
|
499
|
-
<span><b class="ev-dot hit"></b>收到过</span>
|
|
500
|
-
</div>
|
|
501
|
-
<div id="eventGroups" class="event-groups"></div>
|
|
502
|
-
</div>
|
|
503
|
-
</section>
|
|
504
|
-
|
|
505
|
-
<!-- 群组 -->
|
|
506
|
-
<section id="tab-groups" class="panel">
|
|
507
|
-
<div class="box">
|
|
508
|
-
<div class="box-hd">
|
|
509
|
-
<h3>机器人主人</h3>
|
|
510
|
-
<span class="hint">主人可以使用全部管理命令</span>
|
|
511
|
-
</div>
|
|
512
|
-
<div id="ownerChips" class="chips"></div>
|
|
513
|
-
<div class="form-inline" style="margin-top:12px">
|
|
514
|
-
<input id="ownerInput" placeholder="填 openid,回车添加">
|
|
515
|
-
<button class="btn primary" id="btnAddOwner">添加</button>
|
|
516
|
-
</div>
|
|
517
|
-
<div class="hint" style="margin-top:8px">
|
|
518
|
-
不知道 openid?在群里 @机器人 发 /whoami,或用上面的「活跃会话」看。
|
|
519
|
-
</div>
|
|
520
|
-
</div>
|
|
521
|
-
|
|
522
|
-
<div class="box">
|
|
523
|
-
<div class="box-hd"><h3>入群后自动授予的权限</h3></div>
|
|
524
|
-
<ul class="tips">
|
|
525
|
-
<li><b>邀请人</b> → 该群管理员(1 级),只影响这一个群</li>
|
|
526
|
-
<li><b>群主</b> → 该群管理员(1 级)。群主发过言才能识别(报文里 member_role=owner)</li>
|
|
527
|
-
<li>两者都<b>不会</b>获得全局主人或全局管理员</li>
|
|
528
|
-
</ul>
|
|
529
|
-
<div class="hint" style="margin-top:8px">
|
|
530
|
-
要调整或撤销,去「权限」页改对应的 <code>group:xxx</code> 作用域。
|
|
531
|
-
全局主人只能在 config.json 的 owners 里配,或首次启动时用认领码认领。
|
|
532
|
-
</div>
|
|
533
|
-
</div>
|
|
534
|
-
|
|
535
|
-
<div class="box">
|
|
536
|
-
<div class="box-hd">
|
|
537
|
-
<h3>手动登记群</h3>
|
|
538
|
-
<span class="hint">官方没有「列出机器人所在的群」的接口,群只能靠事件发现</span>
|
|
539
|
-
</div>
|
|
540
|
-
<ul class="tips">
|
|
541
|
-
<li>机器人被拉进群、或在群里被 @ 过一次,下面列表里就会自动出现</li>
|
|
542
|
-
<li><b>一直不出现</b>:多半是没开「群聊与私聊」intent——去概览页点「检查」能看到</li>
|
|
543
|
-
<li>已经知道群 openid 的话,可以手动登记,方便提前配 <code>group:xxx</code> 权限</li>
|
|
544
|
-
</ul>
|
|
545
|
-
<div class="form-inline" style="margin-top:12px">
|
|
546
|
-
<input id="groupOpenidInput" placeholder="群 openid" />
|
|
547
|
-
<input id="groupNoteInput" placeholder="备注(可选)" style="width:200px" />
|
|
548
|
-
<button class="btn primary" id="btnAddGroup">登记</button>
|
|
549
|
-
</div>
|
|
550
|
-
</div>
|
|
551
|
-
|
|
552
|
-
<div class="box">
|
|
553
|
-
<div class="box-hd">
|
|
554
|
-
<h3>群列表</h3>
|
|
555
|
-
<div class="btn-row" style="margin:0">
|
|
556
|
-
<button class="btn small" id="btnReloadGroups">刷新</button>
|
|
557
|
-
</div>
|
|
558
|
-
</div>
|
|
559
|
-
<div class="table-wrap">
|
|
560
|
-
<table>
|
|
561
|
-
<thead>
|
|
562
|
-
<tr>
|
|
563
|
-
<th>群 openid</th>
|
|
564
|
-
<th>邀请者</th>
|
|
565
|
-
<th>群主(识别)</th>
|
|
566
|
-
<th>状态</th>
|
|
567
|
-
<th>最后活跃</th>
|
|
568
|
-
<th class="num">操作</th>
|
|
569
|
-
</tr>
|
|
570
|
-
</thead>
|
|
571
|
-
<tbody id="groupBody">
|
|
572
|
-
<tr><td colspan="6" class="empty">还没有群。把机器人拉进群后这里会自动出现。</td></tr>
|
|
573
|
-
</tbody>
|
|
574
|
-
</table>
|
|
575
|
-
</div>
|
|
576
|
-
<div class="hint" style="margin-top:8px">
|
|
577
|
-
这里只显示群档案。谁能在这个群做什么,统一在「权限」页按
|
|
578
|
-
<code>group:<群openid></code> 作用域配置。
|
|
579
|
-
</div>
|
|
580
|
-
|
|
581
|
-
<div class="divider"></div>
|
|
582
|
-
|
|
583
|
-
<div class="hint" style="margin-bottom:8px">
|
|
584
|
-
<b>看不到你的群?</b>官方没有「查询机器人所在群列表」的接口,
|
|
585
|
-
群只能靠事件被动发现。请按顺序排查:
|
|
586
|
-
</div>
|
|
587
|
-
<ol class="tips">
|
|
588
|
-
<li>在群里 <b>@机器人</b> 发一句话(不 @ 不会推送消息)</li>
|
|
589
|
-
<li>确认这个群在开放平台「沙箱配置」里(开发中的机器人只收沙箱群消息)</li>
|
|
590
|
-
<li>确认机器人是在它<b>运行期间</b>被拉进群的——离线时入群的事件会丢</li>
|
|
591
|
-
<li>看上面「事件统计」:全是 0 说明平台一条都没推过来</li>
|
|
592
|
-
</ol>
|
|
593
|
-
<div class="form-inline" style="margin-top:12px">
|
|
594
|
-
<input id="groupInput" placeholder="已知群 openid 时可直接登记">
|
|
595
|
-
<button class="btn" id="btnAddGroupManual">手动登记</button>
|
|
596
|
-
</div>
|
|
597
|
-
</div>
|
|
598
|
-
</section>
|
|
599
|
-
|
|
600
|
-
<!-- 权限 -->
|
|
601
|
-
<section id="tab-roles" class="panel">
|
|
602
|
-
<div class="box">
|
|
603
|
-
<div class="box-hd">
|
|
604
|
-
<h3>权限等级</h3>
|
|
605
|
-
<span class="hint">作用域决定「在哪管」,等级决定「能管谁」;数字越小权限越高,只能授予数字更大的等级</span>
|
|
606
|
-
</div>
|
|
607
|
-
<div class="perm-legend">
|
|
608
|
-
<span class="hint" style="margin-right:6px">数字越小权限越高:</span>
|
|
609
|
-
<span><b>0</b> 主人(config.json)</span>
|
|
610
|
-
<span><b>1</b> 管理员</span>
|
|
611
|
-
<span><b>2</b> 群管</span>
|
|
612
|
-
<span><b>3</b> 助手</span>
|
|
613
|
-
<span><b>4-9</b> 框架预留</span>
|
|
614
|
-
<span><b>10+</b> 插件区</span>
|
|
615
|
-
<span><b>9999</b> 无权限</span>
|
|
616
|
-
</div>
|
|
617
|
-
<div class="perm-legend" style="margin-top:6px">
|
|
618
|
-
<span><b>global</b> 全局</span>
|
|
619
|
-
<span><b>group:xxx</b> 某个群</span>
|
|
620
|
-
<span><b>channel:xxx</b> 频道</span>
|
|
621
|
-
<span><b>user:xxx</b> 私聊</span>
|
|
622
|
-
<span><b>feature:插件</b> 功能</span>
|
|
623
|
-
</div>
|
|
624
|
-
</div>
|
|
625
|
-
|
|
626
|
-
<div class="box">
|
|
627
|
-
<div class="box-hd"><h3>添加 / 修改</h3></div>
|
|
628
|
-
<div class="form-inline">
|
|
629
|
-
<input id="roleScope" list="scopeList" placeholder="作用域,如 group:xxx / global">
|
|
630
|
-
<datalist id="scopeList"></datalist>
|
|
631
|
-
<input id="roleOpenid" placeholder="openid">
|
|
632
|
-
<input id="roleLevel" type="number" min="1" max="998" value="2"
|
|
633
|
-
style="width:120px" title="数字越小权限越高">
|
|
634
|
-
<span class="hint">等级(1 管理员 / 2 群管 / 3 助手 / 10+ 插件区,最大 998)</span>
|
|
635
|
-
<button class="btn primary" id="btnAddRole">保存</button>
|
|
636
|
-
</div>
|
|
637
|
-
<div class="hint" style="margin-top:8px">
|
|
638
|
-
面板操作视为本机管理员行为,不受等级限制;聊天里请用 /admin set。
|
|
639
|
-
</div>
|
|
640
|
-
</div>
|
|
641
|
-
|
|
642
|
-
<div class="box">
|
|
643
|
-
<div class="box-hd">
|
|
644
|
-
<h3>最近说过话的人</h3>
|
|
645
|
-
<span class="hint">点一下自动填好 openid 和作用域,不用去日志里翻</span>
|
|
646
|
-
<button class="btn small" id="btnReloadPeople">刷新</button>
|
|
647
|
-
</div>
|
|
648
|
-
<div id="peopleList" class="people-list">
|
|
649
|
-
<div class="empty">还没有收到消息。让要授权的人在群里说句话,这里就会出现。</div>
|
|
650
|
-
</div>
|
|
651
|
-
</div>
|
|
652
|
-
|
|
653
|
-
<div class="box">
|
|
654
|
-
<div class="box-hd">
|
|
655
|
-
<h3>已授权列表</h3>
|
|
656
|
-
<button class="btn small" id="btnReloadRoles">刷新</button>
|
|
657
|
-
</div>
|
|
658
|
-
<div class="table-wrap">
|
|
659
|
-
<table>
|
|
660
|
-
<thead><tr><th>作用域</th><th>openid</th><th>等级</th><th class="num">操作</th></tr></thead>
|
|
661
|
-
<tbody id="roleBody"><tr><td colspan="4" class="empty">还没有配置权限</td></tr></tbody>
|
|
662
|
-
</table>
|
|
663
|
-
</div>
|
|
664
|
-
</div>
|
|
665
|
-
</section>
|
|
666
|
-
|
|
667
|
-
<!-- 日志 -->
|
|
668
|
-
<section id="tab-logs" class="panel">
|
|
669
|
-
<div class="box">
|
|
670
|
-
<div class="box-hd">
|
|
671
|
-
<h3>实时日志</h3>
|
|
672
|
-
<span class="hint">按来源和关键词筛选,不影响实时接收</span>
|
|
673
|
-
</div>
|
|
674
|
-
<div class="log-toolbar">
|
|
675
|
-
<input id="logSearch" class="log-search" placeholder="搜索日志" autocomplete="off">
|
|
676
|
-
<select id="logSourceFilter">
|
|
677
|
-
<option value="all">全部来源</option>
|
|
678
|
-
<option value="core">框架</option>
|
|
679
|
-
<option value="net">网关 / 接口</option>
|
|
680
|
-
<option value="plugin">插件</option>
|
|
681
|
-
</select>
|
|
682
|
-
<select id="logLevelFilter">
|
|
683
|
-
<option value="debug">全部</option>
|
|
684
|
-
<option value="info">info 及以上</option>
|
|
685
|
-
<option value="warn">warn 及以上</option>
|
|
686
|
-
<option value="error">仅 error</option>
|
|
687
|
-
</select>
|
|
688
|
-
<label class="switch small"><input type="checkbox" id="autoScroll" checked> 自动滚动</label>
|
|
689
|
-
<button class="btn small" id="btnClearLog">清屏</button>
|
|
690
|
-
</div>
|
|
691
|
-
<div class="log-legend">
|
|
692
|
-
<span><b class="lg-dot in"></b>收到消息</span>
|
|
693
|
-
<span><b class="lg-dot ok"></b>成功 / 已就绪</span>
|
|
694
|
-
<span><b class="lg-dot err"></b>失败 / 错误</span>
|
|
695
|
-
<span><b class="lg-dot cmd"></b>指令</span>
|
|
696
|
-
<span class="lg-sep"></span>
|
|
697
|
-
<span><b class="lg-chip info">INFO</b>普通</span>
|
|
698
|
-
<span><b class="lg-chip warn">WARN</b>警告</span>
|
|
699
|
-
<span><b class="lg-chip error">ERROR</b>错误</span>
|
|
700
|
-
<span class="lg-sep"></span>
|
|
701
|
-
<span class="hint">模块标签按来源上色:gateway / api / core / plugins / roles …</span>
|
|
702
|
-
</div>
|
|
703
|
-
<div id="logView" class="log-view"></div>
|
|
704
|
-
</div>
|
|
705
|
-
</section>
|
|
706
|
-
</main>
|
|
707
|
-
|
|
708
|
-
<!-- 通用确认弹窗 -->
|
|
709
|
-
<div class="modal-mask" id="modalMask" hidden>
|
|
710
|
-
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
|
|
711
|
-
<h3 class="modal-title" id="modalTitle">确认</h3>
|
|
712
|
-
<div class="modal-body" id="modalBody"></div>
|
|
713
|
-
<div class="modal-actions">
|
|
714
|
-
<button class="btn" id="modalCancel">取消</button>
|
|
715
|
-
<button class="btn danger" id="modalOk">确定</button>
|
|
716
|
-
</div>
|
|
717
|
-
</div>
|
|
718
|
-
</div>
|
|
719
|
-
|
|
720
|
-
<!-- 分群插件开关:这个群能用哪些插件 -->
|
|
721
|
-
<div class="modal-mask" id="gplugMask" hidden>
|
|
722
|
-
<div class="modal wide" role="dialog" aria-modal="true" aria-labelledby="gplugTitle">
|
|
723
|
-
<h3 class="modal-title" id="gplugTitle">分群插件开关</h3>
|
|
724
|
-
<div class="hint" id="gplugSub" style="margin-bottom:10px"></div>
|
|
725
|
-
|
|
726
|
-
<div class="gplug-mode">
|
|
727
|
-
<label class="gplug-radio">
|
|
728
|
-
<input type="radio" name="gplugMode" value="global" checked>
|
|
729
|
-
<span>跟随全局<em id="gplugGlobalHint"></em></span>
|
|
730
|
-
</label>
|
|
731
|
-
<label class="gplug-radio">
|
|
732
|
-
<input type="radio" name="gplugMode" value="custom">
|
|
733
|
-
<span>本群单独配置</span>
|
|
734
|
-
</label>
|
|
735
|
-
</div>
|
|
736
|
-
|
|
737
|
-
<div class="gplug-list" id="gplugList" hidden></div>
|
|
738
|
-
|
|
739
|
-
<div class="modal-actions">
|
|
740
|
-
<button class="btn" id="gplugCancel">取消</button>
|
|
741
|
-
<button class="btn primary" id="gplugSave">保存</button>
|
|
742
|
-
</div>
|
|
743
|
-
</div>
|
|
744
|
-
</div>
|
|
745
|
-
|
|
746
|
-
<!-- 新建机器人 -->
|
|
747
|
-
<div class="modal-mask" id="newBotMask" hidden>
|
|
748
|
-
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="newBotTitle">
|
|
749
|
-
<h3 class="modal-title" id="newBotTitle">新建机器人</h3>
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
<label>
|
|
765
|
-
<span>
|
|
766
|
-
<input id="
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
<
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
<button
|
|
785
|
-
<button
|
|
786
|
-
</div>
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>栖 Roost · 控制台</title>
|
|
7
|
+
<script>
|
|
8
|
+
// 在样式加载前定好主题,避免刷新时闪一下白
|
|
9
|
+
(function () {
|
|
10
|
+
try {
|
|
11
|
+
var t = localStorage.getItem('qqbot_theme');
|
|
12
|
+
if (!t) t = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
13
|
+
document.documentElement.dataset.theme = t;
|
|
14
|
+
} catch (e) {}
|
|
15
|
+
})();
|
|
16
|
+
</script>
|
|
17
|
+
<link rel="stylesheet" href="/style.css">
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
|
|
21
|
+
<header class="topbar">
|
|
22
|
+
<div class="brand" title="栖 Roost · 倦飞之鸟,终有一栖">
|
|
23
|
+
<span class="logo" aria-hidden="true">栖</span>
|
|
24
|
+
<div>
|
|
25
|
+
<div class="title">栖<span class="brand-en">Roost</span></div>
|
|
26
|
+
<div class="sub" id="botName">未连接</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="bot-switch" id="botSwitch">
|
|
30
|
+
<button class="bot-trigger" id="botTrigger" aria-haspopup="listbox" aria-expanded="false">
|
|
31
|
+
<span class="bot-dot" id="botDot"></span>
|
|
32
|
+
<span class="bot-name" id="botNameLabel">加载中…</span>
|
|
33
|
+
<svg class="bot-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
34
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
35
|
+
<path d="M6 9l6 6 6-6"/>
|
|
36
|
+
</svg>
|
|
37
|
+
</button>
|
|
38
|
+
<div class="bot-menu" id="botMenu" hidden role="listbox">
|
|
39
|
+
<input class="bot-search" id="botSearch" placeholder="搜索机器人" hidden>
|
|
40
|
+
<div class="bot-list" id="botList"></div>
|
|
41
|
+
<div class="bot-empty" id="botEmpty" hidden>没有匹配的机器人</div>
|
|
42
|
+
<div class="bot-menu-foot">
|
|
43
|
+
<button type="button" id="botAddBtn">
|
|
44
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
45
|
+
<path d="M12 5v14M5 12h14"/>
|
|
46
|
+
</svg>
|
|
47
|
+
新建机器人
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<nav class="tabs">
|
|
54
|
+
<button class="tab active" data-tab="overview">概览</button>
|
|
55
|
+
|
|
56
|
+
<div class="tab-group" data-group="data">
|
|
57
|
+
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
58
|
+
数据
|
|
59
|
+
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
60
|
+
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
61
|
+
<path d="M6 9l6 6 6-6"/>
|
|
62
|
+
</svg>
|
|
63
|
+
</button>
|
|
64
|
+
<div class="tab-menu" hidden>
|
|
65
|
+
<button class="tab-item" data-tab="stats">统计</button>
|
|
66
|
+
<button class="tab-item" data-tab="events">事件</button>
|
|
67
|
+
<button class="tab-item" data-tab="logs">日志</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="tab-group" data-group="settings">
|
|
72
|
+
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
73
|
+
设置
|
|
74
|
+
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
75
|
+
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
76
|
+
<path d="M6 9l6 6 6-6"/>
|
|
77
|
+
</svg>
|
|
78
|
+
</button>
|
|
79
|
+
<div class="tab-menu" hidden>
|
|
80
|
+
<button class="tab-item" data-tab="config">配置</button>
|
|
81
|
+
<button class="tab-item" data-tab="groups">群组</button>
|
|
82
|
+
<button class="tab-item" data-tab="roles">权限</button>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="tab-group" data-group="plugins">
|
|
87
|
+
<button class="tab tab-parent" aria-haspopup="true" aria-expanded="false">
|
|
88
|
+
插件
|
|
89
|
+
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
90
|
+
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
91
|
+
<path d="M6 9l6 6 6-6"/>
|
|
92
|
+
</svg>
|
|
93
|
+
</button>
|
|
94
|
+
<div class="tab-menu" hidden>
|
|
95
|
+
<button class="tab-item" data-tab="plugins">插件管理</button>
|
|
96
|
+
<!-- 插件注册的页面挂到这里,见 loadPluginPages() -->
|
|
97
|
+
<div class="tab-menu-sep" id="pluginPageSep" hidden></div>
|
|
98
|
+
<div class="tab-menu-label" id="pluginPageLabel" hidden>插件页面</div>
|
|
99
|
+
<div class="tab-menu-sub" id="pluginPageItems"></div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<button class="tab" data-tab="about">关于</button>
|
|
104
|
+
</nav>
|
|
105
|
+
<button class="icon-btn" id="btnTheme" title="切换日间 / 夜间" aria-label="切换主题">
|
|
106
|
+
<svg class="ic-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
107
|
+
stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
|
108
|
+
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/>
|
|
109
|
+
</svg>
|
|
110
|
+
<svg class="ic-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
111
|
+
stroke-width="1.8" stroke-linecap="round">
|
|
112
|
+
<circle cx="12" cy="12" r="4.2"/>
|
|
113
|
+
<path d="M12 2.5v2M12 19.5v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M2.5 12h2M19.5 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/>
|
|
114
|
+
</svg>
|
|
115
|
+
</button>
|
|
116
|
+
|
|
117
|
+
<button class="icon-btn icon-btn-danger" id="btnShutdown" title="关闭程序" aria-label="关闭程序">
|
|
118
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
119
|
+
stroke-width="1.8" stroke-linecap="round">
|
|
120
|
+
<path d="M12 3.2v8.4"/>
|
|
121
|
+
<path d="M6.6 6.6a8 8 0 1 0 10.8 0"/>
|
|
122
|
+
</svg>
|
|
123
|
+
</button>
|
|
124
|
+
|
|
125
|
+
<button class="status-pill" id="connPill" title="点击上线 / 下线">
|
|
126
|
+
<span class="dot" id="connDot"></span>
|
|
127
|
+
<span id="connText">连接中</span>
|
|
128
|
+
<span class="pill-sep"></span>
|
|
129
|
+
<span id="connAction">上线</span>
|
|
130
|
+
</button>
|
|
131
|
+
</header>
|
|
132
|
+
|
|
133
|
+
<main>
|
|
134
|
+
<!-- 概览 -->
|
|
135
|
+
<section id="tab-overview" class="panel active">
|
|
136
|
+
<div class="cards">
|
|
137
|
+
<div class="card"><div class="k">连接状态</div><div class="v" id="c-conn">-</div></div>
|
|
138
|
+
<div class="card"><div class="k">运行时长</div><div class="v" id="c-uptime">-</div></div>
|
|
139
|
+
<div class="card"><div class="k">凭证有效期</div><div class="v" id="c-cred">-</div></div>
|
|
140
|
+
<div class="card"><div class="k">内存占用</div><div class="v" id="c-mem">-</div></div>
|
|
141
|
+
<div class="card"><div class="k">收到消息</div><div class="v" id="c-recv">0</div></div>
|
|
142
|
+
<div class="card"><div class="k">发出消息</div><div class="v" id="c-sent">0</div></div>
|
|
143
|
+
<div class="card"><div class="k">命令命中</div><div class="v" id="c-cmd">0</div></div>
|
|
144
|
+
<div class="card"><div class="k">错误 / 拦截</div><div class="v" id="c-err">0</div></div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="row">
|
|
148
|
+
<div class="box grow">
|
|
149
|
+
<div class="box-hd">
|
|
150
|
+
<h3>活跃会话</h3>
|
|
151
|
+
<span class="hint">按消息数排序,最多 20 条</span>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="table-wrap">
|
|
154
|
+
<table>
|
|
155
|
+
<thead><tr><th>openid</th><th>类型</th><th class="num">消息数</th><th>最后活跃</th></tr></thead>
|
|
156
|
+
<tbody id="chatBody"><tr><td colspan="4" class="empty">暂无数据</td></tr></tbody>
|
|
157
|
+
</table>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div class="box">
|
|
162
|
+
<div class="box-hd"><h3>运行信息</h3></div>
|
|
163
|
+
<dl class="kv">
|
|
164
|
+
<dt>机器人 ID</dt><dd id="i-botid">-</dd>
|
|
165
|
+
<dt>网关</dt><dd id="i-gw" class="mono">-</dd>
|
|
166
|
+
<dt>会话 ID</dt><dd id="i-session" class="mono">-</dd>
|
|
167
|
+
<dt>intents</dt><dd id="i-intents">-</dd>
|
|
168
|
+
<dt>命令前缀</dt><dd id="i-prefix">-</dd>
|
|
169
|
+
<dt>重连次数</dt><dd id="i-reconn">0</dd>
|
|
170
|
+
<dt>事件统计</dt><dd id="i-events">-</dd>
|
|
171
|
+
<dt>Node</dt><dd id="i-node">-</dd>
|
|
172
|
+
</dl>
|
|
173
|
+
<div class="btn-row">
|
|
174
|
+
<button class="btn" id="btnReconnect">重连网关</button>
|
|
175
|
+
<button class="btn" id="btnRefreshCred">刷新凭证</button>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div class="box">
|
|
181
|
+
<div class="box-hd"><h3>发送消息(调试)</h3></div>
|
|
182
|
+
<div class="form-inline">
|
|
183
|
+
<select id="sendScene"><option value="group">群聊</option><option value="c2c">私聊</option></select>
|
|
184
|
+
<input id="sendTarget" placeholder="群 openid 或用户 openid">
|
|
185
|
+
<input id="sendContent" placeholder="要发送的内容">
|
|
186
|
+
<button class="btn primary" id="btnSend">发送</button>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="hint" id="sendHint">主动消息有频次限制,仅建议调试用。</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div class="box">
|
|
192
|
+
<div class="box-hd">
|
|
193
|
+
<h3>后台服务</h3>
|
|
194
|
+
<span class="hint">健康巡检、文件清理、配置热加载、定时重启、检查更新</span>
|
|
195
|
+
</div>
|
|
196
|
+
<div id="serviceList" class="service-list">
|
|
197
|
+
<div class="empty">加载中…</div>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<!-- 体检:放最后。它是排查工具,不是每次都要看的指标 -->
|
|
202
|
+
<div class="box" id="doctorBox">
|
|
203
|
+
<div class="box-hd">
|
|
204
|
+
<h3>体检</h3>
|
|
205
|
+
<span class="hint" id="doctorSummary">点一下,看看哪里还没通</span>
|
|
206
|
+
<button class="btn small" id="btnDoctor">检查</button>
|
|
207
|
+
</div>
|
|
208
|
+
<div id="doctorList" class="doctor-list" hidden></div>
|
|
209
|
+
</div>
|
|
210
|
+
</section>
|
|
211
|
+
|
|
212
|
+
<!-- 关于 -->
|
|
213
|
+
<section id="tab-about" class="panel">
|
|
214
|
+
<div class="box">
|
|
215
|
+
<div class="about-hero">
|
|
216
|
+
<span class="logo about-logo" aria-hidden="true">栖</span>
|
|
217
|
+
<div>
|
|
218
|
+
<div class="about-name">栖 Roost</div>
|
|
219
|
+
<div class="hint">倦飞之鸟,终有一栖 · 零依赖的 QQ 官方机器人框架</div>
|
|
220
|
+
<div class="hint">当前版本 v<span id="updCurrent">-</span></div>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div class="box">
|
|
226
|
+
<div class="box-hd">
|
|
227
|
+
<h3>版本更新</h3>
|
|
228
|
+
<div class="box-hd-right">
|
|
229
|
+
<button class="btn small" id="btnCheckUpdate">检查更新</button>
|
|
230
|
+
<button class="btn small primary" id="btnApplyUpdate" hidden>立即更新</button>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="hint" id="updMsg">
|
|
234
|
+
从 GitHub 检查新版本。更新只替换代码目录,<strong>配置、存档、日志、插件都不会动</strong>,更新后需重启程序。
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<div class="box">
|
|
239
|
+
<div class="box-hd">
|
|
240
|
+
<h3>联系方式</h3>
|
|
241
|
+
<span class="hint">反馈问题、提建议都欢迎</span>
|
|
242
|
+
</div>
|
|
243
|
+
<dl class="kv">
|
|
244
|
+
<dt>QQ</dt><dd class="mono">2014433751</dd>
|
|
245
|
+
<dt>邮箱</dt><dd class="mono">jfzn9594@outlook.com</dd>
|
|
246
|
+
<dt>项目主页</dt>
|
|
247
|
+
<dd>
|
|
248
|
+
<a href="https://github.com/tdcq9594/qq-bot-roost" target="_blank" rel="noopener">GitHub</a>
|
|
249
|
+
·
|
|
250
|
+
<a href="https://gitee.com/tdcq9594/qq-bot-roost" target="_blank" rel="noopener">Gitee</a>
|
|
251
|
+
</dd>
|
|
252
|
+
</dl>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<div class="box">
|
|
256
|
+
<div class="box-hd"><h3>许可</h3></div>
|
|
257
|
+
<div class="hint">永久免费、禁止任何收费、禁止商业使用(source-available)。详见项目根目录 LICENSE。</div>
|
|
258
|
+
</div>
|
|
259
|
+
</section>
|
|
260
|
+
|
|
261
|
+
<!-- 配置 -->
|
|
262
|
+
<section id="tab-config" class="panel">
|
|
263
|
+
<form id="cfgForm">
|
|
264
|
+
<div class="box">
|
|
265
|
+
<div class="box-hd"><h3>连接凭证</h3>
|
|
266
|
+
<span class="hint">AppID 或 intents 变化会自动重连</span>
|
|
267
|
+
</div>
|
|
268
|
+
<div class="grid2">
|
|
269
|
+
<label>AppID<input name="appId" placeholder="机器人 AppID"></label>
|
|
270
|
+
<label>AppSecret<input name="appSecret" type="password" placeholder="留空则不修改"></label>
|
|
271
|
+
<label>API 地址<input name="baseUrl"></label>
|
|
272
|
+
<label>命令前缀<input name="commandPrefix" maxlength="3"></label>
|
|
273
|
+
<label>收事件方式
|
|
274
|
+
<select name="connectionMode">
|
|
275
|
+
<option value="websocket">WebSocket 长连接(本地推荐)</option>
|
|
276
|
+
<option value="webhook">Webhook 回调(公网 / Serverless)</option>
|
|
277
|
+
</select>
|
|
278
|
+
</label>
|
|
279
|
+
</div>
|
|
280
|
+
<div class="cred-actions">
|
|
281
|
+
<span class="hint" id="cfgMsgTop"></span>
|
|
282
|
+
<button type="submit" class="btn primary">保存配置</button>
|
|
283
|
+
</div>
|
|
284
|
+
<div class="full intents-block">
|
|
285
|
+
<div class="intents-head">
|
|
286
|
+
<span class="intents-title">事件订阅(intents)</span>
|
|
287
|
+
<span class="hint">勾选/取消后<strong>立即生效</strong>,不用点保存。会短暂重连一次。</span>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div class="intent-group">
|
|
291
|
+
<div class="intent-group-title">群聊 / 私聊</div>
|
|
292
|
+
<div id="intentGroupChat" class="intent-list"></div>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<div class="intent-group">
|
|
296
|
+
<div class="intent-group-title">频道(guild)</div>
|
|
297
|
+
<div id="intentGroupGuild" class="intent-list"></div>
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
<div class="intents-summary">
|
|
301
|
+
<span>当前值 <b id="intentsValue">33554432</b></span>
|
|
302
|
+
<span class="hint" id="intentsDesc">群聊与私聊</span>
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
<div class="btn-row">
|
|
306
|
+
<button type="button" class="btn small" data-preset="chat">群聊 + 私聊(推荐)</button>
|
|
307
|
+
<button type="button" class="btn small" data-preset="guild">频道基础</button>
|
|
308
|
+
<button type="button" class="btn small" data-preset="all">全部基础</button>
|
|
309
|
+
<button type="button" class="btn small" data-preset="none">清空</button>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<label class="switch small" style="margin-top:12px">
|
|
313
|
+
<input type="checkbox" id="intentsAdvanced"> 高级:手动填写数值
|
|
314
|
+
</label>
|
|
315
|
+
<input name="intents" id="intentsManual" type="number" style="display:none;margin-top:8px">
|
|
316
|
+
|
|
317
|
+
<div class="intent-warn" id="intentsWarn"></div>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
<div class="box">
|
|
322
|
+
<div class="box-hd"><h3>行为控制</h3></div>
|
|
323
|
+
<div class="grid2">
|
|
324
|
+
<label class="switch"><input type="checkbox" name="whitelistEnabled"> 启用白名单</label>
|
|
325
|
+
<label class="switch"><input type="checkbox" name="rateLimitEnabled"> 启用限流</label>
|
|
326
|
+
<label>每分钟每会话上限<input name="perChatPerMinute" type="number" min="1"></label>
|
|
327
|
+
<label>去重窗口(秒)<input name="dedupWindowSec" type="number" min="0"></label>
|
|
328
|
+
</div>
|
|
329
|
+
<div class="divider"></div>
|
|
330
|
+
<div class="intent-group-title">消息日志</div>
|
|
331
|
+
<label class="switch">
|
|
332
|
+
<input type="checkbox" name="messageLogEnabled">
|
|
333
|
+
把收到的每一条消息写进日志(便于排查"为什么没反应")
|
|
334
|
+
</label>
|
|
335
|
+
<div class="mute-row">
|
|
336
|
+
<span class="hint">屏蔽以下来源,不记录也不显示:</span>
|
|
337
|
+
<label class="switch small"><input type="checkbox" name="muteGroup"> 群聊</label>
|
|
338
|
+
<label class="switch small"><input type="checkbox" name="muteC2c"> 私聊</label>
|
|
339
|
+
<label class="switch small"><input type="checkbox" name="muteGuild"> 频道</label>
|
|
340
|
+
<label class="switch small"><input type="checkbox" name="muteDm"> 频道私信</label>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<label class="full">白名单群 openid(每行一个)
|
|
344
|
+
<textarea name="whitelistGroups" rows="2"></textarea>
|
|
345
|
+
</label>
|
|
346
|
+
<label class="full">白名单用户 openid(每行一个)
|
|
347
|
+
<textarea name="whitelistUsers" rows="2"></textarea>
|
|
348
|
+
</label>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<div class="box">
|
|
352
|
+
<div class="box-hd"><h3>群管能力</h3><span class="hint">禁言 / 撤回已开放;群成员与踢人需官方白名单</span></div>
|
|
353
|
+
<label class="switch">
|
|
354
|
+
<input type="checkbox" name="groupInvited">
|
|
355
|
+
我已申请到群管内邀资格(群成员列表 / 踢人 / 群黑名单)
|
|
356
|
+
</label>
|
|
357
|
+
<div class="hint" style="margin-top:8px">
|
|
358
|
+
官方群管理接口分两档:<b>禁言、撤回、群基本信息</b>对所有机器人开放;
|
|
359
|
+
<b>群成员列表、批量移除(踢人)、群黑名单</b>只对白名单机器人开放,
|
|
360
|
+
没申请就调会返回 <code>11253</code>。<br>
|
|
361
|
+
所以这里默认关闭。去开放平台申请通过后再勾上,勾选后立即生效、不用重启。
|
|
362
|
+
没申请而勾上,只会让机器人每次调用都白跑一趟报错。
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<div class="box">
|
|
367
|
+
<div class="box-hd"><h3>面板与日志</h3></div>
|
|
368
|
+
<div class="grid2">
|
|
369
|
+
<label>监听地址<input name="webuiHost" placeholder="127.0.0.1"></label>
|
|
370
|
+
<label>端口<input name="webuiPort" type="number"></label>
|
|
371
|
+
<label>面板访问密钥(留空则不校验;已设置时不会回显,想改就重填)<input name="webuiAccessKey" type="password" autocomplete="new-password"></label>
|
|
372
|
+
<label>日志级别
|
|
373
|
+
<select name="logLevel">
|
|
374
|
+
<option value="debug">debug</option>
|
|
375
|
+
<option value="info">info</option>
|
|
376
|
+
<option value="warn">warn</option>
|
|
377
|
+
<option value="error">error</option>
|
|
378
|
+
</select>
|
|
379
|
+
</label>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="hint">修改监听地址或端口需要重启进程才生效。</div>
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
<div class="sticky-actions">
|
|
385
|
+
<span id="cfgMsg" class="hint"></span>
|
|
386
|
+
<button type="submit" class="btn primary">保存配置</button>
|
|
387
|
+
</div>
|
|
388
|
+
</form>
|
|
389
|
+
</section>
|
|
390
|
+
|
|
391
|
+
<!-- 统计 -->
|
|
392
|
+
<section id="tab-stats" class="panel">
|
|
393
|
+
<div class="box">
|
|
394
|
+
<div class="box-hd">
|
|
395
|
+
<h3>消息统计</h3>
|
|
396
|
+
<div class="plugin-tools">
|
|
397
|
+
<select id="statsDays" class="mini-select" aria-label="统计范围">
|
|
398
|
+
<option value="7">最近 7 天</option>
|
|
399
|
+
<option value="14">最近 14 天</option>
|
|
400
|
+
<option value="30">最近 30 天</option>
|
|
401
|
+
</select>
|
|
402
|
+
<button class="btn small" id="btnRefreshStats">刷新</button>
|
|
403
|
+
<button class="btn small" id="btnExportStats" title="导出汇总 CSV(不含消息正文)">导出</button>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
<div id="statsUnavailable" class="empty" hidden></div>
|
|
407
|
+
<div class="cards" id="statsCards"></div>
|
|
408
|
+
<div class="stat-chart" id="statsChart"></div>
|
|
409
|
+
<div class="hint" id="statsFoot"></div>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<div class="row">
|
|
413
|
+
<div class="box grow">
|
|
414
|
+
<div class="box-hd">
|
|
415
|
+
<h3>命令排行</h3>
|
|
416
|
+
<span class="hint">按调用次数</span>
|
|
417
|
+
</div>
|
|
418
|
+
<div id="statsTopCommands" class="stat-list"></div>
|
|
419
|
+
</div>
|
|
420
|
+
<div class="box grow">
|
|
421
|
+
<div class="box-hd">
|
|
422
|
+
<h3>会话排行</h3>
|
|
423
|
+
<span class="hint">按消息数</span>
|
|
424
|
+
</div>
|
|
425
|
+
<div id="statsTopChats" class="stat-list"></div>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
</section>
|
|
429
|
+
|
|
430
|
+
<!-- 插件 -->
|
|
431
|
+
<section id="tab-plugins" class="panel">
|
|
432
|
+
<div class="box">
|
|
433
|
+
<div class="box-hd">
|
|
434
|
+
<h3>已安装插件</h3>
|
|
435
|
+
<div class="plugin-tools">
|
|
436
|
+
<span class="hint">往 plugins/ 里放了新插件,点「刷新」即可加载,不用重启</span>
|
|
437
|
+
<button class="btn small" id="btnRescanPlugins">刷新</button>
|
|
438
|
+
<button class="btn small" id="btnLoadMarket">插件市场</button>
|
|
439
|
+
</div>
|
|
440
|
+
</div>
|
|
441
|
+
<div class="upd-tip" id="pluginUpdateTip"></div>
|
|
442
|
+
<div id="pluginList" class="plugin-list"></div>
|
|
443
|
+
</div>
|
|
444
|
+
|
|
445
|
+
<div class="box" id="marketBox" hidden>
|
|
446
|
+
<div class="box-hd">
|
|
447
|
+
<h3>插件市场</h3>
|
|
448
|
+
<div class="plugin-tools">
|
|
449
|
+
<span class="hint" id="marketMeta">加载中…</span>
|
|
450
|
+
<button class="btn small" id="btnRefreshMarket">重新获取</button>
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
|
|
454
|
+
<!-- 下载源:国内直连 GitHub 经常超时,这里可以换镜像 -->
|
|
455
|
+
<div class="mirror-bar">
|
|
456
|
+
<span class="hint">下载源</span>
|
|
457
|
+
<select id="mirrorSelect" class="mini-select" aria-label="下载源"></select>
|
|
458
|
+
<input
|
|
459
|
+
id="mirrorCustom"
|
|
460
|
+
class="mini-input"
|
|
461
|
+
placeholder="自定义前缀,如 https://gh.example/"
|
|
462
|
+
hidden
|
|
463
|
+
/>
|
|
464
|
+
<input
|
|
465
|
+
id="mirrorGiteeToken"
|
|
466
|
+
class="mini-input"
|
|
467
|
+
type="password"
|
|
468
|
+
placeholder="Gitee 私人令牌(选填,留空走匿名)"
|
|
469
|
+
hidden
|
|
470
|
+
/>
|
|
471
|
+
<button class="btn small" id="btnMirrorTest" title="并发测一遍,按你这边实际网络选">测速</button>
|
|
472
|
+
<span class="hint" id="mirrorTip"></span>
|
|
473
|
+
</div>
|
|
474
|
+
|
|
475
|
+
<!-- 插件一多就得能找 -->
|
|
476
|
+
<div class="market-filter">
|
|
477
|
+
<input id="marketSearch" class="mini-input" placeholder="搜索插件名 / 描述 / 标签" />
|
|
478
|
+
<select id="marketCat" class="mini-select" aria-label="分类"></select>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<div id="marketList" class="plugin-list"></div>
|
|
482
|
+
</div>
|
|
483
|
+
</section>
|
|
484
|
+
|
|
485
|
+
<!-- 事件 -->
|
|
486
|
+
<section id="tab-events" class="panel">
|
|
487
|
+
<div class="box">
|
|
488
|
+
<div class="box-hd">
|
|
489
|
+
<h3>事件订阅与接收</h3>
|
|
490
|
+
<span class="hint">
|
|
491
|
+
官方事件全部可接收并转交插件。灰掉的是当前 intents 没订阅,
|
|
492
|
+
去「配置 → 事件订阅」勾上才会推送
|
|
493
|
+
</span>
|
|
494
|
+
</div>
|
|
495
|
+
<div id="eventSummary" class="event-summary"></div>
|
|
496
|
+
<div class="event-legend">
|
|
497
|
+
<span><b class="ev-dot on"></b>已订阅</span>
|
|
498
|
+
<span><b class="ev-dot off"></b>未订阅</span>
|
|
499
|
+
<span><b class="ev-dot hit"></b>收到过</span>
|
|
500
|
+
</div>
|
|
501
|
+
<div id="eventGroups" class="event-groups"></div>
|
|
502
|
+
</div>
|
|
503
|
+
</section>
|
|
504
|
+
|
|
505
|
+
<!-- 群组 -->
|
|
506
|
+
<section id="tab-groups" class="panel">
|
|
507
|
+
<div class="box">
|
|
508
|
+
<div class="box-hd">
|
|
509
|
+
<h3>机器人主人</h3>
|
|
510
|
+
<span class="hint">主人可以使用全部管理命令</span>
|
|
511
|
+
</div>
|
|
512
|
+
<div id="ownerChips" class="chips"></div>
|
|
513
|
+
<div class="form-inline" style="margin-top:12px">
|
|
514
|
+
<input id="ownerInput" placeholder="填 openid,回车添加">
|
|
515
|
+
<button class="btn primary" id="btnAddOwner">添加</button>
|
|
516
|
+
</div>
|
|
517
|
+
<div class="hint" style="margin-top:8px">
|
|
518
|
+
不知道 openid?在群里 @机器人 发 /whoami,或用上面的「活跃会话」看。
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
<div class="box">
|
|
523
|
+
<div class="box-hd"><h3>入群后自动授予的权限</h3></div>
|
|
524
|
+
<ul class="tips">
|
|
525
|
+
<li><b>邀请人</b> → 该群管理员(1 级),只影响这一个群</li>
|
|
526
|
+
<li><b>群主</b> → 该群管理员(1 级)。群主发过言才能识别(报文里 member_role=owner)</li>
|
|
527
|
+
<li>两者都<b>不会</b>获得全局主人或全局管理员</li>
|
|
528
|
+
</ul>
|
|
529
|
+
<div class="hint" style="margin-top:8px">
|
|
530
|
+
要调整或撤销,去「权限」页改对应的 <code>group:xxx</code> 作用域。
|
|
531
|
+
全局主人只能在 config.json 的 owners 里配,或首次启动时用认领码认领。
|
|
532
|
+
</div>
|
|
533
|
+
</div>
|
|
534
|
+
|
|
535
|
+
<div class="box">
|
|
536
|
+
<div class="box-hd">
|
|
537
|
+
<h3>手动登记群</h3>
|
|
538
|
+
<span class="hint">官方没有「列出机器人所在的群」的接口,群只能靠事件发现</span>
|
|
539
|
+
</div>
|
|
540
|
+
<ul class="tips">
|
|
541
|
+
<li>机器人被拉进群、或在群里被 @ 过一次,下面列表里就会自动出现</li>
|
|
542
|
+
<li><b>一直不出现</b>:多半是没开「群聊与私聊」intent——去概览页点「检查」能看到</li>
|
|
543
|
+
<li>已经知道群 openid 的话,可以手动登记,方便提前配 <code>group:xxx</code> 权限</li>
|
|
544
|
+
</ul>
|
|
545
|
+
<div class="form-inline" style="margin-top:12px">
|
|
546
|
+
<input id="groupOpenidInput" placeholder="群 openid" />
|
|
547
|
+
<input id="groupNoteInput" placeholder="备注(可选)" style="width:200px" />
|
|
548
|
+
<button class="btn primary" id="btnAddGroup">登记</button>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
<div class="box">
|
|
553
|
+
<div class="box-hd">
|
|
554
|
+
<h3>群列表</h3>
|
|
555
|
+
<div class="btn-row" style="margin:0">
|
|
556
|
+
<button class="btn small" id="btnReloadGroups">刷新</button>
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
<div class="table-wrap">
|
|
560
|
+
<table>
|
|
561
|
+
<thead>
|
|
562
|
+
<tr>
|
|
563
|
+
<th>群 openid</th>
|
|
564
|
+
<th>邀请者</th>
|
|
565
|
+
<th>群主(识别)</th>
|
|
566
|
+
<th>状态</th>
|
|
567
|
+
<th>最后活跃</th>
|
|
568
|
+
<th class="num">操作</th>
|
|
569
|
+
</tr>
|
|
570
|
+
</thead>
|
|
571
|
+
<tbody id="groupBody">
|
|
572
|
+
<tr><td colspan="6" class="empty">还没有群。把机器人拉进群后这里会自动出现。</td></tr>
|
|
573
|
+
</tbody>
|
|
574
|
+
</table>
|
|
575
|
+
</div>
|
|
576
|
+
<div class="hint" style="margin-top:8px">
|
|
577
|
+
这里只显示群档案。谁能在这个群做什么,统一在「权限」页按
|
|
578
|
+
<code>group:<群openid></code> 作用域配置。
|
|
579
|
+
</div>
|
|
580
|
+
|
|
581
|
+
<div class="divider"></div>
|
|
582
|
+
|
|
583
|
+
<div class="hint" style="margin-bottom:8px">
|
|
584
|
+
<b>看不到你的群?</b>官方没有「查询机器人所在群列表」的接口,
|
|
585
|
+
群只能靠事件被动发现。请按顺序排查:
|
|
586
|
+
</div>
|
|
587
|
+
<ol class="tips">
|
|
588
|
+
<li>在群里 <b>@机器人</b> 发一句话(不 @ 不会推送消息)</li>
|
|
589
|
+
<li>确认这个群在开放平台「沙箱配置」里(开发中的机器人只收沙箱群消息)</li>
|
|
590
|
+
<li>确认机器人是在它<b>运行期间</b>被拉进群的——离线时入群的事件会丢</li>
|
|
591
|
+
<li>看上面「事件统计」:全是 0 说明平台一条都没推过来</li>
|
|
592
|
+
</ol>
|
|
593
|
+
<div class="form-inline" style="margin-top:12px">
|
|
594
|
+
<input id="groupInput" placeholder="已知群 openid 时可直接登记">
|
|
595
|
+
<button class="btn" id="btnAddGroupManual">手动登记</button>
|
|
596
|
+
</div>
|
|
597
|
+
</div>
|
|
598
|
+
</section>
|
|
599
|
+
|
|
600
|
+
<!-- 权限 -->
|
|
601
|
+
<section id="tab-roles" class="panel">
|
|
602
|
+
<div class="box">
|
|
603
|
+
<div class="box-hd">
|
|
604
|
+
<h3>权限等级</h3>
|
|
605
|
+
<span class="hint">作用域决定「在哪管」,等级决定「能管谁」;数字越小权限越高,只能授予数字更大的等级</span>
|
|
606
|
+
</div>
|
|
607
|
+
<div class="perm-legend">
|
|
608
|
+
<span class="hint" style="margin-right:6px">数字越小权限越高:</span>
|
|
609
|
+
<span><b>0</b> 主人(config.json)</span>
|
|
610
|
+
<span><b>1</b> 管理员</span>
|
|
611
|
+
<span><b>2</b> 群管</span>
|
|
612
|
+
<span><b>3</b> 助手</span>
|
|
613
|
+
<span><b>4-9</b> 框架预留</span>
|
|
614
|
+
<span><b>10+</b> 插件区</span>
|
|
615
|
+
<span><b>9999</b> 无权限</span>
|
|
616
|
+
</div>
|
|
617
|
+
<div class="perm-legend" style="margin-top:6px">
|
|
618
|
+
<span><b>global</b> 全局</span>
|
|
619
|
+
<span><b>group:xxx</b> 某个群</span>
|
|
620
|
+
<span><b>channel:xxx</b> 频道</span>
|
|
621
|
+
<span><b>user:xxx</b> 私聊</span>
|
|
622
|
+
<span><b>feature:插件</b> 功能</span>
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
|
|
626
|
+
<div class="box">
|
|
627
|
+
<div class="box-hd"><h3>添加 / 修改</h3></div>
|
|
628
|
+
<div class="form-inline">
|
|
629
|
+
<input id="roleScope" list="scopeList" placeholder="作用域,如 group:xxx / global">
|
|
630
|
+
<datalist id="scopeList"></datalist>
|
|
631
|
+
<input id="roleOpenid" placeholder="openid">
|
|
632
|
+
<input id="roleLevel" type="number" min="1" max="998" value="2"
|
|
633
|
+
style="width:120px" title="数字越小权限越高">
|
|
634
|
+
<span class="hint">等级(1 管理员 / 2 群管 / 3 助手 / 10+ 插件区,最大 998)</span>
|
|
635
|
+
<button class="btn primary" id="btnAddRole">保存</button>
|
|
636
|
+
</div>
|
|
637
|
+
<div class="hint" style="margin-top:8px">
|
|
638
|
+
面板操作视为本机管理员行为,不受等级限制;聊天里请用 /admin set。
|
|
639
|
+
</div>
|
|
640
|
+
</div>
|
|
641
|
+
|
|
642
|
+
<div class="box">
|
|
643
|
+
<div class="box-hd">
|
|
644
|
+
<h3>最近说过话的人</h3>
|
|
645
|
+
<span class="hint">点一下自动填好 openid 和作用域,不用去日志里翻</span>
|
|
646
|
+
<button class="btn small" id="btnReloadPeople">刷新</button>
|
|
647
|
+
</div>
|
|
648
|
+
<div id="peopleList" class="people-list">
|
|
649
|
+
<div class="empty">还没有收到消息。让要授权的人在群里说句话,这里就会出现。</div>
|
|
650
|
+
</div>
|
|
651
|
+
</div>
|
|
652
|
+
|
|
653
|
+
<div class="box">
|
|
654
|
+
<div class="box-hd">
|
|
655
|
+
<h3>已授权列表</h3>
|
|
656
|
+
<button class="btn small" id="btnReloadRoles">刷新</button>
|
|
657
|
+
</div>
|
|
658
|
+
<div class="table-wrap">
|
|
659
|
+
<table>
|
|
660
|
+
<thead><tr><th>作用域</th><th>openid</th><th>等级</th><th class="num">操作</th></tr></thead>
|
|
661
|
+
<tbody id="roleBody"><tr><td colspan="4" class="empty">还没有配置权限</td></tr></tbody>
|
|
662
|
+
</table>
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
</section>
|
|
666
|
+
|
|
667
|
+
<!-- 日志 -->
|
|
668
|
+
<section id="tab-logs" class="panel">
|
|
669
|
+
<div class="box">
|
|
670
|
+
<div class="box-hd">
|
|
671
|
+
<h3>实时日志</h3>
|
|
672
|
+
<span class="hint">按来源和关键词筛选,不影响实时接收</span>
|
|
673
|
+
</div>
|
|
674
|
+
<div class="log-toolbar">
|
|
675
|
+
<input id="logSearch" class="log-search" placeholder="搜索日志" autocomplete="off">
|
|
676
|
+
<select id="logSourceFilter">
|
|
677
|
+
<option value="all">全部来源</option>
|
|
678
|
+
<option value="core">框架</option>
|
|
679
|
+
<option value="net">网关 / 接口</option>
|
|
680
|
+
<option value="plugin">插件</option>
|
|
681
|
+
</select>
|
|
682
|
+
<select id="logLevelFilter">
|
|
683
|
+
<option value="debug">全部</option>
|
|
684
|
+
<option value="info">info 及以上</option>
|
|
685
|
+
<option value="warn">warn 及以上</option>
|
|
686
|
+
<option value="error">仅 error</option>
|
|
687
|
+
</select>
|
|
688
|
+
<label class="switch small"><input type="checkbox" id="autoScroll" checked> 自动滚动</label>
|
|
689
|
+
<button class="btn small" id="btnClearLog">清屏</button>
|
|
690
|
+
</div>
|
|
691
|
+
<div class="log-legend">
|
|
692
|
+
<span><b class="lg-dot in"></b>收到消息</span>
|
|
693
|
+
<span><b class="lg-dot ok"></b>成功 / 已就绪</span>
|
|
694
|
+
<span><b class="lg-dot err"></b>失败 / 错误</span>
|
|
695
|
+
<span><b class="lg-dot cmd"></b>指令</span>
|
|
696
|
+
<span class="lg-sep"></span>
|
|
697
|
+
<span><b class="lg-chip info">INFO</b>普通</span>
|
|
698
|
+
<span><b class="lg-chip warn">WARN</b>警告</span>
|
|
699
|
+
<span><b class="lg-chip error">ERROR</b>错误</span>
|
|
700
|
+
<span class="lg-sep"></span>
|
|
701
|
+
<span class="hint">模块标签按来源上色:gateway / api / core / plugins / roles …</span>
|
|
702
|
+
</div>
|
|
703
|
+
<div id="logView" class="log-view"></div>
|
|
704
|
+
</div>
|
|
705
|
+
</section>
|
|
706
|
+
</main>
|
|
707
|
+
|
|
708
|
+
<!-- 通用确认弹窗 -->
|
|
709
|
+
<div class="modal-mask" id="modalMask" hidden>
|
|
710
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
|
|
711
|
+
<h3 class="modal-title" id="modalTitle">确认</h3>
|
|
712
|
+
<div class="modal-body" id="modalBody"></div>
|
|
713
|
+
<div class="modal-actions">
|
|
714
|
+
<button class="btn" id="modalCancel">取消</button>
|
|
715
|
+
<button class="btn danger" id="modalOk">确定</button>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
|
|
720
|
+
<!-- 分群插件开关:这个群能用哪些插件 -->
|
|
721
|
+
<div class="modal-mask" id="gplugMask" hidden>
|
|
722
|
+
<div class="modal wide" role="dialog" aria-modal="true" aria-labelledby="gplugTitle">
|
|
723
|
+
<h3 class="modal-title" id="gplugTitle">分群插件开关</h3>
|
|
724
|
+
<div class="hint" id="gplugSub" style="margin-bottom:10px"></div>
|
|
725
|
+
|
|
726
|
+
<div class="gplug-mode">
|
|
727
|
+
<label class="gplug-radio">
|
|
728
|
+
<input type="radio" name="gplugMode" value="global" checked>
|
|
729
|
+
<span>跟随全局<em id="gplugGlobalHint"></em></span>
|
|
730
|
+
</label>
|
|
731
|
+
<label class="gplug-radio">
|
|
732
|
+
<input type="radio" name="gplugMode" value="custom">
|
|
733
|
+
<span>本群单独配置</span>
|
|
734
|
+
</label>
|
|
735
|
+
</div>
|
|
736
|
+
|
|
737
|
+
<div class="gplug-list" id="gplugList" hidden></div>
|
|
738
|
+
|
|
739
|
+
<div class="modal-actions">
|
|
740
|
+
<button class="btn" id="gplugCancel">取消</button>
|
|
741
|
+
<button class="btn primary" id="gplugSave">保存</button>
|
|
742
|
+
</div>
|
|
743
|
+
</div>
|
|
744
|
+
</div>
|
|
745
|
+
|
|
746
|
+
<!-- 新建机器人 -->
|
|
747
|
+
<div class="modal-mask" id="newBotMask" hidden>
|
|
748
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="newBotTitle">
|
|
749
|
+
<h3 class="modal-title" id="newBotTitle">新建机器人</h3>
|
|
750
|
+
|
|
751
|
+
<!-- 扫码一键创建:手机 QQ 扫一下,AppID / AppSecret 自动填好 -->
|
|
752
|
+
<div class="nb-qr-wrap">
|
|
753
|
+
<button class="btn primary" id="nbQrStart" type="button">扫码一键创建</button>
|
|
754
|
+
<i class="nb-qr-hint">推荐:不用去 q.qq.com 手动建机器人</i>
|
|
755
|
+
</div>
|
|
756
|
+
<div class="nb-qr" id="nbQr" hidden>
|
|
757
|
+
<div class="nb-qr-code" id="nbQrCode"></div>
|
|
758
|
+
<div class="nb-qr-tip" id="nbQrTip"></div>
|
|
759
|
+
</div>
|
|
760
|
+
|
|
761
|
+
<div class="nb-or">或者手动填(已有机器人、或扫码用不了时)</div>
|
|
762
|
+
|
|
763
|
+
<div class="bot-form">
|
|
764
|
+
<label>
|
|
765
|
+
<span>ID</span>
|
|
766
|
+
<input id="nbId" placeholder="main-bot,小写字母数字短横线" autocomplete="off">
|
|
767
|
+
<i>用来做文件夹名,创建后不能改</i>
|
|
768
|
+
</label>
|
|
769
|
+
<label>
|
|
770
|
+
<span>显示名</span>
|
|
771
|
+
<input id="nbName" placeholder="留空则用 ID" autocomplete="off">
|
|
772
|
+
</label>
|
|
773
|
+
<label>
|
|
774
|
+
<span>AppID</span>
|
|
775
|
+
<input id="nbAppId" placeholder="q.qq.com 开发设置里的 AppID" autocomplete="off">
|
|
776
|
+
</label>
|
|
777
|
+
<label>
|
|
778
|
+
<span>AppSecret</span>
|
|
779
|
+
<input id="nbSecret" type="password" placeholder="AppSecret" autocomplete="off">
|
|
780
|
+
</label>
|
|
781
|
+
<div class="bot-form-err" id="nbErr" hidden></div>
|
|
782
|
+
</div>
|
|
783
|
+
<div class="modal-actions">
|
|
784
|
+
<button class="btn" id="nbCancel">取消</button>
|
|
785
|
+
<button class="btn primary" id="nbOk">创建并连接</button>
|
|
786
|
+
</div>
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
789
|
+
|
|
790
|
+
<!-- 插件设置:配置 + 玩家数据 -->
|
|
791
|
+
<div class="modal-mask" id="pluginPanelMask" hidden>
|
|
792
|
+
<div class="modal wide" role="dialog" aria-modal="true" aria-labelledby="ppTitle">
|
|
793
|
+
<h3 class="modal-title" id="ppTitle">插件设置</h3>
|
|
794
|
+
<div class="pp-tabs">
|
|
795
|
+
<button type="button" class="pp-tab active" data-pp="config">配置</button>
|
|
796
|
+
<button type="button" class="pp-tab" data-pp="data">玩家数据</button>
|
|
797
|
+
<button type="button" class="pp-tab" data-pp="dash">运行数据</button>
|
|
798
|
+
<button type="button" class="pp-tab" data-pp="groups">分群开关</button>
|
|
799
|
+
</div>
|
|
800
|
+
<div id="ppConfig" class="pp-body"></div>
|
|
801
|
+
<div id="ppData" class="pp-body" hidden></div>
|
|
802
|
+
<div id="ppDash" class="pp-body" hidden></div>
|
|
803
|
+
<div id="ppGroups" class="pp-body" hidden></div>
|
|
804
|
+
<div class="modal-actions">
|
|
805
|
+
<button class="btn" id="ppClose">关闭</button>
|
|
806
|
+
<button class="btn danger" id="ppReset" title="把所有配置项恢复成插件声明的默认值">恢复默认</button>
|
|
807
|
+
<button class="btn primary" id="ppSave">保存配置</button>
|
|
808
|
+
</div>
|
|
809
|
+
</div>
|
|
810
|
+
</div>
|
|
811
|
+
|
|
812
|
+
<script src="/vendor/qrcode.js"></script>
|
|
813
|
+
<script src="/app.js"></script>
|
|
814
|
+
</body>
|
|
815
|
+
</html>
|