koishi-plugin-adapter-onebot-multi 1.0.0 → 1.0.2
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/client/page.vue +89 -13
- package/dist/index.js +7 -5
- package/dist/style.css +1 -1
- package/lib/config-store.d.ts +14 -0
- package/lib/index.js +108 -8
- package/package.json +1 -1
package/client/page.vue
CHANGED
|
@@ -150,18 +150,27 @@
|
|
|
150
150
|
</div>
|
|
151
151
|
|
|
152
152
|
<div class="split-grid">
|
|
153
|
-
<
|
|
154
|
-
群黑名单
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
153
|
+
<div class="pop-label">
|
|
154
|
+
群黑名单
|
|
155
|
+
<div class="list-summary-box">
|
|
156
|
+
<span class="list-count">已配置 {{ countLines(blacklistText) }} 个群</span>
|
|
157
|
+
<button class="pop-btn mini action-btn" @click="openListEditor('blacklist')">编辑</button>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="pop-label">
|
|
161
|
+
群白名单
|
|
162
|
+
<div class="list-summary-box">
|
|
163
|
+
<span class="list-count">已配置 {{ countLines(whitelistText) }} 个群</span>
|
|
164
|
+
<button class="pop-btn mini action-btn" @click="openListEditor('whitelist')">编辑</button>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="pop-label">
|
|
168
|
+
优先群聊
|
|
169
|
+
<div class="list-summary-box">
|
|
170
|
+
<span class="list-count">已配置 {{ countLines(priorityText) }} 个群</span>
|
|
171
|
+
<button class="pop-btn mini action-btn" @click="openListEditor('priority')">编辑</button>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
165
174
|
|
|
166
175
|
<div class="pop-table-editor">
|
|
167
176
|
<div class="table-head">
|
|
@@ -268,6 +277,20 @@
|
|
|
268
277
|
</div>
|
|
269
278
|
</div>
|
|
270
279
|
|
|
280
|
+
<!-- List Editor Modal -->
|
|
281
|
+
<div v-if="listEditorTarget" class="pop-modal-overlay" @click.self="listEditorTarget = null">
|
|
282
|
+
<div class="pop-modal comic-panel">
|
|
283
|
+
<div class="comic-burst" style="background: var(--pop-secondary); color: var(--pop-text);">✎</div>
|
|
284
|
+
<h3>{{ listEditorTitle }}</h3>
|
|
285
|
+
<p class="modal-sub">每行输入一个群号(仅保留数字)</p>
|
|
286
|
+
<textarea v-model="listEditorText" rows="10" class="pop-textarea" style="width: 100%;"></textarea>
|
|
287
|
+
<div class="modal-actions">
|
|
288
|
+
<button class="pop-btn primary-btn" @click="saveListEditor">确认保存</button>
|
|
289
|
+
<button class="pop-btn" @click="listEditorTarget = null">取消</button>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
|
|
271
294
|
<!-- Toast -->
|
|
272
295
|
<div v-if="toast.show" class="pop-toast comic-panel" :class="toast.type">
|
|
273
296
|
<span v-if="toast.type === 'success'">✓</span>
|
|
@@ -279,7 +302,7 @@
|
|
|
279
302
|
</template>
|
|
280
303
|
|
|
281
304
|
<script setup lang="ts">
|
|
282
|
-
import { onMounted, onUnmounted, reactive, ref } from 'vue'
|
|
305
|
+
import { onMounted, onUnmounted, reactive, ref, computed } from 'vue'
|
|
283
306
|
import { send } from '@koishijs/client'
|
|
284
307
|
|
|
285
308
|
type BotStatus = 'online' | 'offline' | 'connecting'
|
|
@@ -359,6 +382,9 @@ const priorityText = ref('')
|
|
|
359
382
|
const botMaxLoadRows = ref<Array<{ botId: string, maxLoad: number }>>([])
|
|
360
383
|
const channelPriorityRows = ref<Array<{ channelId: string, botIds: string[] }>>([])
|
|
361
384
|
|
|
385
|
+
const listEditorTarget = ref<'blacklist' | 'whitelist' | 'priority' | null>(null)
|
|
386
|
+
const listEditorText = ref('')
|
|
387
|
+
|
|
362
388
|
const editingMode = ref<'create' | 'edit'>('create')
|
|
363
389
|
const editingOldSelfId = ref('')
|
|
364
390
|
const editing = ref<ManagedBot | null>(null)
|
|
@@ -385,6 +411,39 @@ function lineArray(value: string) {
|
|
|
385
411
|
.filter(Boolean)
|
|
386
412
|
}
|
|
387
413
|
|
|
414
|
+
function countLines(text: string) {
|
|
415
|
+
return lineArray(text).length
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const listEditorTitle = computed(() => {
|
|
419
|
+
if (listEditorTarget.value === 'blacklist') return '编辑群黑名单'
|
|
420
|
+
if (listEditorTarget.value === 'whitelist') return '编辑群白名单'
|
|
421
|
+
if (listEditorTarget.value === 'priority') return '编辑优先群聊'
|
|
422
|
+
return '编辑列表'
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
function openListEditor(target: 'blacklist' | 'whitelist' | 'priority') {
|
|
426
|
+
listEditorTarget.value = target
|
|
427
|
+
if (target === 'blacklist') listEditorText.value = blacklistText.value
|
|
428
|
+
else if (target === 'whitelist') listEditorText.value = whitelistText.value
|
|
429
|
+
else if (target === 'priority') listEditorText.value = priorityText.value
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function saveListEditor() {
|
|
433
|
+
const filtered = listEditorText.value
|
|
434
|
+
.split('\n')
|
|
435
|
+
.map(v => v.trim())
|
|
436
|
+
.filter(v => /^\d+$/.test(v))
|
|
437
|
+
.join('\n')
|
|
438
|
+
|
|
439
|
+
if (listEditorTarget.value === 'blacklist') blacklistText.value = filtered
|
|
440
|
+
else if (listEditorTarget.value === 'whitelist') whitelistText.value = filtered
|
|
441
|
+
else if (listEditorTarget.value === 'priority') priorityText.value = filtered
|
|
442
|
+
|
|
443
|
+
listEditorTarget.value = null
|
|
444
|
+
showToast('success', '列表已暂存,请点击保存规则生效')
|
|
445
|
+
}
|
|
446
|
+
|
|
388
447
|
function showToast(type: 'success' | 'error', message: string) {
|
|
389
448
|
toast.type = type
|
|
390
449
|
toast.message = message
|
|
@@ -916,6 +975,23 @@ onUnmounted(() => {
|
|
|
916
975
|
/* SPLIT GRID FOR BALANCE */
|
|
917
976
|
.split-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-bottom: 24px; }
|
|
918
977
|
|
|
978
|
+
.list-summary-box {
|
|
979
|
+
display: flex;
|
|
980
|
+
align-items: center;
|
|
981
|
+
justify-content: space-between;
|
|
982
|
+
background: #fff;
|
|
983
|
+
border: 3px solid var(--pop-text);
|
|
984
|
+
border-radius: 12px;
|
|
985
|
+
padding: 8px 12px;
|
|
986
|
+
box-shadow: 2px 2px 0 var(--pop-shadow-color);
|
|
987
|
+
margin-top: 4px;
|
|
988
|
+
}
|
|
989
|
+
.list-count {
|
|
990
|
+
font-size: 14px;
|
|
991
|
+
font-weight: 900;
|
|
992
|
+
color: var(--pop-primary);
|
|
993
|
+
}
|
|
994
|
+
|
|
919
995
|
/* TABLE EDITOR */
|
|
920
996
|
.pop-table-editor {
|
|
921
997
|
border: 3px dashed var(--pop-text); background: var(--pop-secondary); border-radius: 16px;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import{send as
|
|
2
|
-
`).map(
|
|
3
|
-
`)
|
|
4
|
-
`),
|
|
5
|
-
`),B.value=Object.entries(b.botMaxLoad||{}).map(([n,e])=>({botId:n,maxLoad:Number(e)||0})),U.value=Object.entries(b.channelBotPriority||{}).map(([n,e])=>({channelId:n,botIds:Array.isArray(e)?[...e]:[]}))}function Y(){B.value.push({botId:"",maxLoad:0})}function Z(n){B.value.splice(n,1)}function ee(){U.value.push({channelId:"",botIds:[]})}function te(n){U.value.splice(n,1)}async function k(){if(!W){W=true;try{const n=await g("onebot-multi/state");_.value=(n==null?void 0:n.bots)||[],Object.assign(m,(n==null?void 0:n.runtime)||{}),Object.assign(b,(n==null?void 0:n.loadBalance)||{}),Q()}catch(n){c("error",(n==null?void 0:n.message)||"刷新失败")}finally{W=false}}}function le(){R.value="create",F.value="",i.value={token:"",protocol:"ws-reverse",endpoint:"",path:"/onebot",name:"",enabled:true}}function ne(n){R.value="edit",F.value=n.selfId,i.value={...n}}async function oe(){if(i.value)try{R.value==="create"?await g("onebot-multi/bots/create",i.value):await g("onebot-multi/bots/update",{oldSelfId:F.value,bot:i.value}),i.value=null,await k(),c("success","保存成功")}catch(n){c("error",(n==null?void 0:n.message)||"保存失败")}}async function se(n){if(confirm(`确认删除 Bot ${n.selfId} 吗?`))try{await g("onebot-multi/bots/delete",{selfId:n.selfId}),await k(),c("success","删除成功")}catch(e){c("error",(e==null?void 0:e.message)||"删除失败")}}async function ae(n){try{await g("onebot-multi/bots/toggle",{selfId:n.selfId}),await k(),c("success","状态已更新")}catch(e){c("error",(e==null?void 0:e.message)||"更新失败")}}async function ie(n){try{await g("onebot-multi/bots/restart",{selfId:n.selfId}),await k(),c("success","重启已触发")}catch(e){c("error",(e==null?void 0:e.message)||"重启失败")}}function ue(n){w.value=n,N.value=n.nickname||""}async function pe(){if(w.value)try{const n=await g("onebot-multi/bots/profile",{selfId:w.value.selfId,nickname:N.value});if(!(n!=null&&n.success))throw new Error((n==null?void 0:n.error)||"保存失败");w.value=null,await k(),c("success","昵称已更新")}catch(n){c("error",(n==null?void 0:n.message)||"更新失败")}}function de(n){I.value=n,T.value=""}function re(n){var d;const M=(d=n.target.files)==null?void 0:d[0];if(!M){T.value="";return}const l=new FileReader;l.onload=s=>{var D;T.value=(D=s.target)==null?void 0:D.result},l.readAsDataURL(M)}async function ce(){if(!I.value||!T.value.trim()){c("error","请先选择图片文件");return}try{const n=await g("onebot-multi/bots/avatar",{selfId:I.value.selfId,file:T.value});if(!(n!=null&&n.success))throw new Error((n==null?void 0:n.error)||"保存失败");I.value=null,c("success","头像已更新")}catch(n){c("error",(n==null?void 0:n.message)||"更新失败")}}async function ve(){try{await g("onebot-multi/settings/runtime/update",{...m}),await k(),c("success","运行时设置已保存")}catch(n){c("error",(n==null?void 0:n.message)||"保存失败")}}async function be(){try{const n={};for(const l of B.value){const d=l.botId.trim();if(!d)continue;const s=Math.max(0,Number(l.maxLoad||0));n[d]=s}const e={};for(const l of U.value){const d=l.channelId.trim();if(!d)continue;const s=(l.botIds||[]).filter(Boolean);s.length>0&&(e[d]=s)}const M={...b,channelBlacklist:z(E.value),channelWhitelist:z(S.value),priorityChannels:z(O.value),botMaxLoad:n,channelBotPriority:e};await g("onebot-multi/settings/load-balance/update",M),await k(),c("success","负载均衡设置已保存")}catch(n){c("error",(n==null?void 0:n.message)||"保存失败")}}return ye(async()=>{await k(),h.value=false,P=setInterval(()=>{k()},5e3)}),ke(()=>{P&&(clearInterval(P),P=null)}),(n,e)=>{const M=ge("k-layout");return a(),xe(M,null,{default:we(()=>[t("div",Ie,[h.value?(a(),p("div",Ce,[...e[30]||(e[30]=[t("div",{class:"comic-text"},"LOADING...",-1)])])):(a(),p("div",he,[y(" HEADER "),t("header",_e,[e[31]||(e[31]=t("div",{class:"brand"},[t("div",{class:"logo"},"✦"),t("div",{class:"title-box"},[t("h1",null,"ONEBOT 控制中心"),t("p",null,"实例管理与负载分发路由")])],-1)),t("nav",Ve,[t("button",{class:L(["pop-btn",{active:x.value==="bots"}]),onClick:e[0]||(e[0]=l=>x.value="bots")},"Bot 管理",2),t("button",{class:L(["pop-btn",{active:x.value==="balance"}]),onClick:e[1]||(e[1]=l=>x.value="balance")},"负载均衡",2),t("button",{class:"pop-btn action-btn",onClick:k},"刷新状态")])]),y(" BOTS TAB "),o(t("section",Be,[t("div",{class:"panel-header"},[e[32]||(e[32]=t("div",{class:"panel-title"},[t("h2",null,"Bot 状态"),t("p",null,"查看与管理当前运行实例")],-1)),t("button",{class:"pop-btn primary-btn",onClick:le},"新增节点")]),_.value.length===0?(a(),p("div",Ue,[...e[33]||(e[33]=[t("div",{class:"comic-speech"},"无可用实例。请点击“新增节点”以配置。",-1)])])):(a(),p("div",Me,[(a(true),p($,null,A(_.value,l=>(a(),p("article",{key:l.selfId,class:L(["bot-card",{disabled:l.enabled===false}])},[t("div",Te,[t("img",{class:"bot-avatar",src:l.avatarUrl||"",alt:"avatar"},null,8,Le),t("div",$e,[t("div",Ae,v(l.name||`Bot ${l.selfId}`),1),t("div",Ee,v(l.nickname||"未知")+" | "+v(l.protocol==="ws-reverse"?"反向 WebSocket":l.protocol||"反向 WebSocket"),1),t("div",Se,v(l.selfId),1)]),t("div",{class:L(["status-badge",`status-${l.status||"offline"}`])},v(K(l.status)),3)]),t("div",Oe,[t("div",Re,[e[34]||(e[34]=t("span",null,"群组",-1)),t("strong",null,v(l.groupCount??"-"),1)]),t("div",Ne,[e[35]||(e[35]=t("span",null,"好友",-1)),t("strong",null,v(l.friendCount??"-"),1)]),t("div",Pe,[e[36]||(e[36]=t("span",null,"收",-1)),t("strong",null,v(l.messageReceived??"-"),1)]),t("div",De,[e[37]||(e[37]=t("span",null,"发",-1)),t("strong",null,v(l.messageSent??"-"),1)])]),t("div",je,[t("div",null,[e[38]||(e[38]=t("strong",null,"终端:",-1)),u(" "+v(l.endpoint||"-"),1)]),t("div",null,[e[39]||(e[39]=t("strong",null,"路径:",-1)),u(" "+v(l.path||"/onebot"),1)])]),t("div",Fe,[t("button",{class:"pop-btn mini",onClick:d=>ne(l)},"编辑",8,We),t("button",{class:"pop-btn mini",onClick:d=>ae(l)},v(l.enabled===false?"启用":"禁用"),9,ze),t("button",{class:"pop-btn mini",onClick:d=>ie(l)},"重启",8,Ge),t("button",{class:"pop-btn mini",onClick:d=>ue(l)},"昵称",8,Xe),t("button",{class:"pop-btn mini",onClick:d=>de(l)},"头像",8,He),t("button",{class:"pop-btn mini danger",onClick:d=>se(l)},"删除",8,qe)])],2))),128))])),y(" MERGED RUNTIME SETTINGS "),e[46]||(e[46]=t("div",{class:"panel-header",style:{"margin-top":"40px"}},[t("div",{class:"panel-title"},[t("h2",null,"运行参数"),t("p",null,"调整核心连接与重试策略")])],-1)),t("div",Je,[t("label",Ke,[e[40]||(e[40]=u(" 超时时间 (毫秒) ",-1)),o(t("input",{"onUpdate:modelValue":e[2]||(e[2]=l=>m.responseTimeout=l),type:"number",class:"pop-input"},null,512),[[r,m.responseTimeout,void 0,{number:true}]])]),t("label",Qe,[e[41]||(e[41]=u(" 心跳间隔 (毫秒) ",-1)),o(t("input",{"onUpdate:modelValue":e[3]||(e[3]=l=>m.heartbeatInterval=l),type:"number",class:"pop-input"},null,512),[[r,m.heartbeatInterval,void 0,{number:true}]])]),t("label",Ye,[e[42]||(e[42]=u(" 重试次数 ",-1)),o(t("input",{"onUpdate:modelValue":e[4]||(e[4]=l=>m.retryTimes=l),type:"number",class:"pop-input"},null,512),[[r,m.retryTimes,void 0,{number:true}]])]),t("label",Ze,[e[43]||(e[43]=u(" 重试间隔 (毫秒) ",-1)),o(t("input",{"onUpdate:modelValue":e[5]||(e[5]=l=>m.retryInterval=l),type:"number",class:"pop-input"},null,512),[[r,m.retryInterval,void 0,{number:true}]])]),t("label",et,[e[44]||(e[44]=u(" 懒重试 (毫秒) ",-1)),o(t("input",{"onUpdate:modelValue":e[6]||(e[6]=l=>m.retryLazy=l),type:"number",class:"pop-input"},null,512),[[r,m.retryLazy,void 0,{number:true}]])]),t("label",tt,[o(t("input",{"onUpdate:modelValue":e[7]||(e[7]=l=>m.advanced.splitMixedContent=l),type:"checkbox",class:"pop-check"},null,512),[[j,m.advanced.splitMixedContent]]),e[45]||(e[45]=t("span",null,"拆分混合内容",-1))])]),t("div",{class:"panel-footer"},[t("button",{class:"pop-btn primary-btn",onClick:ve},"保存配置")])],512),[[q,x.value==="bots"]]),y(" LOAD BALANCE TAB "),o(t("section",lt,[e[59]||(e[59]=t("div",{class:"panel-header"},[t("div",{class:"panel-title"},[t("h2",null,"负载均衡"),t("p",null,"配置全局流量分发规则")])],-1)),t("div",nt,[t("label",ot,[o(t("input",{"onUpdate:modelValue":e[8]||(e[8]=l=>b.enabled=l),type:"checkbox",class:"pop-check"},null,512),[[j,b.enabled]]),e[47]||(e[47]=t("span",null,"启用负载均衡",-1))]),t("label",st,[e[48]||(e[48]=u(" 均衡间隔 (秒) ",-1)),o(t("input",{"onUpdate:modelValue":e[9]||(e[9]=l=>b.balanceInterval=l),type:"number",class:"pop-input"},null,512),[[r,b.balanceInterval,void 0,{number:true}]])]),t("label",at,[e[50]||(e[50]=u(" 过滤模式 ",-1)),o(t("select",{"onUpdate:modelValue":e[10]||(e[10]=l=>b.channelFilterMode=l),class:"pop-select"},[...e[49]||(e[49]=[t("option",{value:"blacklist"},"黑名单",-1),t("option",{value:"whitelist"},"白名单",-1)])],512),[[X,b.channelFilterMode]])]),t("label",it,[e[51]||(e[51]=u(" 默认最大负载 (0=无限) ",-1)),o(t("input",{"onUpdate:modelValue":e[11]||(e[11]=l=>b.defaultMaxLoad=l),type:"number",class:"pop-input"},null,512),[[r,b.defaultMaxLoad,void 0,{number:true}]])]),t("label",ut,[e[52]||(e[52]=u(" 未分配值 ",-1)),o(t("input",{"onUpdate:modelValue":e[12]||(e[12]=l=>b.unassignedValue=l),type:"text",class:"pop-input"},null,512),[[r,b.unassignedValue]])])]),t("div",pt,[t("label",dt,[e[53]||(e[53]=u(" 群黑名单 (每行一个) ",-1)),o(t("textarea",{"onUpdate:modelValue":e[13]||(e[13]=l=>E.value=l),rows:"5",class:"pop-textarea"},null,512),[[r,E.value]])]),t("label",rt,[e[54]||(e[54]=u(" 群白名单 (每行一个) ",-1)),o(t("textarea",{"onUpdate:modelValue":e[14]||(e[14]=l=>S.value=l),rows:"5",class:"pop-textarea"},null,512),[[r,S.value]])]),t("label",ct,[e[55]||(e[55]=u(" 优先群聊 (每行一个) ",-1)),o(t("textarea",{"onUpdate:modelValue":e[15]||(e[15]=l=>O.value=l),rows:"5",class:"pop-textarea"},null,512),[[r,O.value]])]),t("div",vt,[t("div",{class:"table-head"},[e[56]||(e[56]=t("span",null,"节点最大负载",-1)),t("button",{class:"pop-btn mini",onClick:Y},"添加行")]),t("div",bt,[B.value.length===0?(a(),p("div",mt,"暂无规则。")):y("v-if",true),(a(true),p($,null,A(B.value,(l,d)=>(a(),p("div",{key:`max-${d}`,class:"editor-row"},[o(t("select",{"onUpdate:modelValue":s=>l.botId=s,class:"pop-select mini-input"},[e[57]||(e[57]=t("option",{disabled:"",value:""},"选择 Bot",-1)),(a(true),p($,null,A(_.value,s=>(a(),p("option",{key:s.selfId,value:s.selfId},v(s.name||s.nickname||s.selfId),9,yt))),128))],8,ft),[[X,l.botId]]),o(t("input",{"onUpdate:modelValue":s=>l.maxLoad=s,type:"number",min:"0",placeholder:"最大值",class:"pop-input mini-input"},null,8,kt),[[r,l.maxLoad,void 0,{number:true}]]),t("button",{class:"pop-btn mini danger",onClick:s=>Z(d)},"X",8,gt)]))),128))])]),t("div",xt,[t("div",{class:"table-head"},[e[58]||(e[58]=t("span",null,"群聊专属节点",-1)),t("button",{class:"pop-btn mini",onClick:ee},"添加行")]),t("div",wt,[U.value.length===0?(a(),p("div",It,"暂无规则。")):y("v-if",true),(a(true),p($,null,A(U.value,(l,d)=>(a(),p("div",{key:`priority-${d}`,class:"editor-row",style:{display:"flex","flex-direction":"column"}},[t("div",Ct,[o(t("input",{"onUpdate:modelValue":s=>l.channelId=s,type:"text",placeholder:"群号",class:"pop-input mini-input",style:{flex:"1"}},null,8,ht),[[r,l.channelId]]),t("button",{class:"pop-btn mini danger",onClick:s=>te(d)},"X",8,_t)]),t("div",Vt,[(a(true),p($,null,A(_.value,s=>(a(),p("label",{key:s.selfId,class:"pop-checkbox mini-checkbox"},[o(t("input",{type:"checkbox",value:s.selfId,"onUpdate:modelValue":D=>l.botIds=D,class:"pop-check mini-check"},null,8,Bt),[[j,l.botIds]]),t("span",null,v(s.name||s.nickname||s.selfId),1)]))),128))])]))),128))])])]),t("div",{class:"panel-footer"},[t("button",{class:"pop-btn primary-btn",onClick:be},"保存规则")])],512),[[q,x.value==="balance"]])])),y(" MODALS "),y(" Create/Edit Bot "),i.value?(a(),p("div",{key:2,class:"pop-modal-overlay",onClick:e[24]||(e[24]=H(l=>i.value=null,["self"]))},[t("div",Ut,[e[68]||(e[68]=t("div",{class:"comic-burst"},"★",-1)),t("h3",null,v(R.value==="create"?"创建节点":"编辑节点"),1),t("div",Mt,[t("label",Tt,[e[60]||(e[60]=u("名称",-1)),o(t("input",{"onUpdate:modelValue":e[16]||(e[16]=l=>i.value.name=l),type:"text",class:"pop-input",placeholder:"选填"},null,512),[[r,i.value.name]])]),t("label",Lt,[e[61]||(e[61]=u("自身 ID",-1)),o(t("input",{"onUpdate:modelValue":e[17]||(e[17]=l=>i.value.selfId=l),type:"text",class:"pop-input"},null,512),[[r,i.value.selfId]])]),t("label",$t,[e[62]||(e[62]=u("访问密钥",-1)),o(t("input",{"onUpdate:modelValue":e[18]||(e[18]=l=>i.value.token=l),type:"text",class:"pop-input"},null,512),[[r,i.value.token]])]),t("label",At,[e[64]||(e[64]=u("协议 ",-1)),o(t("select",{"onUpdate:modelValue":e[19]||(e[19]=l=>i.value.protocol=l),class:"pop-select"},[...e[63]||(e[63]=[t("option",{value:"ws-reverse"},"反向 WebSocket",-1),t("option",{value:"ws"},"ws",-1)])],512),[[X,i.value.protocol]])]),t("label",Et,[e[65]||(e[65]=u("终端地址 (ws)",-1)),o(t("input",{"onUpdate:modelValue":e[20]||(e[20]=l=>i.value.endpoint=l),type:"text",class:"pop-input"},null,512),[[r,i.value.endpoint]])]),t("label",St,[e[66]||(e[66]=u("Path (反向 WebSocket)",-1)),o(t("input",{"onUpdate:modelValue":e[21]||(e[21]=l=>i.value.path=l),type:"text",class:"pop-input"},null,512),[[r,i.value.path]])]),t("label",Ot,[o(t("input",{"onUpdate:modelValue":e[22]||(e[22]=l=>i.value.enabled=l),type:"checkbox",class:"pop-check"},null,512),[[j,i.value.enabled]]),e[67]||(e[67]=t("span",null,"已启用",-1))])]),t("div",Rt,[t("button",{class:"pop-btn primary-btn",onClick:oe},"保存"),t("button",{class:"pop-btn",onClick:e[23]||(e[23]=l=>i.value=null)},"取消")])])])):y("v-if",true),y(" Profile Modal "),w.value?(a(),p("div",{key:3,class:"pop-modal-overlay",onClick:e[27]||(e[27]=H(l=>w.value=null,["self"]))},[t("div",Nt,[e[70]||(e[70]=t("h3",null,"修改昵称",-1)),t("p",Pt,v(w.value.selfId),1),t("label",Dt,[e[69]||(e[69]=u("昵称",-1)),o(t("input",{"onUpdate:modelValue":e[25]||(e[25]=l=>N.value=l),type:"text",class:"pop-input"},null,512),[[r,N.value]])]),t("div",jt,[t("button",{class:"pop-btn primary-btn",onClick:pe},"保存"),t("button",{class:"pop-btn",onClick:e[26]||(e[26]=l=>w.value=null)},"取消")])])])):y("v-if",true),y(" Avatar Modal "),I.value?(a(),p("div",{key:4,class:"pop-modal-overlay",onClick:e[29]||(e[29]=H(l=>I.value=null,["self"]))},[t("div",Ft,[e[72]||(e[72]=t("h3",null,"修改头像",-1)),t("p",Wt,v(I.value.selfId),1),t("label",zt,[e[71]||(e[71]=u(" 选择图片文件 ",-1)),t("input",{type:"file",accept:"image/*",class:"pop-file-input",onChange:re},null,32)]),t("div",Gt,[t("button",{class:"pop-btn primary-btn",onClick:ce},"保存"),t("button",{class:"pop-btn",onClick:e[28]||(e[28]=l=>I.value=null)},"取消")])])])):y("v-if",true),y(" Toast "),C.show?(a(),p("div",{key:5,class:L(["pop-toast comic-panel",C.type])},[C.type==="success"?(a(),p("span",Xt,"✓")):(a(),p("span",Ht,"✕")),u(" "+v(C.message),1)],2)):y("v-if",true)])]),_:1})}}}),J=(V,h)=>{const x=V.__vccOpts||V;for(const[_,m]of h)x[_]=m;return x},Jt=J(qt,[["__scopeId","data-v-539ab5ea"]]),Kt={},Qt={xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"};function Yt(V,h){return a(),p("svg",Qt,[...h[0]||(h[0]=[t("rect",{x:"2",y:"4",width:"20",height:"18",rx:"3"},null,-1),t("circle",{cx:"8",cy:"13",r:"2.5"},null,-1),t("circle",{cx:"16",cy:"13",r:"2.5"},null,-1)])])}const Zt=J(Kt,[["render",Yt]]);me.register("activity:onebot-multi",Zt);const ll=V=>{V.page({name:"OneBot Multi",path:"/onebot-multi",component:Jt,icon:"activity:onebot-multi",order:600})};export{ll as default};
|
|
1
|
+
import{send as x,icons as wt}from"@koishijs/client";import{defineComponent as Ct,ref as b,reactive as K,computed as It,onMounted as ht,onUnmounted as _t,resolveComponent as Bt,createBlock as Vt,openBlock as a,withCtx as Ut,createElementVNode as e,createElementBlock as i,createCommentVNode as m,withDirectives as o,normalizeClass as O,Fragment as R,renderList as N,toDisplayString as d,createTextVNode as p,vModelText as f,vModelCheckbox as z,vShow as Y,vModelSelect as Q,withModifiers as G}from"vue";const Tt={class:"pop-wrapper"},Mt={key:0,class:"pop-loading"},$t={key:1,class:"pop-container"},Lt={class:"pop-header"},Et={class:"pop-tabs"},At={class:"pop-panel bots-panel"},St={key:0,class:"empty-state"},Ot={key:1,class:"bot-grid"},Rt={class:"bot-header"},Nt=["src"],Pt={class:"bot-info"},jt={class:"bot-name"},Dt={class:"bot-sub"},Ft={class:"bot-id"},Wt={class:"bot-stats"},zt={class:"stat-box"},Gt={class:"stat-box"},Xt={class:"stat-box"},Ht={class:"stat-box"},qt={class:"bot-meta"},Jt={class:"bot-actions"},Kt=["onClick"],Qt=["onClick"],Yt=["onClick"],Zt=["onClick"],te=["onClick"],ee=["onClick"],le={class:"form-grid"},se={class:"pop-label"},ne={class:"pop-label"},oe={class:"pop-label"},ae={class:"pop-label"},ie={class:"pop-label"},ue={class:"pop-label pop-checkbox",style:{"align-self":"center","margin-top":"24px"}},pe={class:"pop-panel balance-panel"},de={class:"form-grid"},re={class:"pop-label pop-checkbox"},ce={class:"pop-label"},ve={class:"pop-label"},be={class:"pop-label"},me={class:"pop-label"},fe={class:"split-grid"},ye={class:"pop-label"},ke={class:"list-summary-box"},ge={class:"list-count"},xe={class:"pop-label"},we={class:"list-summary-box"},Ce={class:"list-count"},Ie={class:"pop-label"},he={class:"list-summary-box"},_e={class:"list-count"},Be={class:"pop-table-editor"},Ve={class:"table-body"},Ue={key:0,class:"empty-row"},Te=["onUpdate:modelValue"],Me=["value"],$e=["onUpdate:modelValue"],Le=["onClick"],Ee={class:"pop-table-editor full-width"},Ae={class:"table-body"},Se={key:0,class:"empty-row"},Oe={style:{display:"flex",gap:"8px"}},Re=["onUpdate:modelValue"],Ne=["onClick"],Pe={class:"bot-checkbox-group",style:{display:"flex","flex-wrap":"wrap",gap:"8px","margin-top":"8px"}},je=["value","onUpdate:modelValue"],De={class:"pop-modal comic-panel"},Fe={class:"form-grid modal-grid"},We={class:"pop-label"},ze={class:"pop-label hidden"},Ge={class:"pop-label"},Xe={class:"pop-label"},He={class:"pop-label"},qe={class:"pop-label"},Je={class:"pop-label pop-checkbox"},Ke={class:"modal-actions"},Qe={class:"pop-modal comic-panel"},Ye={class:"modal-sub"},Ze={class:"pop-label"},tl={class:"modal-actions"},el={class:"pop-modal comic-panel"},ll={class:"modal-sub"},sl={class:"pop-label"},nl={class:"modal-actions"},ol={class:"pop-modal comic-panel"},al={class:"modal-actions"},il={key:0},ul={key:1},pl=Ct({__name:"page",setup(V){const _=b(true),w=b("bots"),B=b([]),y=K({responseTimeout:6e4,heartbeatInterval:3e4,retryTimes:6,retryInterval:5e3,retryLazy:6e4,advanced:{splitMixedContent:true}}),v=K({enabled:false,balanceInterval:600,channelFilterMode:"blacklist",channelBlacklist:[],channelWhitelist:[],priorityChannels:[],defaultMaxLoad:0,botMaxLoad:{},unassignedValue:"",channelBotPriority:{}}),L=b(""),E=b(""),A=b(""),U=b([]),T=b([]),k=b(null),M=b(""),P=b("create"),X=b(""),u=b(null),C=b(null),j=b(""),I=b(null),S=b(""),h=K({show:false,type:"success",message:""});let D=null,H=false;function F(s){return s.split(`
|
|
2
|
+
`).map(t=>t.trim()).filter(Boolean)}function q(s){return F(s).length}const tt=It(()=>k.value==="blacklist"?"编辑群黑名单":k.value==="whitelist"?"编辑群白名单":k.value==="priority"?"编辑优先群聊":"编辑列表");function J(s){k.value=s,s==="blacklist"?M.value=L.value:s==="whitelist"?M.value=E.value:s==="priority"&&(M.value=A.value)}function et(){const s=M.value.split(`
|
|
3
|
+
`).map(t=>t.trim()).filter(t=>/^\d+$/.test(t)).join(`
|
|
4
|
+
`);k.value==="blacklist"?L.value=s:k.value==="whitelist"?E.value=s:k.value==="priority"&&(A.value=s),k.value=null,c("success","列表已暂存,请点击保存规则生效")}function c(s,t){h.type=s,h.message=t,h.show=true,setTimeout(()=>{h.show=false},2e3)}function lt(s){return s==="online"?"在线":s==="connecting"?"连接中":"离线"}function st(){L.value=v.channelBlacklist.join(`
|
|
5
|
+
`),E.value=v.channelWhitelist.join(`
|
|
6
|
+
`),A.value=v.priorityChannels.join(`
|
|
7
|
+
`),U.value=Object.entries(v.botMaxLoad||{}).map(([s,t])=>({botId:s,maxLoad:Number(t)||0})),T.value=Object.entries(v.channelBotPriority||{}).map(([s,t])=>({channelId:s,botIds:Array.isArray(t)?[...t]:[]}))}function nt(){U.value.push({botId:"",maxLoad:0})}function ot(s){U.value.splice(s,1)}function at(){T.value.push({channelId:"",botIds:[]})}function it(s){T.value.splice(s,1)}async function g(){if(!H){H=true;try{const s=await x("onebot-multi/state");B.value=(s==null?void 0:s.bots)||[],Object.assign(y,(s==null?void 0:s.runtime)||{}),Object.assign(v,(s==null?void 0:s.loadBalance)||{}),st()}catch(s){c("error",(s==null?void 0:s.message)||"刷新失败")}finally{H=false}}}function ut(){P.value="create",X.value="",u.value={token:"",protocol:"ws-reverse",endpoint:"",path:"/onebot",name:"",enabled:true}}function pt(s){P.value="edit",X.value=s.selfId,u.value={...s}}async function dt(){if(u.value)try{P.value==="create"?await x("onebot-multi/bots/create",u.value):await x("onebot-multi/bots/update",{oldSelfId:X.value,bot:u.value}),u.value=null,await g(),c("success","保存成功")}catch(s){c("error",(s==null?void 0:s.message)||"保存失败")}}async function rt(s){if(confirm(`确认删除 Bot ${s.selfId} 吗?`))try{await x("onebot-multi/bots/delete",{selfId:s.selfId}),await g(),c("success","删除成功")}catch(t){c("error",(t==null?void 0:t.message)||"删除失败")}}async function ct(s){try{await x("onebot-multi/bots/toggle",{selfId:s.selfId}),await g(),c("success","状态已更新")}catch(t){c("error",(t==null?void 0:t.message)||"更新失败")}}async function vt(s){try{await x("onebot-multi/bots/restart",{selfId:s.selfId}),await g(),c("success","重启已触发")}catch(t){c("error",(t==null?void 0:t.message)||"重启失败")}}function bt(s){C.value=s,j.value=s.nickname||""}async function mt(){if(C.value)try{const s=await x("onebot-multi/bots/profile",{selfId:C.value.selfId,nickname:j.value});if(!(s!=null&&s.success))throw new Error((s==null?void 0:s.error)||"保存失败");C.value=null,await g(),c("success","昵称已更新")}catch(s){c("error",(s==null?void 0:s.message)||"更新失败")}}function ft(s){I.value=s,S.value=""}function yt(s){var r;const $=(r=s.target.files)==null?void 0:r[0];if(!$){S.value="";return}const l=new FileReader;l.onload=n=>{var W;S.value=(W=n.target)==null?void 0:W.result},l.readAsDataURL($)}async function kt(){if(!I.value||!S.value.trim()){c("error","请先选择图片文件");return}try{const s=await x("onebot-multi/bots/avatar",{selfId:I.value.selfId,file:S.value});if(!(s!=null&&s.success))throw new Error((s==null?void 0:s.error)||"保存失败");I.value=null,c("success","头像已更新")}catch(s){c("error",(s==null?void 0:s.message)||"更新失败")}}async function gt(){try{await x("onebot-multi/settings/runtime/update",{...y}),await g(),c("success","运行时设置已保存")}catch(s){c("error",(s==null?void 0:s.message)||"保存失败")}}async function xt(){try{const s={};for(const l of U.value){const r=l.botId.trim();if(!r)continue;const n=Math.max(0,Number(l.maxLoad||0));s[r]=n}const t={};for(const l of T.value){const r=l.channelId.trim();if(!r)continue;const n=(l.botIds||[]).filter(Boolean);n.length>0&&(t[r]=n)}const $={...v,channelBlacklist:F(L.value),channelWhitelist:F(E.value),priorityChannels:F(A.value),botMaxLoad:s,channelBotPriority:t};await x("onebot-multi/settings/load-balance/update",$),await g(),c("success","负载均衡设置已保存")}catch(s){c("error",(s==null?void 0:s.message)||"保存失败")}}return ht(async()=>{await g(),_.value=false,D=setInterval(()=>{g()},5e3)}),_t(()=>{D&&(clearInterval(D),D=null)}),(s,t)=>{const $=Bt("k-layout");return a(),Vt($,null,{default:Ut(()=>[e("div",Tt,[_.value?(a(),i("div",Mt,[...t[33]||(t[33]=[e("div",{class:"comic-text"},"LOADING...",-1)])])):(a(),i("div",$t,[m(" HEADER "),e("header",Lt,[t[34]||(t[34]=e("div",{class:"brand"},[e("div",{class:"logo"},"✦"),e("div",{class:"title-box"},[e("h1",null,"ONEBOT 控制中心"),e("p",null,"实例管理与负载分发路由")])],-1)),e("nav",Et,[e("button",{class:O(["pop-btn",{active:w.value==="bots"}]),onClick:t[0]||(t[0]=l=>w.value="bots")},"Bot 管理",2),e("button",{class:O(["pop-btn",{active:w.value==="balance"}]),onClick:t[1]||(t[1]=l=>w.value="balance")},"负载均衡",2),e("button",{class:"pop-btn action-btn",onClick:g},"刷新状态")])]),m(" BOTS TAB "),o(e("section",At,[e("div",{class:"panel-header"},[t[35]||(t[35]=e("div",{class:"panel-title"},[e("h2",null,"Bot 状态"),e("p",null,"查看与管理当前运行实例")],-1)),e("button",{class:"pop-btn primary-btn",onClick:ut},"新增节点")]),B.value.length===0?(a(),i("div",St,[...t[36]||(t[36]=[e("div",{class:"comic-speech"},"无可用实例。请点击“新增节点”以配置。",-1)])])):(a(),i("div",Ot,[(a(true),i(R,null,N(B.value,l=>(a(),i("article",{key:l.selfId,class:O(["bot-card",{disabled:l.enabled===false}])},[e("div",Rt,[e("img",{class:"bot-avatar",src:l.avatarUrl||"",alt:"avatar"},null,8,Nt),e("div",Pt,[e("div",jt,d(l.name||`Bot ${l.selfId}`),1),e("div",Dt,d(l.nickname||"未知")+" | "+d(l.protocol==="ws-reverse"?"反向 WebSocket":l.protocol||"反向 WebSocket"),1),e("div",Ft,d(l.selfId),1)]),e("div",{class:O(["status-badge",`status-${l.status||"offline"}`])},d(lt(l.status)),3)]),e("div",Wt,[e("div",zt,[t[37]||(t[37]=e("span",null,"群组",-1)),e("strong",null,d(l.groupCount??"-"),1)]),e("div",Gt,[t[38]||(t[38]=e("span",null,"好友",-1)),e("strong",null,d(l.friendCount??"-"),1)]),e("div",Xt,[t[39]||(t[39]=e("span",null,"收",-1)),e("strong",null,d(l.messageReceived??"-"),1)]),e("div",Ht,[t[40]||(t[40]=e("span",null,"发",-1)),e("strong",null,d(l.messageSent??"-"),1)])]),e("div",qt,[e("div",null,[t[41]||(t[41]=e("strong",null,"终端:",-1)),p(" "+d(l.endpoint||"-"),1)]),e("div",null,[t[42]||(t[42]=e("strong",null,"路径:",-1)),p(" "+d(l.path||"/onebot"),1)])]),e("div",Jt,[e("button",{class:"pop-btn mini",onClick:r=>pt(l)},"编辑",8,Kt),e("button",{class:"pop-btn mini",onClick:r=>ct(l)},d(l.enabled===false?"启用":"禁用"),9,Qt),e("button",{class:"pop-btn mini",onClick:r=>vt(l)},"重启",8,Yt),e("button",{class:"pop-btn mini",onClick:r=>bt(l)},"昵称",8,Zt),e("button",{class:"pop-btn mini",onClick:r=>ft(l)},"头像",8,te),e("button",{class:"pop-btn mini danger",onClick:r=>rt(l)},"删除",8,ee)])],2))),128))])),m(" MERGED RUNTIME SETTINGS "),t[49]||(t[49]=e("div",{class:"panel-header",style:{"margin-top":"40px"}},[e("div",{class:"panel-title"},[e("h2",null,"运行参数"),e("p",null,"调整核心连接与重试策略")])],-1)),e("div",le,[e("label",se,[t[43]||(t[43]=p(" 超时时间 (毫秒) ",-1)),o(e("input",{"onUpdate:modelValue":t[2]||(t[2]=l=>y.responseTimeout=l),type:"number",class:"pop-input"},null,512),[[f,y.responseTimeout,void 0,{number:true}]])]),e("label",ne,[t[44]||(t[44]=p(" 心跳间隔 (毫秒) ",-1)),o(e("input",{"onUpdate:modelValue":t[3]||(t[3]=l=>y.heartbeatInterval=l),type:"number",class:"pop-input"},null,512),[[f,y.heartbeatInterval,void 0,{number:true}]])]),e("label",oe,[t[45]||(t[45]=p(" 重试次数 ",-1)),o(e("input",{"onUpdate:modelValue":t[4]||(t[4]=l=>y.retryTimes=l),type:"number",class:"pop-input"},null,512),[[f,y.retryTimes,void 0,{number:true}]])]),e("label",ae,[t[46]||(t[46]=p(" 重试间隔 (毫秒) ",-1)),o(e("input",{"onUpdate:modelValue":t[5]||(t[5]=l=>y.retryInterval=l),type:"number",class:"pop-input"},null,512),[[f,y.retryInterval,void 0,{number:true}]])]),e("label",ie,[t[47]||(t[47]=p(" 懒重试 (毫秒) ",-1)),o(e("input",{"onUpdate:modelValue":t[6]||(t[6]=l=>y.retryLazy=l),type:"number",class:"pop-input"},null,512),[[f,y.retryLazy,void 0,{number:true}]])]),e("label",ue,[o(e("input",{"onUpdate:modelValue":t[7]||(t[7]=l=>y.advanced.splitMixedContent=l),type:"checkbox",class:"pop-check"},null,512),[[z,y.advanced.splitMixedContent]]),t[48]||(t[48]=e("span",null,"拆分混合内容",-1))])]),e("div",{class:"panel-footer"},[e("button",{class:"pop-btn primary-btn",onClick:gt},"保存配置")])],512),[[Y,w.value==="bots"]]),m(" LOAD BALANCE TAB "),o(e("section",pe,[t[62]||(t[62]=e("div",{class:"panel-header"},[e("div",{class:"panel-title"},[e("h2",null,"负载均衡"),e("p",null,"配置全局流量分发规则")])],-1)),e("div",de,[e("label",re,[o(e("input",{"onUpdate:modelValue":t[8]||(t[8]=l=>v.enabled=l),type:"checkbox",class:"pop-check"},null,512),[[z,v.enabled]]),t[50]||(t[50]=e("span",null,"启用负载均衡",-1))]),e("label",ce,[t[51]||(t[51]=p(" 均衡间隔 (秒) ",-1)),o(e("input",{"onUpdate:modelValue":t[9]||(t[9]=l=>v.balanceInterval=l),type:"number",class:"pop-input"},null,512),[[f,v.balanceInterval,void 0,{number:true}]])]),e("label",ve,[t[53]||(t[53]=p(" 过滤模式 ",-1)),o(e("select",{"onUpdate:modelValue":t[10]||(t[10]=l=>v.channelFilterMode=l),class:"pop-select"},[...t[52]||(t[52]=[e("option",{value:"blacklist"},"黑名单",-1),e("option",{value:"whitelist"},"白名单",-1)])],512),[[Q,v.channelFilterMode]])]),e("label",be,[t[54]||(t[54]=p(" 默认最大负载 (0=无限) ",-1)),o(e("input",{"onUpdate:modelValue":t[11]||(t[11]=l=>v.defaultMaxLoad=l),type:"number",class:"pop-input"},null,512),[[f,v.defaultMaxLoad,void 0,{number:true}]])]),e("label",me,[t[55]||(t[55]=p(" 未分配值 ",-1)),o(e("input",{"onUpdate:modelValue":t[12]||(t[12]=l=>v.unassignedValue=l),type:"text",class:"pop-input"},null,512),[[f,v.unassignedValue]])])]),e("div",fe,[e("div",ye,[t[56]||(t[56]=p(" 群黑名单 ",-1)),e("div",ke,[e("span",ge,"已配置 "+d(q(L.value))+" 个群",1),e("button",{class:"pop-btn mini action-btn",onClick:t[13]||(t[13]=l=>J("blacklist"))},"编辑")])]),e("div",xe,[t[57]||(t[57]=p(" 群白名单 ",-1)),e("div",we,[e("span",Ce,"已配置 "+d(q(E.value))+" 个群",1),e("button",{class:"pop-btn mini action-btn",onClick:t[14]||(t[14]=l=>J("whitelist"))},"编辑")])]),e("div",Ie,[t[58]||(t[58]=p(" 优先群聊 ",-1)),e("div",he,[e("span",_e,"已配置 "+d(q(A.value))+" 个群",1),e("button",{class:"pop-btn mini action-btn",onClick:t[15]||(t[15]=l=>J("priority"))},"编辑")])]),e("div",Be,[e("div",{class:"table-head"},[t[59]||(t[59]=e("span",null,"节点最大负载",-1)),e("button",{class:"pop-btn mini",onClick:nt},"添加行")]),e("div",Ve,[U.value.length===0?(a(),i("div",Ue,"暂无规则。")):m("v-if",true),(a(true),i(R,null,N(U.value,(l,r)=>(a(),i("div",{key:`max-${r}`,class:"editor-row"},[o(e("select",{"onUpdate:modelValue":n=>l.botId=n,class:"pop-select mini-input"},[t[60]||(t[60]=e("option",{disabled:"",value:""},"选择 Bot",-1)),(a(true),i(R,null,N(B.value,n=>(a(),i("option",{key:n.selfId,value:n.selfId},d(n.name||n.nickname||n.selfId),9,Me))),128))],8,Te),[[Q,l.botId]]),o(e("input",{"onUpdate:modelValue":n=>l.maxLoad=n,type:"number",min:"0",placeholder:"最大值",class:"pop-input mini-input"},null,8,$e),[[f,l.maxLoad,void 0,{number:true}]]),e("button",{class:"pop-btn mini danger",onClick:n=>ot(r)},"X",8,Le)]))),128))])]),e("div",Ee,[e("div",{class:"table-head"},[t[61]||(t[61]=e("span",null,"群聊专属节点",-1)),e("button",{class:"pop-btn mini",onClick:at},"添加行")]),e("div",Ae,[T.value.length===0?(a(),i("div",Se,"暂无规则。")):m("v-if",true),(a(true),i(R,null,N(T.value,(l,r)=>(a(),i("div",{key:`priority-${r}`,class:"editor-row",style:{display:"flex","flex-direction":"column"}},[e("div",Oe,[o(e("input",{"onUpdate:modelValue":n=>l.channelId=n,type:"text",placeholder:"群号",class:"pop-input mini-input",style:{flex:"1"}},null,8,Re),[[f,l.channelId]]),e("button",{class:"pop-btn mini danger",onClick:n=>it(r)},"X",8,Ne)]),e("div",Pe,[(a(true),i(R,null,N(B.value,n=>(a(),i("label",{key:n.selfId,class:"pop-checkbox mini-checkbox"},[o(e("input",{type:"checkbox",value:n.selfId,"onUpdate:modelValue":W=>l.botIds=W,class:"pop-check mini-check"},null,8,je),[[z,l.botIds]]),e("span",null,d(n.name||n.nickname||n.selfId),1)]))),128))])]))),128))])])]),e("div",{class:"panel-footer"},[e("button",{class:"pop-btn primary-btn",onClick:xt},"保存规则")])],512),[[Y,w.value==="balance"]])])),m(" MODALS "),m(" Create/Edit Bot "),u.value?(a(),i("div",{key:2,class:"pop-modal-overlay",onClick:t[24]||(t[24]=G(l=>u.value=null,["self"]))},[e("div",De,[t[71]||(t[71]=e("div",{class:"comic-burst"},"★",-1)),e("h3",null,d(P.value==="create"?"创建节点":"编辑节点"),1),e("div",Fe,[e("label",We,[t[63]||(t[63]=p("名称",-1)),o(e("input",{"onUpdate:modelValue":t[16]||(t[16]=l=>u.value.name=l),type:"text",class:"pop-input",placeholder:"选填"},null,512),[[f,u.value.name]])]),e("label",ze,[t[64]||(t[64]=p("自身 ID",-1)),o(e("input",{"onUpdate:modelValue":t[17]||(t[17]=l=>u.value.selfId=l),type:"text",class:"pop-input"},null,512),[[f,u.value.selfId]])]),e("label",Ge,[t[65]||(t[65]=p("访问密钥",-1)),o(e("input",{"onUpdate:modelValue":t[18]||(t[18]=l=>u.value.token=l),type:"text",class:"pop-input"},null,512),[[f,u.value.token]])]),e("label",Xe,[t[67]||(t[67]=p("协议 ",-1)),o(e("select",{"onUpdate:modelValue":t[19]||(t[19]=l=>u.value.protocol=l),class:"pop-select"},[...t[66]||(t[66]=[e("option",{value:"ws-reverse"},"反向 WebSocket",-1),e("option",{value:"ws"},"ws",-1)])],512),[[Q,u.value.protocol]])]),e("label",He,[t[68]||(t[68]=p("终端地址 (ws)",-1)),o(e("input",{"onUpdate:modelValue":t[20]||(t[20]=l=>u.value.endpoint=l),type:"text",class:"pop-input"},null,512),[[f,u.value.endpoint]])]),e("label",qe,[t[69]||(t[69]=p("Path (反向 WebSocket)",-1)),o(e("input",{"onUpdate:modelValue":t[21]||(t[21]=l=>u.value.path=l),type:"text",class:"pop-input"},null,512),[[f,u.value.path]])]),e("label",Je,[o(e("input",{"onUpdate:modelValue":t[22]||(t[22]=l=>u.value.enabled=l),type:"checkbox",class:"pop-check"},null,512),[[z,u.value.enabled]]),t[70]||(t[70]=e("span",null,"已启用",-1))])]),e("div",Ke,[e("button",{class:"pop-btn primary-btn",onClick:dt},"保存"),e("button",{class:"pop-btn",onClick:t[23]||(t[23]=l=>u.value=null)},"取消")])])])):m("v-if",true),m(" Profile Modal "),C.value?(a(),i("div",{key:3,class:"pop-modal-overlay",onClick:t[27]||(t[27]=G(l=>C.value=null,["self"]))},[e("div",Qe,[t[73]||(t[73]=e("h3",null,"修改昵称",-1)),e("p",Ye,d(C.value.selfId),1),e("label",Ze,[t[72]||(t[72]=p("昵称",-1)),o(e("input",{"onUpdate:modelValue":t[25]||(t[25]=l=>j.value=l),type:"text",class:"pop-input"},null,512),[[f,j.value]])]),e("div",tl,[e("button",{class:"pop-btn primary-btn",onClick:mt},"保存"),e("button",{class:"pop-btn",onClick:t[26]||(t[26]=l=>C.value=null)},"取消")])])])):m("v-if",true),m(" Avatar Modal "),I.value?(a(),i("div",{key:4,class:"pop-modal-overlay",onClick:t[29]||(t[29]=G(l=>I.value=null,["self"]))},[e("div",el,[t[75]||(t[75]=e("h3",null,"修改头像",-1)),e("p",ll,d(I.value.selfId),1),e("label",sl,[t[74]||(t[74]=p(" 选择图片文件 ",-1)),e("input",{type:"file",accept:"image/*",class:"pop-file-input",onChange:yt},null,32)]),e("div",nl,[e("button",{class:"pop-btn primary-btn",onClick:kt},"保存"),e("button",{class:"pop-btn",onClick:t[28]||(t[28]=l=>I.value=null)},"取消")])])])):m("v-if",true),m(" List Editor Modal "),k.value?(a(),i("div",{key:5,class:"pop-modal-overlay",onClick:t[32]||(t[32]=G(l=>k.value=null,["self"]))},[e("div",ol,[t[76]||(t[76]=e("div",{class:"comic-burst",style:{background:"var(--pop-secondary)",color:"var(--pop-text)"}},"✎",-1)),e("h3",null,d(tt.value),1),t[77]||(t[77]=e("p",{class:"modal-sub"},"每行输入一个群号(仅保留数字)",-1)),o(e("textarea",{"onUpdate:modelValue":t[30]||(t[30]=l=>M.value=l),rows:"10",class:"pop-textarea",style:{width:"100%"}},null,512),[[f,M.value]]),e("div",al,[e("button",{class:"pop-btn primary-btn",onClick:et},"确认保存"),e("button",{class:"pop-btn",onClick:t[31]||(t[31]=l=>k.value=null)},"取消")])])])):m("v-if",true),m(" Toast "),h.show?(a(),i("div",{key:6,class:O(["pop-toast comic-panel",h.type])},[h.type==="success"?(a(),i("span",il,"✓")):(a(),i("span",ul,"✕")),p(" "+d(h.message),1)],2)):m("v-if",true)])]),_:1})}}}),Z=(V,_)=>{const w=V.__vccOpts||V;for(const[B,y]of _)w[B]=y;return w},dl=Z(pl,[["__scopeId","data-v-6479fe79"]]),rl={},cl={xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"};function vl(V,_){return a(),i("svg",cl,[..._[0]||(_[0]=[e("rect",{x:"2",y:"4",width:"20",height:"18",rx:"3"},null,-1),e("circle",{cx:"8",cy:"13",r:"2.5"},null,-1),e("circle",{cx:"16",cy:"13",r:"2.5"},null,-1)])])}const bl=Z(rl,[["render",vl]]);wt.register("activity:onebot-multi",bl);const yl=V=>{V.page({name:"OneBot Multi",path:"/onebot-multi",component:dl,icon:"activity:onebot-multi",order:600})};export{yl as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[data-v-539ab5ea] .k-layout,[data-v-539ab5ea] .k-layout__main{background:transparent!important;padding:0!important;margin:0!important;height:100%;position:relative}.pop-wrapper[data-v-539ab5ea]{--pop-bg: #fffbeb;--pop-text: #6b5243;--pop-border: 3px solid var(--pop-text);--pop-shadow-color: var(--pop-text);--pop-panel: #ffffff;--pop-primary: #ff9a9e;--pop-secondary: #a1c4fd;--pop-success: #b2fba5;--pop-danger: #ffb3ba;--pop-dot: rgba(107, 82, 67, .05);width:100%;height:100%;box-sizing:border-box;color:var(--pop-text);font-family:Nunito,Varela Round,PingFang SC,Microsoft YaHei,sans-serif;background-color:var(--pop-bg);background-image:radial-gradient(var(--pop-dot) 15%,transparent 16%),radial-gradient(var(--pop-dot) 15%,transparent 16%);background-size:24px 24px;background-position:0 0,12px 12px;position:absolute;top:0;left:0;right:0;bottom:0;z-index:0;overflow-y:auto;padding:24px;font-weight:800}.pop-wrapper[data-v-539ab5ea] *{box-sizing:border-box}.comic-panel[data-v-539ab5ea]{background:var(--pop-panel);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);border-radius:16px}.pop-loading[data-v-539ab5ea]{display:flex;justify-content:center;align-items:center;height:60vh}.comic-text[data-v-539ab5ea]{font-size:4rem;color:#fff;text-shadow:2px 2px 0 var(--pop-text),-1px -1px 0 var(--pop-text),1px -1px 0 var(--pop-text),-1px 1px 0 var(--pop-text),1px 1px 0 var(--pop-text);transform:rotate(-2deg);animation:pulse-539ab5ea 1s infinite alternate}@keyframes pulse-539ab5ea{0%{transform:rotate(-5deg) scale(1)}to{transform:rotate(-5deg) scale(1.1)}}.pop-container[data-v-539ab5ea]{max-width:1200px;margin:0 auto;display:flex;flex-direction:column;gap:24px}.pop-header[data-v-539ab5ea]{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;background:var(--pop-secondary);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);padding:20px 24px;border-radius:16px;position:relative;overflow:hidden}.pop-header[data-v-539ab5ea]:before{content:"";position:absolute;top:-50%;left:-50%;width:200%;height:200%;background-image:repeating-linear-gradient(45deg,transparent,transparent 10px,rgba(255,255,255,.2) 10px,rgba(255,255,255,.2) 20px);z-index:0}.pop-header[data-v-539ab5ea]>*{position:relative;z-index:1}.brand[data-v-539ab5ea]{display:flex;align-items:center;gap:16px}.logo[data-v-539ab5ea]{font-size:42px;background:var(--pop-bg);width:72px;height:72px;border-radius:50%;border:var(--pop-border);display:flex;align-items:center;justify-content:center;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:rotate(-5deg)}.title-box h1[data-v-539ab5ea]{margin:0;font-size:36px;font-weight:900;color:#fff;text-shadow:2px 2px 0 var(--pop-text),-1px -1px 0 var(--pop-text),1px -1px 0 var(--pop-text),-1px 1px 0 var(--pop-text),1px 1px 0 var(--pop-text);letter-spacing:2px;text-transform:uppercase}.title-box p[data-v-539ab5ea]{margin:4px 0 0;background:var(--pop-text);color:#fff;display:inline-block;padding:4px 8px;font-size:14px;transform:skew(-5deg);text-transform:uppercase}.pop-tabs[data-v-539ab5ea]{display:flex;gap:12px;flex-wrap:wrap}.pop-btn[data-v-539ab5ea]{background:#fff;color:var(--pop-text);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);padding:10px 20px;font-size:16px;font-family:inherit;font-weight:900;cursor:pointer;border-radius:16px;transition:all .1s ease;position:relative;text-transform:uppercase}.pop-btn[data-v-539ab5ea]:hover{transform:translate(-2px,-2px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn[data-v-539ab5ea]:active{transform:translate(4px,4px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.active[data-v-539ab5ea]{background:var(--pop-primary);color:#fff}.pop-btn.primary-btn[data-v-539ab5ea]{background:var(--pop-primary);color:#fff;font-size:18px}.pop-btn.action-btn[data-v-539ab5ea]{background:#ffb347;color:#fff}.pop-btn.mini[data-v-539ab5ea]{padding:6px 12px;font-size:13px;box-shadow:2px 2px 0 var(--pop-shadow-color);border-width:2px}.pop-btn.mini[data-v-539ab5ea]:hover{transform:translate(-1px,-1px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn.mini[data-v-539ab5ea]:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.danger[data-v-539ab5ea]{background:var(--pop-danger);color:#fff}.pop-panel[data-v-539ab5ea]{background:var(--pop-panel);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);border-radius:16px;padding:24px;position:relative}.panel-header[data-v-539ab5ea]{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:24px;border-bottom:3px solid var(--pop-text);padding-bottom:16px}.panel-title h2[data-v-539ab5ea]{margin:0;font-size:28px;color:var(--pop-primary);text-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.panel-title p[data-v-539ab5ea]{margin:4px 0 0;font-size:16px;font-weight:700;text-transform:uppercase}.bot-grid[data-v-539ab5ea]{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:20px}.bot-card[data-v-539ab5ea]{border:var(--pop-border);border-radius:16px;background:#fff;padding:16px;box-shadow:4px 4px 0 var(--pop-shadow-color);transition:transform .2s,box-shadow .2s;position:relative;overflow:hidden}.bot-card[data-v-539ab5ea]:before{content:"";position:absolute;top:0;right:0;width:40px;height:40px;background:var(--pop-bg);border-bottom-left-radius:20px;border-left:var(--pop-border);border-bottom:var(--pop-border)}.bot-card.disabled[data-v-539ab5ea]{background:#e5e7eb;opacity:.8}.bot-card.disabled .bot-avatar[data-v-539ab5ea]{filter:grayscale(1)}.bot-card[data-v-539ab5ea]:hover{transform:translate(-4px,-4px);box-shadow:6px 6px 0 var(--pop-shadow-color)}.bot-header[data-v-539ab5ea]{display:flex;align-items:center;gap:12px;margin-bottom:16px}.bot-avatar[data-v-539ab5ea]{width:64px;height:64px;border-radius:50%;border:var(--pop-border);background:var(--pop-bg);object-fit:cover;box-shadow:2px 2px 0 var(--pop-text)}.bot-info[data-v-539ab5ea]{flex:1;overflow:hidden}.bot-name[data-v-539ab5ea]{font-size:20px;font-weight:900;margin-bottom:4px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-transform:uppercase}.bot-sub[data-v-539ab5ea]{font-size:13px;color:var(--pop-text);background:var(--pop-bg);display:inline-block;padding:2px 6px;border:2px solid var(--pop-text);border-radius:4px;margin-bottom:4px}.bot-id[data-v-539ab5ea]{font-family:Courier New,Courier,monospace;font-size:12px;font-weight:700}.status-badge[data-v-539ab5ea]{border:3px solid var(--pop-text);border-radius:16px;padding:4px 10px;font-size:14px;font-weight:900;box-shadow:2px 2px 0 var(--pop-text);transform:rotate(2deg);text-transform:uppercase}.status-online[data-v-539ab5ea]{background:var(--pop-success);color:var(--pop-text)}.status-offline[data-v-539ab5ea]{background:var(--pop-danger);color:#fff}.status-connecting[data-v-539ab5ea]{background:var(--pop-bg);color:var(--pop-text)}.bot-stats[data-v-539ab5ea]{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-bottom:16px}.stat-box[data-v-539ab5ea]{display:flex;justify-content:space-between;padding:6px 10px;border:2px solid var(--pop-text);border-radius:10px;background:#f8f9fa;box-shadow:2px 2px 0 var(--pop-shadow-color)}.stat-box span[data-v-539ab5ea]{color:#666;font-size:12px;font-weight:700;text-transform:uppercase}.stat-box strong[data-v-539ab5ea]{font-size:16px}.bot-meta[data-v-539ab5ea]{background:var(--pop-secondary);border:2px solid var(--pop-text);padding:8px;border-radius:10px;font-size:12px;margin-bottom:16px;word-break:break-all}.bot-actions[data-v-539ab5ea]{display:flex;flex-wrap:wrap;gap:8px}.form-grid[data-v-539ab5ea]{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:24px}.modal-grid[data-v-539ab5ea]{grid-template-columns:1fr;gap:12px;max-height:50vh;overflow-y:auto;padding-right:8px}.pop-label[data-v-539ab5ea]{display:flex;flex-direction:column;gap:8px;font-size:16px;font-weight:700;text-transform:uppercase}.pop-label.hidden[data-v-539ab5ea]{display:none}.pop-input[data-v-539ab5ea],.pop-select[data-v-539ab5ea],.pop-textarea[data-v-539ab5ea]{border:3px solid var(--pop-text);border-radius:16px;padding:10px 14px;font-size:15px;font-family:inherit;font-weight:700;background:#fff;color:var(--pop-text);box-shadow:inset 2px 2px #0000001a;transition:all .2s}.pop-input[data-v-539ab5ea]:focus,.pop-select[data-v-539ab5ea]:focus,.pop-textarea[data-v-539ab5ea]:focus{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-textarea[data-v-539ab5ea]{resize:vertical}.pop-file-input[data-v-539ab5ea]{border:3px solid var(--pop-text);border-radius:16px;padding:8px;font-size:14px;font-family:inherit;font-weight:700;background:#fff;color:var(--pop-text);box-shadow:inset 2px 2px #0000001a;transition:all .2s;cursor:pointer}.pop-file-input[data-v-539ab5ea]:focus,.pop-file-input[data-v-539ab5ea]:hover{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-file-input[data-v-539ab5ea]::file-selector-button{background:var(--pop-primary);color:#fff;border:2px solid var(--pop-text);border-radius:8px;padding:6px 12px;font-weight:700;cursor:pointer;margin-right:12px;text-transform:uppercase}.pop-checkbox[data-v-539ab5ea]{flex-direction:row;align-items:center;cursor:pointer;background:var(--pop-bg);padding:10px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-shadow-color);transition:transform .1s}.pop-checkbox[data-v-539ab5ea]:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--pop-shadow-color)}.pop-check[data-v-539ab5ea]{width:20px;height:20px;accent-color:var(--pop-primary);border:2px solid var(--pop-text);cursor:pointer}.mini-checkbox[data-v-539ab5ea]{padding:4px 8px;border-radius:8px;font-size:13px;gap:4px;border-width:2px}.mini-check[data-v-539ab5ea]{width:14px;height:14px}.split-grid[data-v-539ab5ea]{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-bottom:24px}.pop-table-editor[data-v-539ab5ea]{border:3px dashed var(--pop-text);background:var(--pop-secondary);border-radius:16px;padding:16px;display:flex;flex-direction:column;gap:12px;position:relative}.pop-table-editor.full-width[data-v-539ab5ea]{grid-column:1/-1;background:#ffb3ff}.table-head[data-v-539ab5ea]{display:flex;justify-content:space-between;align-items:center;font-size:18px;font-weight:900;background:#fff;padding:6px 12px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.table-body[data-v-539ab5ea]{display:flex;flex-direction:column;gap:8px;max-height:250px;overflow-y:auto;padding-right:8px}.empty-row[data-v-539ab5ea]{background:#fff;padding:12px;text-align:center;border:3px solid var(--pop-text);border-radius:16px;font-weight:700;text-transform:uppercase}.editor-row[data-v-539ab5ea]{display:grid;grid-template-columns:1fr 1fr auto;gap:8px;background:#fff;padding:8px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-text)}.editor-row.wide[data-v-539ab5ea]{grid-template-columns:1fr 2fr auto}.mini-input[data-v-539ab5ea]{padding:6px 10px;font-size:14px}.panel-footer[data-v-539ab5ea]{margin-top:24px;padding-top:20px;border-top:3px solid var(--pop-text);display:flex;justify-content:flex-end}.pop-modal-overlay[data-v-539ab5ea]{position:fixed;top:0;right:0;bottom:0;left:0;background:#6b524366;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:1000}.pop-modal[data-v-539ab5ea]{width:min(600px,90vw);position:relative;padding:32px}.pop-modal h3[data-v-539ab5ea]{font-size:32px;margin:0 0 8px;color:var(--pop-primary);text-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.modal-sub[data-v-539ab5ea]{font-family:Courier New,Courier,monospace;background:var(--pop-bg);display:inline-block;padding:4px 8px;border:2px solid var(--pop-text);margin-bottom:20px;font-weight:700}.comic-burst[data-v-539ab5ea]{position:absolute;top:-15px;right:-15px;background:var(--pop-bg);color:var(--pop-text);font-size:24px;font-weight:900;padding:10px;border:var(--pop-border);border-radius:50%;transform:rotate(5deg);box-shadow:4px 4px 0 var(--pop-shadow-color);animation:pop-539ab5ea .5s cubic-bezier(.175,.885,.32,1.275);text-transform:uppercase}@keyframes pop-539ab5ea{0%{transform:scale(0) rotate(0)}to{transform:scale(1) rotate(15deg)}}.modal-actions[data-v-539ab5ea]{display:flex;gap:12px;margin-top:24px;justify-content:flex-end}.pop-toast[data-v-539ab5ea]{position:fixed;bottom:24px;left:50%;transform:translate(-50%);padding:12px 24px;font-size:20px;font-weight:900;z-index:1100;display:flex;align-items:center;gap:12px;animation:slideUp-539ab5ea .3s ease-out;text-transform:uppercase}.pop-toast.success[data-v-539ab5ea]{background:var(--pop-success);color:var(--pop-text)}.pop-toast.error[data-v-539ab5ea]{background:var(--pop-danger);color:#fff}@keyframes slideUp-539ab5ea{0%{transform:translate(-50%,100%);opacity:0}to{transform:translate(-50%);opacity:1}}.empty-state[data-v-539ab5ea]{display:flex;justify-content:center;padding:40px}.comic-speech[data-v-539ab5ea]{position:relative;background:#fff;border:3px solid var(--pop-text);border-radius:16px;padding:20px 30px;font-size:24px;font-weight:700;box-shadow:4px 4px 0 var(--pop-shadow-color);text-transform:uppercase}.comic-speech[data-v-539ab5ea]:after{display:none;content:"";position:absolute;bottom:-20px;left:30px;border-width:12px 12px 0 0;border-style:solid;border-color:#fff transparent transparent transparent}.comic-speech[data-v-539ab5ea]:before{display:none;content:"";position:absolute;bottom:-26px;left:28px;border-width:14px 14px 0 0;border-style:solid;border-color:var(--pop-text) transparent transparent transparent;z-index:-1}[data-v-539ab5ea]::-webkit-scrollbar{width:12px}[data-v-539ab5ea]::-webkit-scrollbar-track{background:var(--pop-bg);border-left:3px solid var(--pop-text)}[data-v-539ab5ea]::-webkit-scrollbar-thumb{background:var(--pop-primary);border:3px solid var(--pop-text);border-radius:0}@media (max-width: 960px){.split-grid[data-v-539ab5ea]{grid-template-columns:1fr}}@media (max-width: 768px){.pop-wrapper[data-v-539ab5ea]{padding:12px}.pop-header[data-v-539ab5ea]{flex-direction:column;text-align:center}.pop-tabs[data-v-539ab5ea]{justify-content:center;width:100%}.pop-btn[data-v-539ab5ea]{flex:1;min-width:45%;text-align:center}.bot-actions .pop-btn[data-v-539ab5ea]{flex:1;min-width:30%}.pop-modal[data-v-539ab5ea]{padding:20px}.comic-speech[data-v-539ab5ea]{font-size:18px}.bot-grid[data-v-539ab5ea]{grid-template-columns:1fr}}
|
|
1
|
+
[data-v-6479fe79] .k-layout,[data-v-6479fe79] .k-layout__main{background:transparent!important;padding:0!important;margin:0!important;height:100%;position:relative}.pop-wrapper[data-v-6479fe79]{--pop-bg: #fffbeb;--pop-text: #6b5243;--pop-border: 3px solid var(--pop-text);--pop-shadow-color: var(--pop-text);--pop-panel: #ffffff;--pop-primary: #ff9a9e;--pop-secondary: #a1c4fd;--pop-success: #b2fba5;--pop-danger: #ffb3ba;--pop-dot: rgba(107, 82, 67, .05);width:100%;height:100%;box-sizing:border-box;color:var(--pop-text);font-family:Nunito,Varela Round,PingFang SC,Microsoft YaHei,sans-serif;background-color:var(--pop-bg);background-image:radial-gradient(var(--pop-dot) 15%,transparent 16%),radial-gradient(var(--pop-dot) 15%,transparent 16%);background-size:24px 24px;background-position:0 0,12px 12px;position:absolute;top:0;left:0;right:0;bottom:0;z-index:0;overflow-y:auto;padding:24px;font-weight:800}.pop-wrapper[data-v-6479fe79] *{box-sizing:border-box}.comic-panel[data-v-6479fe79]{background:var(--pop-panel);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);border-radius:16px}.pop-loading[data-v-6479fe79]{display:flex;justify-content:center;align-items:center;height:60vh}.comic-text[data-v-6479fe79]{font-size:4rem;color:#fff;text-shadow:2px 2px 0 var(--pop-text),-1px -1px 0 var(--pop-text),1px -1px 0 var(--pop-text),-1px 1px 0 var(--pop-text),1px 1px 0 var(--pop-text);transform:rotate(-2deg);animation:pulse-6479fe79 1s infinite alternate}@keyframes pulse-6479fe79{0%{transform:rotate(-5deg) scale(1)}to{transform:rotate(-5deg) scale(1.1)}}.pop-container[data-v-6479fe79]{max-width:1200px;margin:0 auto;display:flex;flex-direction:column;gap:24px}.pop-header[data-v-6479fe79]{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;background:var(--pop-secondary);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);padding:20px 24px;border-radius:16px;position:relative;overflow:hidden}.pop-header[data-v-6479fe79]:before{content:"";position:absolute;top:-50%;left:-50%;width:200%;height:200%;background-image:repeating-linear-gradient(45deg,transparent,transparent 10px,rgba(255,255,255,.2) 10px,rgba(255,255,255,.2) 20px);z-index:0}.pop-header[data-v-6479fe79]>*{position:relative;z-index:1}.brand[data-v-6479fe79]{display:flex;align-items:center;gap:16px}.logo[data-v-6479fe79]{font-size:42px;background:var(--pop-bg);width:72px;height:72px;border-radius:50%;border:var(--pop-border);display:flex;align-items:center;justify-content:center;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:rotate(-5deg)}.title-box h1[data-v-6479fe79]{margin:0;font-size:36px;font-weight:900;color:#fff;text-shadow:2px 2px 0 var(--pop-text),-1px -1px 0 var(--pop-text),1px -1px 0 var(--pop-text),-1px 1px 0 var(--pop-text),1px 1px 0 var(--pop-text);letter-spacing:2px;text-transform:uppercase}.title-box p[data-v-6479fe79]{margin:4px 0 0;background:var(--pop-text);color:#fff;display:inline-block;padding:4px 8px;font-size:14px;transform:skew(-5deg);text-transform:uppercase}.pop-tabs[data-v-6479fe79]{display:flex;gap:12px;flex-wrap:wrap}.pop-btn[data-v-6479fe79]{background:#fff;color:var(--pop-text);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);padding:10px 20px;font-size:16px;font-family:inherit;font-weight:900;cursor:pointer;border-radius:16px;transition:all .1s ease;position:relative;text-transform:uppercase}.pop-btn[data-v-6479fe79]:hover{transform:translate(-2px,-2px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn[data-v-6479fe79]:active{transform:translate(4px,4px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.active[data-v-6479fe79]{background:var(--pop-primary);color:#fff}.pop-btn.primary-btn[data-v-6479fe79]{background:var(--pop-primary);color:#fff;font-size:18px}.pop-btn.action-btn[data-v-6479fe79]{background:#ffb347;color:#fff}.pop-btn.mini[data-v-6479fe79]{padding:6px 12px;font-size:13px;box-shadow:2px 2px 0 var(--pop-shadow-color);border-width:2px}.pop-btn.mini[data-v-6479fe79]:hover{transform:translate(-1px,-1px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn.mini[data-v-6479fe79]:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.danger[data-v-6479fe79]{background:var(--pop-danger);color:#fff}.pop-panel[data-v-6479fe79]{background:var(--pop-panel);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);border-radius:16px;padding:24px;position:relative}.panel-header[data-v-6479fe79]{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:24px;border-bottom:3px solid var(--pop-text);padding-bottom:16px}.panel-title h2[data-v-6479fe79]{margin:0;font-size:28px;color:var(--pop-primary);text-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.panel-title p[data-v-6479fe79]{margin:4px 0 0;font-size:16px;font-weight:700;text-transform:uppercase}.bot-grid[data-v-6479fe79]{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:20px}.bot-card[data-v-6479fe79]{border:var(--pop-border);border-radius:16px;background:#fff;padding:16px;box-shadow:4px 4px 0 var(--pop-shadow-color);transition:transform .2s,box-shadow .2s;position:relative;overflow:hidden}.bot-card[data-v-6479fe79]:before{content:"";position:absolute;top:0;right:0;width:40px;height:40px;background:var(--pop-bg);border-bottom-left-radius:20px;border-left:var(--pop-border);border-bottom:var(--pop-border)}.bot-card.disabled[data-v-6479fe79]{background:#e5e7eb;opacity:.8}.bot-card.disabled .bot-avatar[data-v-6479fe79]{filter:grayscale(1)}.bot-card[data-v-6479fe79]:hover{transform:translate(-4px,-4px);box-shadow:6px 6px 0 var(--pop-shadow-color)}.bot-header[data-v-6479fe79]{display:flex;align-items:center;gap:12px;margin-bottom:16px}.bot-avatar[data-v-6479fe79]{width:64px;height:64px;border-radius:50%;border:var(--pop-border);background:var(--pop-bg);object-fit:cover;box-shadow:2px 2px 0 var(--pop-text)}.bot-info[data-v-6479fe79]{flex:1;overflow:hidden}.bot-name[data-v-6479fe79]{font-size:20px;font-weight:900;margin-bottom:4px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-transform:uppercase}.bot-sub[data-v-6479fe79]{font-size:13px;color:var(--pop-text);background:var(--pop-bg);display:inline-block;padding:2px 6px;border:2px solid var(--pop-text);border-radius:4px;margin-bottom:4px}.bot-id[data-v-6479fe79]{font-family:Courier New,Courier,monospace;font-size:12px;font-weight:700}.status-badge[data-v-6479fe79]{border:3px solid var(--pop-text);border-radius:16px;padding:4px 10px;font-size:14px;font-weight:900;box-shadow:2px 2px 0 var(--pop-text);transform:rotate(2deg);text-transform:uppercase}.status-online[data-v-6479fe79]{background:var(--pop-success);color:var(--pop-text)}.status-offline[data-v-6479fe79]{background:var(--pop-danger);color:#fff}.status-connecting[data-v-6479fe79]{background:var(--pop-bg);color:var(--pop-text)}.bot-stats[data-v-6479fe79]{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-bottom:16px}.stat-box[data-v-6479fe79]{display:flex;justify-content:space-between;padding:6px 10px;border:2px solid var(--pop-text);border-radius:10px;background:#f8f9fa;box-shadow:2px 2px 0 var(--pop-shadow-color)}.stat-box span[data-v-6479fe79]{color:#666;font-size:12px;font-weight:700;text-transform:uppercase}.stat-box strong[data-v-6479fe79]{font-size:16px}.bot-meta[data-v-6479fe79]{background:var(--pop-secondary);border:2px solid var(--pop-text);padding:8px;border-radius:10px;font-size:12px;margin-bottom:16px;word-break:break-all}.bot-actions[data-v-6479fe79]{display:flex;flex-wrap:wrap;gap:8px}.form-grid[data-v-6479fe79]{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:24px}.modal-grid[data-v-6479fe79]{grid-template-columns:1fr;gap:12px;max-height:50vh;overflow-y:auto;padding-right:8px}.pop-label[data-v-6479fe79]{display:flex;flex-direction:column;gap:8px;font-size:16px;font-weight:700;text-transform:uppercase}.pop-label.hidden[data-v-6479fe79]{display:none}.pop-input[data-v-6479fe79],.pop-select[data-v-6479fe79],.pop-textarea[data-v-6479fe79]{border:3px solid var(--pop-text);border-radius:16px;padding:10px 14px;font-size:15px;font-family:inherit;font-weight:700;background:#fff;color:var(--pop-text);box-shadow:inset 2px 2px #0000001a;transition:all .2s}.pop-input[data-v-6479fe79]:focus,.pop-select[data-v-6479fe79]:focus,.pop-textarea[data-v-6479fe79]:focus{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-textarea[data-v-6479fe79]{resize:vertical}.pop-file-input[data-v-6479fe79]{border:3px solid var(--pop-text);border-radius:16px;padding:8px;font-size:14px;font-family:inherit;font-weight:700;background:#fff;color:var(--pop-text);box-shadow:inset 2px 2px #0000001a;transition:all .2s;cursor:pointer}.pop-file-input[data-v-6479fe79]:focus,.pop-file-input[data-v-6479fe79]:hover{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-file-input[data-v-6479fe79]::file-selector-button{background:var(--pop-primary);color:#fff;border:2px solid var(--pop-text);border-radius:8px;padding:6px 12px;font-weight:700;cursor:pointer;margin-right:12px;text-transform:uppercase}.pop-checkbox[data-v-6479fe79]{flex-direction:row;align-items:center;cursor:pointer;background:var(--pop-bg);padding:10px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-shadow-color);transition:transform .1s}.pop-checkbox[data-v-6479fe79]:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--pop-shadow-color)}.pop-check[data-v-6479fe79]{width:20px;height:20px;accent-color:var(--pop-primary);border:2px solid var(--pop-text);cursor:pointer}.mini-checkbox[data-v-6479fe79]{padding:4px 8px;border-radius:8px;font-size:13px;gap:4px;border-width:2px}.mini-check[data-v-6479fe79]{width:14px;height:14px}.split-grid[data-v-6479fe79]{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-bottom:24px}.list-summary-box[data-v-6479fe79]{display:flex;align-items:center;justify-content:space-between;background:#fff;border:3px solid var(--pop-text);border-radius:12px;padding:8px 12px;box-shadow:2px 2px 0 var(--pop-shadow-color);margin-top:4px}.list-count[data-v-6479fe79]{font-size:14px;font-weight:900;color:var(--pop-primary)}.pop-table-editor[data-v-6479fe79]{border:3px dashed var(--pop-text);background:var(--pop-secondary);border-radius:16px;padding:16px;display:flex;flex-direction:column;gap:12px;position:relative}.pop-table-editor.full-width[data-v-6479fe79]{grid-column:1/-1;background:#ffb3ff}.table-head[data-v-6479fe79]{display:flex;justify-content:space-between;align-items:center;font-size:18px;font-weight:900;background:#fff;padding:6px 12px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.table-body[data-v-6479fe79]{display:flex;flex-direction:column;gap:8px;max-height:250px;overflow-y:auto;padding-right:8px}.empty-row[data-v-6479fe79]{background:#fff;padding:12px;text-align:center;border:3px solid var(--pop-text);border-radius:16px;font-weight:700;text-transform:uppercase}.editor-row[data-v-6479fe79]{display:grid;grid-template-columns:1fr 1fr auto;gap:8px;background:#fff;padding:8px;border:3px solid var(--pop-text);border-radius:16px;box-shadow:2px 2px 0 var(--pop-text)}.editor-row.wide[data-v-6479fe79]{grid-template-columns:1fr 2fr auto}.mini-input[data-v-6479fe79]{padding:6px 10px;font-size:14px}.panel-footer[data-v-6479fe79]{margin-top:24px;padding-top:20px;border-top:3px solid var(--pop-text);display:flex;justify-content:flex-end}.pop-modal-overlay[data-v-6479fe79]{position:fixed;top:0;right:0;bottom:0;left:0;background:#6b524366;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:1000}.pop-modal[data-v-6479fe79]{width:min(600px,90vw);position:relative;padding:32px}.pop-modal h3[data-v-6479fe79]{font-size:32px;margin:0 0 8px;color:var(--pop-primary);text-shadow:2px 2px 0 var(--pop-text);text-transform:uppercase}.modal-sub[data-v-6479fe79]{font-family:Courier New,Courier,monospace;background:var(--pop-bg);display:inline-block;padding:4px 8px;border:2px solid var(--pop-text);margin-bottom:20px;font-weight:700}.comic-burst[data-v-6479fe79]{position:absolute;top:-15px;right:-15px;background:var(--pop-bg);color:var(--pop-text);font-size:24px;font-weight:900;padding:10px;border:var(--pop-border);border-radius:50%;transform:rotate(5deg);box-shadow:4px 4px 0 var(--pop-shadow-color);animation:pop-6479fe79 .5s cubic-bezier(.175,.885,.32,1.275);text-transform:uppercase}@keyframes pop-6479fe79{0%{transform:scale(0) rotate(0)}to{transform:scale(1) rotate(15deg)}}.modal-actions[data-v-6479fe79]{display:flex;gap:12px;margin-top:24px;justify-content:flex-end}.pop-toast[data-v-6479fe79]{position:fixed;bottom:24px;left:50%;transform:translate(-50%);padding:12px 24px;font-size:20px;font-weight:900;z-index:1100;display:flex;align-items:center;gap:12px;animation:slideUp-6479fe79 .3s ease-out;text-transform:uppercase}.pop-toast.success[data-v-6479fe79]{background:var(--pop-success);color:var(--pop-text)}.pop-toast.error[data-v-6479fe79]{background:var(--pop-danger);color:#fff}@keyframes slideUp-6479fe79{0%{transform:translate(-50%,100%);opacity:0}to{transform:translate(-50%);opacity:1}}.empty-state[data-v-6479fe79]{display:flex;justify-content:center;padding:40px}.comic-speech[data-v-6479fe79]{position:relative;background:#fff;border:3px solid var(--pop-text);border-radius:16px;padding:20px 30px;font-size:24px;font-weight:700;box-shadow:4px 4px 0 var(--pop-shadow-color);text-transform:uppercase}.comic-speech[data-v-6479fe79]:after{display:none;content:"";position:absolute;bottom:-20px;left:30px;border-width:12px 12px 0 0;border-style:solid;border-color:#fff transparent transparent transparent}.comic-speech[data-v-6479fe79]:before{display:none;content:"";position:absolute;bottom:-26px;left:28px;border-width:14px 14px 0 0;border-style:solid;border-color:var(--pop-text) transparent transparent transparent;z-index:-1}[data-v-6479fe79]::-webkit-scrollbar{width:12px}[data-v-6479fe79]::-webkit-scrollbar-track{background:var(--pop-bg);border-left:3px solid var(--pop-text)}[data-v-6479fe79]::-webkit-scrollbar-thumb{background:var(--pop-primary);border:3px solid var(--pop-text);border-radius:0}@media (max-width: 960px){.split-grid[data-v-6479fe79]{grid-template-columns:1fr}}@media (max-width: 768px){.pop-wrapper[data-v-6479fe79]{padding:12px}.pop-header[data-v-6479fe79]{flex-direction:column;text-align:center}.pop-tabs[data-v-6479fe79]{justify-content:center;width:100%}.pop-btn[data-v-6479fe79]{flex:1;min-width:45%;text-align:center}.bot-actions .pop-btn[data-v-6479fe79]{flex:1;min-width:30%}.pop-modal[data-v-6479fe79]{padding:20px}.comic-speech[data-v-6479fe79]{font-size:18px}.bot-grid[data-v-6479fe79]{grid-template-columns:1fr}}
|
package/lib/config-store.d.ts
CHANGED
|
@@ -20,17 +20,29 @@ export interface StoreConfig {
|
|
|
20
20
|
bots: ManagedBotConfig[];
|
|
21
21
|
loadBalance: Required<LoadBalanceConfig>;
|
|
22
22
|
}
|
|
23
|
+
type ExternalChangeListener = (next: StoreConfig, prev: StoreConfig) => void | Promise<void>;
|
|
23
24
|
export declare class ConfigStore {
|
|
24
25
|
private ctx;
|
|
25
26
|
private configRoot;
|
|
26
27
|
private configPath;
|
|
27
28
|
private config;
|
|
28
29
|
private saveTimer;
|
|
30
|
+
private reloadTimer;
|
|
31
|
+
private skipWatchUntil;
|
|
32
|
+
private watching;
|
|
33
|
+
private externalChangeListeners;
|
|
34
|
+
private logger;
|
|
35
|
+
private readonly onFileChanged;
|
|
29
36
|
constructor(ctx: Context);
|
|
30
37
|
private ensureDir;
|
|
31
38
|
private normalize;
|
|
32
39
|
private loadConfig;
|
|
40
|
+
private startWatching;
|
|
41
|
+
private stopWatching;
|
|
42
|
+
private scheduleReloadFromDisk;
|
|
43
|
+
private reloadFromDisk;
|
|
33
44
|
private saveConfigSync;
|
|
45
|
+
onExternalChange(listener: ExternalChangeListener): () => void;
|
|
34
46
|
private scheduleSave;
|
|
35
47
|
getAll(): StoreConfig;
|
|
36
48
|
getRuntime(): RuntimeConfig;
|
|
@@ -40,4 +52,6 @@ export declare class ConfigStore {
|
|
|
40
52
|
setLoadBalance(loadBalance: Partial<LoadBalanceConfig>): void;
|
|
41
53
|
setBots(bots: ManagedBotConfig[]): void;
|
|
42
54
|
flush(): void;
|
|
55
|
+
dispose(): void;
|
|
43
56
|
}
|
|
57
|
+
export {};
|
package/lib/index.js
CHANGED
|
@@ -1695,11 +1695,11 @@ var LoadBalancer = class {
|
|
|
1695
1695
|
selectedBot = this.selectBotByGreedy(validBots, botRemainingCapacity, botLoad);
|
|
1696
1696
|
}
|
|
1697
1697
|
if (!selectedBot) {
|
|
1698
|
-
const
|
|
1699
|
-
if (
|
|
1698
|
+
const unassignedValue2 = this.config.unassignedValue;
|
|
1699
|
+
if (unassignedValue2 !== void 0 && unassignedValue2 !== "") {
|
|
1700
1700
|
const lastAssignee2 = this.lastAssignees.get(channel.channelId);
|
|
1701
|
-
if (lastAssignee2 !==
|
|
1702
|
-
assignments.push({ channelId: channel.channelId, assignee:
|
|
1701
|
+
if (lastAssignee2 !== unassignedValue2) {
|
|
1702
|
+
assignments.push({ channelId: channel.channelId, assignee: unassignedValue2 });
|
|
1703
1703
|
this.logger.info(`群 ${channel.channelId} 所有 Bot 达到上限,设为未分配`);
|
|
1704
1704
|
}
|
|
1705
1705
|
} else {
|
|
@@ -1725,14 +1725,28 @@ var LoadBalancer = class {
|
|
|
1725
1725
|
const channels2 = this.botChannels.get(id);
|
|
1726
1726
|
return channels2 && channels2.size > 0;
|
|
1727
1727
|
});
|
|
1728
|
-
const
|
|
1728
|
+
const managedChannels = channels.filter((c) => this.shouldManageChannel(c.channelId));
|
|
1729
|
+
const priorityCount = managedChannels.filter((c) => c.isPriority).length;
|
|
1730
|
+
const configuredPriorityCount = new Set(this.config.priorityChannels || []).size;
|
|
1731
|
+
const unassignedValue = this.config.unassignedValue || "";
|
|
1732
|
+
let assignedTotal = 0;
|
|
1733
|
+
let unassignedTotal = 0;
|
|
1734
|
+
for (const [, assignee] of this.lastAssignees.entries()) {
|
|
1735
|
+
if (assignee && assignee !== unassignedValue) {
|
|
1736
|
+
assignedTotal++;
|
|
1737
|
+
} else {
|
|
1738
|
+
unassignedTotal++;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1729
1741
|
if (botsWithData.length > 0) {
|
|
1730
1742
|
const loads = botsWithData.map((id) => botLoad.get(id) || 0);
|
|
1731
1743
|
const avg = loads.reduce((a, b) => a + b, 0) / loads.length;
|
|
1732
1744
|
const variance = loads.reduce((sum, load) => sum + Math.pow(load - avg, 2), 0) / loads.length;
|
|
1733
1745
|
const stdDev = Math.sqrt(variance);
|
|
1734
1746
|
const loadInfo = botsWithData.map((id) => `${id}:${botLoad.get(id) || 0}`).join(", ");
|
|
1735
|
-
this.logger.info(
|
|
1747
|
+
this.logger.info(
|
|
1748
|
+
`负载均衡完成,本轮变更 ${assignments.length} 个群;当前已分配 ${assignedTotal} 个,未分配 ${unassignedTotal} 个;关键群(参与调度)${priorityCount} / 配置总数 ${configuredPriorityCount}`
|
|
1749
|
+
);
|
|
1736
1750
|
this.logger.info(`负载分布: [${loadInfo}],平均: ${avg.toFixed(1)},标准差: ${stdDev.toFixed(2)}`);
|
|
1737
1751
|
}
|
|
1738
1752
|
} catch (e) {
|
|
@@ -1914,10 +1928,12 @@ var DEFAULT_CONFIG = {
|
|
|
1914
1928
|
var ConfigStore = class {
|
|
1915
1929
|
constructor(ctx) {
|
|
1916
1930
|
this.ctx = ctx;
|
|
1931
|
+
this.logger = this.ctx.logger("adapter-onebot-multi");
|
|
1917
1932
|
this.configRoot = path.join(ctx.baseDir, "data", "adapter-onebot-multi");
|
|
1918
1933
|
this.configPath = path.join(this.configRoot, "config.yaml");
|
|
1919
1934
|
this.ensureDir(this.configRoot);
|
|
1920
1935
|
this.loadConfig();
|
|
1936
|
+
this.startWatching();
|
|
1921
1937
|
}
|
|
1922
1938
|
static {
|
|
1923
1939
|
__name(this, "ConfigStore");
|
|
@@ -1926,6 +1942,17 @@ var ConfigStore = class {
|
|
|
1926
1942
|
configPath;
|
|
1927
1943
|
config = structuredClone(DEFAULT_CONFIG);
|
|
1928
1944
|
saveTimer = null;
|
|
1945
|
+
reloadTimer = null;
|
|
1946
|
+
skipWatchUntil = 0;
|
|
1947
|
+
watching = false;
|
|
1948
|
+
externalChangeListeners = /* @__PURE__ */ new Set();
|
|
1949
|
+
logger;
|
|
1950
|
+
onFileChanged = /* @__PURE__ */ __name((curr, prev) => {
|
|
1951
|
+
if (!this.watching) return;
|
|
1952
|
+
if (curr.mtimeMs === prev.mtimeMs) return;
|
|
1953
|
+
if (Date.now() < this.skipWatchUntil) return;
|
|
1954
|
+
this.scheduleReloadFromDisk();
|
|
1955
|
+
}, "onFileChanged");
|
|
1929
1956
|
ensureDir(dir) {
|
|
1930
1957
|
if (!fs.existsSync(dir)) {
|
|
1931
1958
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -1981,15 +2008,57 @@ var ConfigStore = class {
|
|
|
1981
2008
|
const parsed = yaml.parse(content);
|
|
1982
2009
|
this.config = this.normalize(parsed);
|
|
1983
2010
|
} catch (error) {
|
|
1984
|
-
this.
|
|
2011
|
+
this.logger.warn("读取配置失败,使用默认配置: %s", error);
|
|
1985
2012
|
this.config = structuredClone(DEFAULT_CONFIG);
|
|
1986
2013
|
this.saveConfigSync();
|
|
1987
2014
|
}
|
|
1988
2015
|
}
|
|
2016
|
+
startWatching() {
|
|
2017
|
+
if (this.watching) return;
|
|
2018
|
+
this.watching = true;
|
|
2019
|
+
fs.watchFile(this.configPath, { interval: 1e3 }, this.onFileChanged);
|
|
2020
|
+
}
|
|
2021
|
+
stopWatching() {
|
|
2022
|
+
if (!this.watching) return;
|
|
2023
|
+
fs.unwatchFile(this.configPath, this.onFileChanged);
|
|
2024
|
+
this.watching = false;
|
|
2025
|
+
}
|
|
2026
|
+
scheduleReloadFromDisk() {
|
|
2027
|
+
if (this.reloadTimer) clearTimeout(this.reloadTimer);
|
|
2028
|
+
this.reloadTimer = setTimeout(() => {
|
|
2029
|
+
this.reloadTimer = null;
|
|
2030
|
+
this.reloadFromDisk();
|
|
2031
|
+
}, 200);
|
|
2032
|
+
}
|
|
2033
|
+
reloadFromDisk() {
|
|
2034
|
+
try {
|
|
2035
|
+
const content = fs.readFileSync(this.configPath, "utf8");
|
|
2036
|
+
const parsed = yaml.parse(content);
|
|
2037
|
+
const normalized = this.normalize(parsed);
|
|
2038
|
+
const prev = structuredClone(this.config);
|
|
2039
|
+
if (JSON.stringify(prev) === JSON.stringify(normalized)) return;
|
|
2040
|
+
this.config = normalized;
|
|
2041
|
+
this.logger.info("检测到配置文件变更,已重新加载。");
|
|
2042
|
+
for (const listener of this.externalChangeListeners) {
|
|
2043
|
+
Promise.resolve(listener(structuredClone(this.config), prev)).catch((error) => {
|
|
2044
|
+
this.logger.warn("配置变更回调执行失败: %s", error);
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
} catch (error) {
|
|
2048
|
+
this.logger.warn("重新加载配置失败,忽略本次变更: %s", error);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
1989
2051
|
saveConfigSync() {
|
|
2052
|
+
this.skipWatchUntil = Date.now() + 300;
|
|
1990
2053
|
const content = yaml.stringify(this.config, { indent: 2, lineWidth: 120 });
|
|
1991
2054
|
fs.writeFileSync(this.configPath, content, "utf8");
|
|
1992
2055
|
}
|
|
2056
|
+
onExternalChange(listener) {
|
|
2057
|
+
this.externalChangeListeners.add(listener);
|
|
2058
|
+
return () => {
|
|
2059
|
+
this.externalChangeListeners.delete(listener);
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
1993
2062
|
scheduleSave() {
|
|
1994
2063
|
if (this.saveTimer) clearTimeout(this.saveTimer);
|
|
1995
2064
|
this.saveTimer = setTimeout(() => {
|
|
@@ -2037,6 +2106,14 @@ var ConfigStore = class {
|
|
|
2037
2106
|
}
|
|
2038
2107
|
this.saveConfigSync();
|
|
2039
2108
|
}
|
|
2109
|
+
dispose() {
|
|
2110
|
+
if (this.reloadTimer) {
|
|
2111
|
+
clearTimeout(this.reloadTimer);
|
|
2112
|
+
this.reloadTimer = null;
|
|
2113
|
+
}
|
|
2114
|
+
this.stopWatching();
|
|
2115
|
+
this.flush();
|
|
2116
|
+
}
|
|
2040
2117
|
};
|
|
2041
2118
|
|
|
2042
2119
|
// src/index.ts
|
|
@@ -2066,6 +2143,28 @@ function apply(ctx, _config) {
|
|
|
2066
2143
|
}, "getGlobalConfig");
|
|
2067
2144
|
ctx._onebotMultiGlobalConfig = getGlobalConfig();
|
|
2068
2145
|
const loadBalancer = new LoadBalancer(ctx, configStore.getLoadBalance(), statusManager);
|
|
2146
|
+
const stopConfigWatcher = configStore.onExternalChange(async (next, prev) => {
|
|
2147
|
+
const runtimeChanged = JSON.stringify(prev.runtime) !== JSON.stringify(next.runtime);
|
|
2148
|
+
const loadBalanceChanged = JSON.stringify(prev.loadBalance) !== JSON.stringify(next.loadBalance);
|
|
2149
|
+
const botsChanged = JSON.stringify(prev.bots) !== JSON.stringify(next.bots);
|
|
2150
|
+
if (runtimeChanged) {
|
|
2151
|
+
;
|
|
2152
|
+
ctx._onebotMultiGlobalConfig = getGlobalConfig();
|
|
2153
|
+
const restartTargets = configStore.getBots().filter((bot) => bot.enabled !== false).map((bot) => bot.selfId);
|
|
2154
|
+
for (const selfId of restartTargets) {
|
|
2155
|
+
await restartBot(selfId);
|
|
2156
|
+
}
|
|
2157
|
+
logger.info("检测到 runtime 配置更新,已重启启用中的 Bot。");
|
|
2158
|
+
}
|
|
2159
|
+
if (loadBalanceChanged) {
|
|
2160
|
+
loadBalancer.updateConfig(configStore.getLoadBalance());
|
|
2161
|
+
logger.info("检测到 loadBalance 配置更新,已应用。");
|
|
2162
|
+
}
|
|
2163
|
+
if (botsChanged) {
|
|
2164
|
+
await syncBots();
|
|
2165
|
+
logger.info("检测到 bots 配置更新,已同步 Bot 状态。");
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2069
2168
|
const getBotListView = /* @__PURE__ */ __name(() => {
|
|
2070
2169
|
const runtime = statusManager.getStatus();
|
|
2071
2170
|
const runtimeMap = new Map(runtime.bots.map((b) => [String(b.selfId), b]));
|
|
@@ -2344,11 +2443,12 @@ function apply(ctx, _config) {
|
|
|
2344
2443
|
logger.info(`Bot 配置 selfId 自动更新: ${configKey} -> ${runtimeSelfId}`);
|
|
2345
2444
|
});
|
|
2346
2445
|
ctx.on("dispose", async () => {
|
|
2446
|
+
stopConfigWatcher();
|
|
2347
2447
|
for (const selfId of Array.from(managedBotIds)) {
|
|
2348
2448
|
await stopBot(selfId);
|
|
2349
2449
|
}
|
|
2350
2450
|
loadBalancer.dispose();
|
|
2351
|
-
configStore.
|
|
2451
|
+
configStore.dispose();
|
|
2352
2452
|
});
|
|
2353
2453
|
}
|
|
2354
2454
|
__name(apply, "apply");
|