koishi-plugin-adapter-onebot-multi 0.0.10 → 0.0.12
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/lib/index.js +273 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1628,6 +1628,77 @@ var StatusPanel = class {
|
|
|
1628
1628
|
this.ctx.logger.info(`重启 Bot 配置: #${id} ${config.name}`);
|
|
1629
1629
|
ctx.body = { success: true };
|
|
1630
1630
|
});
|
|
1631
|
+
router.post(`${adminPath}/api/bots/update`, authMiddleware, async (ctx) => {
|
|
1632
|
+
const data = await this.parseJsonBody(ctx);
|
|
1633
|
+
const id = Number(data.id);
|
|
1634
|
+
const existing = await this.configManager.getConfigById(id);
|
|
1635
|
+
if (!existing) {
|
|
1636
|
+
ctx.status = 404;
|
|
1637
|
+
ctx.body = { error: `配置 #${id} 不存在` };
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
const updates = {};
|
|
1641
|
+
if (data.name !== void 0) updates.name = data.name;
|
|
1642
|
+
if (data.protocol !== void 0) updates.protocol = data.protocol;
|
|
1643
|
+
if (data.endpoint !== void 0) updates.endpoint = data.endpoint;
|
|
1644
|
+
if (data.path !== void 0) updates.path = data.path;
|
|
1645
|
+
if (data.token !== void 0) updates.token = data.token;
|
|
1646
|
+
await this.configManager.updateConfigById(id, updates);
|
|
1647
|
+
this.ctx.logger.info(`更新 Bot 配置: #${id} ${existing.name}`);
|
|
1648
|
+
if (existing.enabled && existing.selfId) {
|
|
1649
|
+
await this.stopBot(existing.selfId);
|
|
1650
|
+
const newConfig = await this.configManager.getConfigById(id);
|
|
1651
|
+
if (newConfig) {
|
|
1652
|
+
await this.startBot(this.configManager.toBotConfig(newConfig));
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
ctx.body = { success: true };
|
|
1656
|
+
});
|
|
1657
|
+
router.post(`${adminPath}/api/bots/profile`, authMiddleware, async (ctx) => {
|
|
1658
|
+
const data = await this.parseJsonBody(ctx);
|
|
1659
|
+
const selfId = String(data.selfId);
|
|
1660
|
+
const nickname = data.nickname || "";
|
|
1661
|
+
const bot = this.ctx.bots.find((b) => b.selfId === selfId && b.platform === "onebot");
|
|
1662
|
+
if (!bot) {
|
|
1663
|
+
ctx.status = 404;
|
|
1664
|
+
ctx.body = { error: `Bot ${selfId} 未在线` };
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
try {
|
|
1668
|
+
await bot.internal.setQqProfile(nickname, "", "", "", "");
|
|
1669
|
+
this.ctx.logger.info(`修改 Bot ${selfId} 昵称为: ${nickname}`);
|
|
1670
|
+
ctx.body = { success: true };
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
this.ctx.logger.error("修改资料失败:", error);
|
|
1673
|
+
ctx.status = 500;
|
|
1674
|
+
ctx.body = { error: "修改失败: " + error.message };
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
router.post(`${adminPath}/api/bots/avatar`, authMiddleware, async (ctx) => {
|
|
1678
|
+
const data = await this.parseJsonBody(ctx);
|
|
1679
|
+
const selfId = String(data.selfId);
|
|
1680
|
+
const file = data.file;
|
|
1681
|
+
const bot = this.ctx.bots.find((b) => b.selfId === selfId && b.platform === "onebot");
|
|
1682
|
+
if (!bot) {
|
|
1683
|
+
ctx.status = 404;
|
|
1684
|
+
ctx.body = { error: `Bot ${selfId} 未在线` };
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
if (!file) {
|
|
1688
|
+
ctx.status = 400;
|
|
1689
|
+
ctx.body = { error: "请提供图片" };
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
try {
|
|
1693
|
+
await bot.internal.setQqAvatar(file);
|
|
1694
|
+
this.ctx.logger.info(`修改 Bot ${selfId} 头像`);
|
|
1695
|
+
ctx.body = { success: true };
|
|
1696
|
+
} catch (error) {
|
|
1697
|
+
this.ctx.logger.error("修改头像失败:", error);
|
|
1698
|
+
ctx.status = 500;
|
|
1699
|
+
ctx.body = { error: "修改失败: " + error.message };
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1631
1702
|
if (this.config.port) {
|
|
1632
1703
|
this.app = new import_koa.default();
|
|
1633
1704
|
this.app.use(router.routes());
|
|
@@ -1930,6 +2001,72 @@ var StatusPanel = class {
|
|
|
1930
2001
|
</div>
|
|
1931
2002
|
</div>
|
|
1932
2003
|
|
|
2004
|
+
<!-- 编辑 Bot 配置模态框 -->
|
|
2005
|
+
<div class="modal" id="configModal">
|
|
2006
|
+
<div class="modal-content">
|
|
2007
|
+
<h2>编辑 Bot 配置</h2>
|
|
2008
|
+
<form id="configForm">
|
|
2009
|
+
<input type="hidden" id="configId">
|
|
2010
|
+
<div class="form-group">
|
|
2011
|
+
<label for="configEditName">配置名称 *</label>
|
|
2012
|
+
<input type="text" id="configEditName" required placeholder="例如: 主号、小号">
|
|
2013
|
+
</div>
|
|
2014
|
+
<div class="form-group">
|
|
2015
|
+
<label for="configProtocol">协议</label>
|
|
2016
|
+
<select id="configProtocol" onchange="toggleConfigEndpoint()">
|
|
2017
|
+
<option value="ws-reverse">反向 WebSocket (ws-reverse)</option>
|
|
2018
|
+
<option value="ws">正向 WebSocket (ws)</option>
|
|
2019
|
+
</select>
|
|
2020
|
+
</div>
|
|
2021
|
+
<div class="form-group" id="configEndpointGroup" style="display: none;">
|
|
2022
|
+
<label for="configEndpoint">Endpoint *</label>
|
|
2023
|
+
<input type="text" id="configEndpoint" placeholder="例如: ws://127.0.0.1:6700">
|
|
2024
|
+
</div>
|
|
2025
|
+
<div class="form-group" id="configPathGroup">
|
|
2026
|
+
<label for="configPath">路径</label>
|
|
2027
|
+
<input type="text" id="configPath" placeholder="例如: /onebot">
|
|
2028
|
+
</div>
|
|
2029
|
+
<div class="form-group">
|
|
2030
|
+
<label for="configToken">Token(可选)</label>
|
|
2031
|
+
<input type="password" id="configToken" placeholder="访问令牌(留空不修改)">
|
|
2032
|
+
</div>
|
|
2033
|
+
<div class="modal-actions">
|
|
2034
|
+
<button type="submit" class="btn">保存</button>
|
|
2035
|
+
<button type="button" class="btn btn-secondary" onclick="hideConfigModal()">取消</button>
|
|
2036
|
+
</div>
|
|
2037
|
+
</form>
|
|
2038
|
+
</div>
|
|
2039
|
+
</div>
|
|
2040
|
+
|
|
2041
|
+
<!-- 修改 Bot 资料模态框 -->
|
|
2042
|
+
<div class="modal" id="profileModal">
|
|
2043
|
+
<div class="modal-content">
|
|
2044
|
+
<h2>修改 Bot 资料</h2>
|
|
2045
|
+
<form id="profileForm">
|
|
2046
|
+
<input type="hidden" id="profileSelfId">
|
|
2047
|
+
<div class="form-group">
|
|
2048
|
+
<label for="profileNickname">昵称</label>
|
|
2049
|
+
<input type="text" id="profileNickname" placeholder="新的QQ昵称">
|
|
2050
|
+
</div>
|
|
2051
|
+
<div class="form-group">
|
|
2052
|
+
<label for="profileAvatar">头像</label>
|
|
2053
|
+
<input type="file" id="profileAvatar" accept="image/*" style="display:none">
|
|
2054
|
+
<div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;">
|
|
2055
|
+
<img id="avatarPreview" style="width:64px;height:64px;border:var(--nl-border);border-radius:50%;object-fit:cover;">
|
|
2056
|
+
<button type="button" class="btn btn-secondary" onclick="document.getElementById('profileAvatar').click()" style="padding:0.5rem 1rem;">选择图片</button>
|
|
2057
|
+
<span id="avatarFileName" style="font-size:0.85rem;color:#92400e;"></span>
|
|
2058
|
+
</div>
|
|
2059
|
+
<p style="font-size:0.8rem;color:#92400e;margin-top:0.5rem;">支持本地图片或输入图片URL</p>
|
|
2060
|
+
<input type="text" id="profileAvatarUrl" placeholder="或输入图片URL" style="margin-top:0.5rem;">
|
|
2061
|
+
</div>
|
|
2062
|
+
<div class="modal-actions">
|
|
2063
|
+
<button type="submit" class="btn">保存</button>
|
|
2064
|
+
<button type="button" class="btn btn-secondary" onclick="hideProfileModal()">取消</button>
|
|
2065
|
+
</div>
|
|
2066
|
+
</form>
|
|
2067
|
+
</div>
|
|
2068
|
+
</div>
|
|
2069
|
+
|
|
1933
2070
|
<!-- Toast -->
|
|
1934
2071
|
<div class="toast" id="toast"></div>
|
|
1935
2072
|
|
|
@@ -2138,7 +2275,9 @@ var StatusPanel = class {
|
|
|
2138
2275
|
'<div class="bot-actions">' +
|
|
2139
2276
|
'<button class="btn btn-secondary" onclick="toggleBot(' + bot.id + ')">' + (bot.enabled ? '禁用' : '启用') + '</button>' +
|
|
2140
2277
|
'<button class="btn btn-secondary" onclick="restartBot(' + bot.id + ')">重启</button>' +
|
|
2141
|
-
'<button class="btn btn-
|
|
2278
|
+
'<button class="btn btn-secondary" onclick="showConfigModal(' + bot.id + ', \\'' + bot.name.replace(/'/g, "\\\\'") + '\\', \\'' + (bot.protocol || 'ws-reverse') + '\\', \\'' + (bot.endpoint || '').replace(/'/g, "\\\\'") + '\\', \\'' + (bot.path || '/onebot').replace(/'/g, "\\\\'") + '\\')">配置</button>' +
|
|
2279
|
+
(bot.status === 'online' ? '<button class="btn btn-secondary" onclick="showProfileModal(\\'' + bot.selfId + '\\', \\'' + (bot.nickname || '').replace(/'/g, "\\\\'") + '\\')">资料</button>' : '') +
|
|
2280
|
+
'<button class="btn btn-danger" onclick="deleteBot(' + bot.id + ', \\'' + bot.name.replace(/'/g, "\\\\'") + '\\')">删除</button>' +
|
|
2142
2281
|
'</div>' +
|
|
2143
2282
|
'</div>'
|
|
2144
2283
|
}).join('')
|
|
@@ -2221,6 +2360,139 @@ var StatusPanel = class {
|
|
|
2221
2360
|
}
|
|
2222
2361
|
})
|
|
2223
2362
|
|
|
2363
|
+
// 编辑 Bot 配置模态框
|
|
2364
|
+
function showConfigModal(id, name, protocol, endpoint, path) {
|
|
2365
|
+
document.getElementById('configId').value = id
|
|
2366
|
+
document.getElementById('configEditName').value = name || ''
|
|
2367
|
+
document.getElementById('configProtocol').value = protocol || 'ws-reverse'
|
|
2368
|
+
document.getElementById('configEndpoint').value = endpoint || ''
|
|
2369
|
+
document.getElementById('configPath').value = path || '/onebot'
|
|
2370
|
+
document.getElementById('configToken').value = ''
|
|
2371
|
+
toggleConfigEndpoint()
|
|
2372
|
+
document.getElementById('configModal').classList.add('active')
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
function hideConfigModal() {
|
|
2376
|
+
document.getElementById('configModal').classList.remove('active')
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
function toggleConfigEndpoint() {
|
|
2380
|
+
const protocol = document.getElementById('configProtocol').value
|
|
2381
|
+
document.getElementById('configEndpointGroup').style.display = protocol === 'ws' ? 'block' : 'none'
|
|
2382
|
+
document.getElementById('configPathGroup').style.display = protocol === 'ws-reverse' ? 'block' : 'none'
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
document.getElementById('configForm').addEventListener('submit', async (e) => {
|
|
2386
|
+
e.preventDefault()
|
|
2387
|
+
const id = document.getElementById('configId').value
|
|
2388
|
+
const data = {
|
|
2389
|
+
id: Number(id),
|
|
2390
|
+
name: document.getElementById('configEditName').value,
|
|
2391
|
+
protocol: document.getElementById('configProtocol').value,
|
|
2392
|
+
endpoint: document.getElementById('configEndpoint').value || undefined,
|
|
2393
|
+
path: document.getElementById('configPath').value || undefined,
|
|
2394
|
+
}
|
|
2395
|
+
// Token 留空不修改
|
|
2396
|
+
const token = document.getElementById('configToken').value
|
|
2397
|
+
if (token) data.token = token
|
|
2398
|
+
|
|
2399
|
+
try {
|
|
2400
|
+
await api('/bots/update', data)
|
|
2401
|
+
showToast('配置更新成功')
|
|
2402
|
+
hideConfigModal()
|
|
2403
|
+
refreshBots()
|
|
2404
|
+
} catch (e) {
|
|
2405
|
+
showToast('更新失败: ' + e.message, 'error')
|
|
2406
|
+
}
|
|
2407
|
+
})
|
|
2408
|
+
|
|
2409
|
+
// 修改 Bot 资料模态框
|
|
2410
|
+
let profileAvatarFile = null
|
|
2411
|
+
|
|
2412
|
+
function showProfileModal(selfId, nickname) {
|
|
2413
|
+
document.getElementById('profileSelfId').value = selfId
|
|
2414
|
+
document.getElementById('profileNickname').value = nickname || ''
|
|
2415
|
+
document.getElementById('avatarPreview').src = 'http://q.qlogo.cn/headimg_dl?dst_uin=' + selfId + '&spec=640'
|
|
2416
|
+
document.getElementById('avatarFileName').textContent = ''
|
|
2417
|
+
document.getElementById('profileAvatarUrl').value = ''
|
|
2418
|
+
profileAvatarFile = null
|
|
2419
|
+
document.getElementById('profileModal').classList.add('active')
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
function hideProfileModal() {
|
|
2423
|
+
document.getElementById('profileModal').classList.remove('active')
|
|
2424
|
+
profileAvatarFile = null
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// 头像文件选择
|
|
2428
|
+
document.getElementById('profileAvatar').addEventListener('change', function(e) {
|
|
2429
|
+
const file = e.target.files[0]
|
|
2430
|
+
if (file) {
|
|
2431
|
+
profileAvatarFile = file
|
|
2432
|
+
document.getElementById('avatarFileName').textContent = file.name
|
|
2433
|
+
// 预览
|
|
2434
|
+
const reader = new FileReader()
|
|
2435
|
+
reader.onload = function(ev) {
|
|
2436
|
+
document.getElementById('avatarPreview').src = ev.target.result
|
|
2437
|
+
}
|
|
2438
|
+
reader.readAsDataURL(file)
|
|
2439
|
+
}
|
|
2440
|
+
})
|
|
2441
|
+
|
|
2442
|
+
// 资料表单提交
|
|
2443
|
+
document.getElementById('profileForm').addEventListener('submit', async (e) => {
|
|
2444
|
+
e.preventDefault()
|
|
2445
|
+
const selfId = document.getElementById('profileSelfId').value
|
|
2446
|
+
const nickname = document.getElementById('profileNickname').value
|
|
2447
|
+
const avatarUrl = document.getElementById('profileAvatarUrl').value
|
|
2448
|
+
|
|
2449
|
+
let hasChange = false
|
|
2450
|
+
|
|
2451
|
+
// 修改昵称
|
|
2452
|
+
if (nickname) {
|
|
2453
|
+
try {
|
|
2454
|
+
await api('/bots/profile', { selfId, nickname })
|
|
2455
|
+
showToast('昵称修改成功')
|
|
2456
|
+
hasChange = true
|
|
2457
|
+
} catch (e) {
|
|
2458
|
+
showToast('昵称修改失败: ' + e.message, 'error')
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
// 修改头像
|
|
2463
|
+
if (profileAvatarFile) {
|
|
2464
|
+
// 本地文件转 base64
|
|
2465
|
+
const reader = new FileReader()
|
|
2466
|
+
reader.onload = async function(ev) {
|
|
2467
|
+
try {
|
|
2468
|
+
await api('/bots/avatar', { selfId, file: ev.target.result })
|
|
2469
|
+
showToast('头像修改成功')
|
|
2470
|
+
refreshBots()
|
|
2471
|
+
} catch (e) {
|
|
2472
|
+
showToast('头像修改失败: ' + e.message, 'error')
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
reader.readAsDataURL(profileAvatarFile)
|
|
2476
|
+
hasChange = true
|
|
2477
|
+
} else if (avatarUrl) {
|
|
2478
|
+
// URL 方式
|
|
2479
|
+
try {
|
|
2480
|
+
await api('/bots/avatar', { selfId, file: avatarUrl })
|
|
2481
|
+
showToast('头像修改成功')
|
|
2482
|
+
hasChange = true
|
|
2483
|
+
} catch (e) {
|
|
2484
|
+
showToast('头像修改失败: ' + e.message, 'error')
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (hasChange) {
|
|
2489
|
+
hideProfileModal()
|
|
2490
|
+
setTimeout(refreshBots, 1000)
|
|
2491
|
+
} else {
|
|
2492
|
+
showToast('未做任何修改', 'error')
|
|
2493
|
+
}
|
|
2494
|
+
})
|
|
2495
|
+
|
|
2224
2496
|
// 自动刷新
|
|
2225
2497
|
setInterval(() => {
|
|
2226
2498
|
if (document.getElementById('adminView').classList.contains('show')) {
|
package/package.json
CHANGED