koishi-plugin-adapter-onebot-multi 0.0.11 → 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.
Files changed (2) hide show
  1. package/lib/index.js +145 -35
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1628,6 +1628,32 @@ 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
+ });
1631
1657
  router.post(`${adminPath}/api/bots/profile`, authMiddleware, async (ctx) => {
1632
1658
  const data = await this.parseJsonBody(ctx);
1633
1659
  const selfId = String(data.selfId);
@@ -1975,30 +2001,67 @@ var StatusPanel = class {
1975
2001
  </div>
1976
2002
  </div>
1977
2003
 
1978
- <!-- 编辑 Bot 模态框 -->
1979
- <div class="modal" id="editModal">
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">
1980
2043
  <div class="modal-content">
1981
- <h2>编辑 Bot 资料</h2>
1982
- <form id="editForm">
1983
- <input type="hidden" id="editSelfId">
2044
+ <h2>修改 Bot 资料</h2>
2045
+ <form id="profileForm">
2046
+ <input type="hidden" id="profileSelfId">
1984
2047
  <div class="form-group">
1985
- <label for="editNickname">昵称</label>
1986
- <input type="text" id="editNickname" placeholder="新的QQ昵称">
2048
+ <label for="profileNickname">昵称</label>
2049
+ <input type="text" id="profileNickname" placeholder="新的QQ昵称">
1987
2050
  </div>
1988
2051
  <div class="form-group">
1989
- <label for="editAvatar">头像</label>
1990
- <input type="file" id="editAvatar" accept="image/*" style="display:none">
2052
+ <label for="profileAvatar">头像</label>
2053
+ <input type="file" id="profileAvatar" accept="image/*" style="display:none">
1991
2054
  <div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;">
1992
2055
  <img id="avatarPreview" style="width:64px;height:64px;border:var(--nl-border);border-radius:50%;object-fit:cover;">
1993
- <button type="button" class="btn btn-secondary" onclick="document.getElementById('editAvatar').click()" style="padding:0.5rem 1rem;">选择图片</button>
2056
+ <button type="button" class="btn btn-secondary" onclick="document.getElementById('profileAvatar').click()" style="padding:0.5rem 1rem;">选择图片</button>
1994
2057
  <span id="avatarFileName" style="font-size:0.85rem;color:#92400e;"></span>
1995
2058
  </div>
1996
2059
  <p style="font-size:0.8rem;color:#92400e;margin-top:0.5rem;">支持本地图片或输入图片URL</p>
1997
- <input type="text" id="editAvatarUrl" placeholder="或输入图片URL" style="margin-top:0.5rem;">
2060
+ <input type="text" id="profileAvatarUrl" placeholder="或输入图片URL" style="margin-top:0.5rem;">
1998
2061
  </div>
1999
2062
  <div class="modal-actions">
2000
2063
  <button type="submit" class="btn">保存</button>
2001
- <button type="button" class="btn btn-secondary" onclick="hideEditModal()">取消</button>
2064
+ <button type="button" class="btn btn-secondary" onclick="hideProfileModal()">取消</button>
2002
2065
  </div>
2003
2066
  </form>
2004
2067
  </div>
@@ -2212,8 +2275,9 @@ var StatusPanel = class {
2212
2275
  '<div class="bot-actions">' +
2213
2276
  '<button class="btn btn-secondary" onclick="toggleBot(' + bot.id + ')">' + (bot.enabled ? '禁用' : '启用') + '</button>' +
2214
2277
  '<button class="btn btn-secondary" onclick="restartBot(' + bot.id + ')">重启</button>' +
2215
- (bot.status === 'online' ? '<button class="btn btn-secondary" onclick="showEditModal(\\'' + bot.selfId + '\\', \\'' + (bot.nickname || '').replace(/'/g, "\\\\'") + '\\')">编辑</button>' : '') +
2216
- '<button class="btn btn-danger" onclick="deleteBot(' + bot.id + ', \\'' + bot.name + '\\')">删除</button>' +
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>' +
2217
2281
  '</div>' +
2218
2282
  '</div>'
2219
2283
  }).join('')
@@ -2296,29 +2360,75 @@ var StatusPanel = class {
2296
2360
  }
2297
2361
  })
2298
2362
 
2299
- // 编辑 Bot 模态框
2300
- let editAvatarFile = null
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
2301
2411
 
2302
- function showEditModal(selfId, nickname) {
2303
- document.getElementById('editSelfId').value = selfId
2304
- document.getElementById('editNickname').value = nickname || ''
2412
+ function showProfileModal(selfId, nickname) {
2413
+ document.getElementById('profileSelfId').value = selfId
2414
+ document.getElementById('profileNickname').value = nickname || ''
2305
2415
  document.getElementById('avatarPreview').src = 'http://q.qlogo.cn/headimg_dl?dst_uin=' + selfId + '&spec=640'
2306
2416
  document.getElementById('avatarFileName').textContent = ''
2307
- document.getElementById('editAvatarUrl').value = ''
2308
- editAvatarFile = null
2309
- document.getElementById('editModal').classList.add('active')
2417
+ document.getElementById('profileAvatarUrl').value = ''
2418
+ profileAvatarFile = null
2419
+ document.getElementById('profileModal').classList.add('active')
2310
2420
  }
2311
2421
 
2312
- function hideEditModal() {
2313
- document.getElementById('editModal').classList.remove('active')
2314
- editAvatarFile = null
2422
+ function hideProfileModal() {
2423
+ document.getElementById('profileModal').classList.remove('active')
2424
+ profileAvatarFile = null
2315
2425
  }
2316
2426
 
2317
2427
  // 头像文件选择
2318
- document.getElementById('editAvatar').addEventListener('change', function(e) {
2428
+ document.getElementById('profileAvatar').addEventListener('change', function(e) {
2319
2429
  const file = e.target.files[0]
2320
2430
  if (file) {
2321
- editAvatarFile = file
2431
+ profileAvatarFile = file
2322
2432
  document.getElementById('avatarFileName').textContent = file.name
2323
2433
  // 预览
2324
2434
  const reader = new FileReader()
@@ -2329,12 +2439,12 @@ var StatusPanel = class {
2329
2439
  }
2330
2440
  })
2331
2441
 
2332
- // 编辑表单提交
2333
- document.getElementById('editForm').addEventListener('submit', async (e) => {
2442
+ // 资料表单提交
2443
+ document.getElementById('profileForm').addEventListener('submit', async (e) => {
2334
2444
  e.preventDefault()
2335
- const selfId = document.getElementById('editSelfId').value
2336
- const nickname = document.getElementById('editNickname').value
2337
- const avatarUrl = document.getElementById('editAvatarUrl').value
2445
+ const selfId = document.getElementById('profileSelfId').value
2446
+ const nickname = document.getElementById('profileNickname').value
2447
+ const avatarUrl = document.getElementById('profileAvatarUrl').value
2338
2448
 
2339
2449
  let hasChange = false
2340
2450
 
@@ -2350,7 +2460,7 @@ var StatusPanel = class {
2350
2460
  }
2351
2461
 
2352
2462
  // 修改头像
2353
- if (editAvatarFile) {
2463
+ if (profileAvatarFile) {
2354
2464
  // 本地文件转 base64
2355
2465
  const reader = new FileReader()
2356
2466
  reader.onload = async function(ev) {
@@ -2362,7 +2472,7 @@ var StatusPanel = class {
2362
2472
  showToast('头像修改失败: ' + e.message, 'error')
2363
2473
  }
2364
2474
  }
2365
- reader.readAsDataURL(editAvatarFile)
2475
+ reader.readAsDataURL(profileAvatarFile)
2366
2476
  hasChange = true
2367
2477
  } else if (avatarUrl) {
2368
2478
  // URL 方式
@@ -2376,7 +2486,7 @@ var StatusPanel = class {
2376
2486
  }
2377
2487
 
2378
2488
  if (hasChange) {
2379
- hideEditModal()
2489
+ hideProfileModal()
2380
2490
  setTimeout(refreshBots, 1000)
2381
2491
  } else {
2382
2492
  showToast('未做任何修改', 'error')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-adapter-onebot-multi",
3
3
  "description": "奶龙bot定制版onebot适配器,支持自动负载均衡,适配器级黑名单/白名单,提供webui,可指定端口",
4
- "version": "0.0.11",
4
+ "version": "0.0.12",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [