koishi-plugin-adapter-onebot-multi 1.0.6 → 2.0.0

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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import{send as w,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(U){const B=b(true),C=b("bots"),V=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(""),T=b([]),M=b([]),k=b(null),$=b(""),P=b("create"),X=b(""),u=b(null),I=b(null),j=b(""),h=b(null),S=b(""),_=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"?$.value=L.value:s==="whitelist"?$.value=E.value:s==="priority"&&($.value=A.value)}function et(){const s=$.value.split(`
3
- `).map(x=>x.trim()).filter(x=>/^\d+$/.test(x)),t=Array.from(new Set(s)).join(`
4
- `);k.value==="blacklist"?L.value=t:k.value==="whitelist"?E.value=t:k.value==="priority"&&(A.value=t),k.value=null,c("success","列表已暂存,请点击保存规则生效")}function c(s,t){_.type=s,_.message=t,_.show=true,setTimeout(()=>{_.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
- `),T.value=Object.entries(v.botMaxLoad||{}).map(([s,t])=>({botId:s,maxLoad:Number(t)||0})),M.value=Object.entries(v.channelBotPriority||{}).map(([s,t])=>({channelId:s,botIds:Array.isArray(t)?[...t]:[]}))}function nt(){T.value.push({botId:"",maxLoad:0})}function ot(s){T.value.splice(s,1)}function at(){M.value.push({channelId:"",botIds:[]})}function it(s){M.value.splice(s,1)}async function g(){if(!H){H=true;try{const s=await w("onebot-multi/state");V.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 w("onebot-multi/bots/create",u.value):await w("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 w("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 w("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 w("onebot-multi/bots/restart",{selfId:s.selfId}),await g(),c("success","重启已触发")}catch(t){c("error",(t==null?void 0:t.message)||"重启失败")}}function bt(s){I.value=s,j.value=s.nickname||""}async function mt(){if(I.value)try{const s=await w("onebot-multi/bots/profile",{selfId:I.value.selfId,nickname:j.value});if(!(s!=null&&s.success))throw new Error((s==null?void 0:s.error)||"保存失败");I.value=null,await g(),c("success","昵称已更新")}catch(s){c("error",(s==null?void 0:s.message)||"更新失败")}}function ft(s){h.value=s,S.value=""}function yt(s){var r;const x=(r=s.target.files)==null?void 0:r[0];if(!x){S.value="";return}const l=new FileReader;l.onload=n=>{var W;S.value=(W=n.target)==null?void 0:W.result},l.readAsDataURL(x)}async function kt(){if(!h.value||!S.value.trim()){c("error","请先选择图片文件");return}try{const s=await w("onebot-multi/bots/avatar",{selfId:h.value.selfId,file:S.value});if(!(s!=null&&s.success))throw new Error((s==null?void 0:s.error)||"保存失败");h.value=null,c("success","头像已更新")}catch(s){c("error",(s==null?void 0:s.message)||"更新失败")}}async function gt(){try{await w("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 T.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 M.value){const r=l.channelId.trim();if(!r)continue;const n=(l.botIds||[]).filter(Boolean);n.length>0&&(t[r]=n)}const x={...v,channelBlacklist:F(L.value),channelWhitelist:F(E.value),priorityChannels:F(A.value),botMaxLoad:s,channelBotPriority:t};await w("onebot-multi/settings/load-balance/update",x),await g(),c("success","负载均衡设置已保存")}catch(s){c("error",(s==null?void 0:s.message)||"保存失败")}}return ht(async()=>{await g(),B.value=false,D=setInterval(()=>{g()},5e3)}),_t(()=>{D&&(clearInterval(D),D=null)}),(s,t)=>{const x=Bt("k-layout");return a(),Vt(x,null,{default:Ut(()=>[e("div",Tt,[B.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:C.value==="bots"}]),onClick:t[0]||(t[0]=l=>C.value="bots")},"Bot 管理",2),e("button",{class:O(["pop-btn",{active:C.value==="balance"}]),onClick:t[1]||(t[1]=l=>C.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},"新增节点")]),V.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(V.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,C.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,[T.value.length===0?(a(),i("div",Ue,"暂无规则。")):m("v-if",true),(a(true),i(R,null,N(T.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(V.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,[M.value.length===0?(a(),i("div",Se,"暂无规则。")):m("v-if",true),(a(true),i(R,null,N(M.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(V.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,C.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 "),I.value?(a(),i("div",{key:3,class:"pop-modal-overlay",onClick:t[27]||(t[27]=G(l=>I.value=null,["self"]))},[e("div",Qe,[t[73]||(t[73]=e("h3",null,"修改昵称",-1)),e("p",Ye,d(I.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=>I.value=null)},"取消")])])])):m("v-if",true),m(" Avatar Modal "),h.value?(a(),i("div",{key:4,class:"pop-modal-overlay",onClick:t[29]||(t[29]=G(l=>h.value=null,["self"]))},[e("div",el,[t[75]||(t[75]=e("h3",null,"修改头像",-1)),e("p",ll,d(h.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=>h.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=>$.value=l),rows:"10",class:"pop-textarea",style:{width:"100%"}},null,512),[[f,$.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 "),_.show?(a(),i("div",{key:6,class:O(["pop-toast comic-panel",_.type])},[_.type==="success"?(a(),i("span",il,"✓")):(a(),i("span",ul,"✕")),p(" "+d(_.message),1)],2)):m("v-if",true)])]),_:1})}}}),Z=(U,B)=>{const C=U.__vccOpts||U;for(const[V,y]of B)C[V]=y;return C},dl=Z(pl,[["__scopeId","data-v-3a32f70e"]]),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(U,B){return a(),i("svg",cl,[...B[0]||(B[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=U=>{U.page({name:"OneBot Multi",path:"/onebot-multi",component:dl,icon:"activity:onebot-multi",order:600})};export{yl as default};
1
+ import{send as $,icons as Ut}from"@koishijs/client";import{defineComponent as ft,reactive as G,watch as Lt,openBlock as a,createElementBlock as d,withModifiers as K,createElementVNode as t,toDisplayString as o,createTextVNode as b,withDirectives as v,vModelText as y,vModelCheckbox as q,ref as f,computed as W,onMounted as Tt,onUnmounted as Et,resolveComponent as Rt,createBlock as vt,withCtx as St,normalizeClass as U,Fragment as L,renderList as T,createCommentVNode as x,vShow as mt,vModelSelect as bt}from"vue";const jt={class:"editor-card","aria-label":"Bot 编辑弹窗"},At={class:"editor-header"},Ot={class:"editor-grid"},Pt={class:"field-label"},Ft={class:"field-label hidden-field"},zt={class:"field-label"},Nt={key:0,class:"field-label"},Qt={key:1,class:"field-label"},Dt={class:"field-checkbox"},Wt={class:"editor-actions"},Gt=ft({__name:"BotEditorModal",props:{modelValue:{},mode:{},kind:{}},emits:["close","save"],setup(C){const _=C,p=G({..._.modelValue});return Lt(()=>_.modelValue,g=>{Object.assign(p,g)},{deep:true,immediate:true}),(g,s)=>(a(),d("div",{class:"editor-overlay",onClick:s[9]||(s[9]=K(i=>g.$emit("close"),["self"]))},[t("section",jt,[t("header",At,[t("div",null,[t("h3",null,o(C.mode==="create"?C.kind==="client"?"新增 ws 客户端":"新增 ws 服务器":"编辑 Bot"),1),t("p",null,o(C.mode==="create"?"填写必要信息后即可创建。":"修改后会保存到本地配置文件。"),1)]),t("button",{type:"button",class:"close-button","aria-label":"关闭编辑弹窗",onClick:s[0]||(s[0]=i=>g.$emit("close"))},"×")]),t("div",Ot,[t("label",Pt,[s[10]||(s[10]=b(" 名称 ",-1)),v(t("input",{"onUpdate:modelValue":s[1]||(s[1]=i=>p.name=i),name:"name",autocomplete:"off",type:"text",placeholder:"例如:主客户端…",class:"field-input"},null,512),[[y,p.name]])]),t("label",Ft,[s[11]||(s[11]=b(" 自身 ID ",-1)),v(t("input",{"onUpdate:modelValue":s[2]||(s[2]=i=>p.selfId=i),name:"selfId",autocomplete:"off",type:"text",class:"field-input"},null,512),[[y,p.selfId]])]),t("label",zt,[s[12]||(s[12]=b(" 访问密钥 ",-1)),v(t("input",{"onUpdate:modelValue":s[3]||(s[3]=i=>p.token=i),name:"token",autocomplete:"off",type:"text",placeholder:"留空表示不校验…",class:"field-input"},null,512),[[y,p.token]])]),p.protocol==="ws"?(a(),d("label",Nt,[s[13]||(s[13]=b(" 连接地址 ",-1)),v(t("input",{"onUpdate:modelValue":s[4]||(s[4]=i=>p.endpoint=i),name:"endpoint",autocomplete:"off",type:"url",inputmode:"url",placeholder:"ws://127.0.0.1:6700…",class:"field-input"},null,512),[[y,p.endpoint]])])):(a(),d("label",Qt,[s[14]||(s[14]=b(" 接入路径 ",-1)),v(t("input",{"onUpdate:modelValue":s[5]||(s[5]=i=>p.path=i),name:"path",autocomplete:"off",type:"text",placeholder:"/onebot…",class:"field-input"},null,512),[[y,p.path]])])),t("label",Dt,[v(t("input",{"onUpdate:modelValue":s[6]||(s[6]=i=>p.enabled=i),name:"enabled",type:"checkbox"},null,512),[[q,p.enabled]]),s[15]||(s[15]=t("span",null,"创建后立即启用",-1))])]),t("footer",Wt,[t("button",{type:"button",class:"action-button primary",onClick:s[7]||(s[7]=i=>g.$emit("save",{...p}))},"保存"),t("button",{type:"button",class:"action-button",onClick:s[8]||(s[8]=i=>g.$emit("close"))},"取消")])])]))}}),st=(C,_)=>{const p=C.__vccOpts||C;for(const[g,s]of _)p[g]=s;return p},Kt=st(Gt,[["__scopeId","data-v-66180dfa"]]),qt={class:"page-shell"},Ht={key:0,class:"loading-state","aria-live":"polite"},Jt={key:1,id:"main-content",class:"page-body"},Xt={class:"hero-card"},Yt={class:"hero-actions"},Zt={class:"tab-bar","aria-label":"页面分区"},te={class:"panel-card"},ee={key:0,class:"empty-card"},le={key:1,class:"bot-sections"},ne={key:0,class:"bot-section-block"},se={class:"server-group-list"},oe={class:"server-group-header"},ae={class:"server-group-title-row"},ie={class:"server-group-title"},ue={class:"server-tag"},de={class:"server-group-path",translate:"no"},re={class:"server-group-meta"},ce={class:"server-count"},pe={class:"server-count"},ve={key:0,class:"card-actions section-actions"},me=["onClick"],be=["onClick"],fe=["onClick"],ye={key:1,class:"empty-row"},ke={key:2,class:"bot-grid inner-bot-grid"},ge={class:"bot-card-header"},he=["src"],Ce={class:"bot-summary"},_e={class:"bot-name"},we={class:"bot-subtitle"},Ie={class:"bot-id",translate:"no"},$e={class:"stat-grid"},xe={class:"stat-item"},Be={class:"stat-item"},Ve={class:"stat-item"},Me={class:"stat-item"},Ue={class:"detail-card"},Le={class:"card-actions"},Te=["onClick"],Ee=["onClick"],Re=["onClick"],Se=["onClick"],je=["onClick"],Ae=["onClick"],Oe={key:1,class:"bot-section-block"},Pe={class:"bot-grid"},Fe={class:"bot-card-header"},ze=["src"],Ne={class:"bot-summary"},Qe={class:"bot-name"},De={class:"bot-subtitle"},We={class:"bot-id",translate:"no"},Ge={class:"stat-grid"},Ke={class:"stat-item"},qe={class:"stat-item"},He={class:"stat-item"},Je={class:"stat-item"},Xe={class:"detail-card"},Ye={class:"card-actions"},Ze=["onClick"],tl=["onClick"],el=["onClick"],ll=["onClick"],nl=["onClick"],sl=["onClick"],ol={class:"runtime-grid"},al={class:"field-label"},il={class:"field-label"},ul={class:"field-label"},dl={class:"field-label"},rl={class:"field-label"},cl={class:"checkbox-card"},pl={class:"panel-card"},vl={class:"balance-grid"},ml={class:"checkbox-card"},bl={class:"field-label"},fl={class:"field-label"},yl={class:"field-label"},kl={class:"field-label"},gl={class:"summary-grid"},hl={class:"summary-card"},Cl={class:"summary-card"},_l={class:"summary-card"},wl={class:"config-grid"},Il={class:"sub-panel"},$l={class:"sub-panel-body"},xl={key:0,class:"empty-row"},Bl=["onUpdate:modelValue"],Vl=["value"],Ml=["onUpdate:modelValue"],Ul=["onClick"],Ll={class:"sub-panel sub-panel-wide"},Tl={class:"sub-panel-body"},El={key:0,class:"empty-row"},Rl={class:"priority-top"},Sl=["onUpdate:modelValue"],jl=["onClick"],Al={class:"bot-choice-list"},Ol=["value","onUpdate:modelValue"],Pl={class:"simple-modal","aria-label":"修改昵称"},Fl={class:"simple-modal-header"},zl={class:"modal-note",translate:"no"},Nl={class:"field-label"},Ql={class:"footer-actions compact-actions"},Dl={class:"simple-modal","aria-label":"修改头像"},Wl={class:"simple-modal-header"},Gl={class:"modal-note",translate:"no"},Kl={class:"field-label"},ql={class:"footer-actions compact-actions"},Hl={class:"simple-modal","aria-label":"编辑群号列表"},Jl={class:"simple-modal-header"},Xl={class:"field-label"},Yl={class:"footer-actions compact-actions"},Zl=ft({__name:"page",setup(C){const _=f(true),p=f("bots"),g=f([]),s=G({responseTimeout:6e4,heartbeatInterval:3e4,retryTimes:6,retryInterval:5e3,retryLazy:6e4,advanced:{splitMixedContent:true}}),i=G({enabled:false,balanceInterval:600,channelFilterMode:"blacklist",channelBlacklist:[],channelWhitelist:[],priorityChannels:[],defaultMaxLoad:0,botMaxLoad:{},unassignedValue:"",channelBotPriority:{}}),j=f(""),A=f(""),O=f(""),E=f([]),R=f([]),h=f(null),S=f(""),z=f("create"),H=f("server"),J=f(""),w=f(null),B=f(null),N=f(""),V=f(null),P=f(""),M=G({show:false,type:"success",message:""});let Q=null,X=false;const yt=W(()=>h.value==="blacklist"?"编辑群黑名单":h.value==="whitelist"?"编辑群白名单":h.value==="priority"?"编辑优先群聊":"编辑列表"),Y=n=>n.protocol==="ws-reverse"&&String(n.selfId||"").startsWith("pending_"),ot=W(()=>g.value.filter(n=>!Y(n))),at=W(()=>g.value.filter(n=>n.protocol==="ws")),it=W(()=>{const n=g.value.filter(Y),e=g.value.filter(l=>l.protocol==="ws-reverse"&&!Y(l)),k=new Map;for(const l of n){const u=l.path||"/onebot";k.set(u,{path:u,template:l,bots:[],onlineCount:0})}for(const l of e){const u=l.path||"/onebot";k.has(u)||k.set(u,{path:u,bots:[],onlineCount:0});const r=k.get(u);r.bots.push(l),l.status==="online"&&(r.onlineCount+=1)}return Array.from(k.values()).sort((l,u)=>l.path.localeCompare(u.path))}),D=n=>n.split(`
2
+ `).map(e=>e.trim()).filter(Boolean),Z=n=>D(n).length;function tt(n){h.value=n,n==="blacklist"?S.value=j.value:n==="whitelist"?S.value=A.value:S.value=O.value}function kt(){const n=S.value.split(`
3
+ `).map(k=>k.trim()).filter(k=>/^\d+$/.test(k)),e=Array.from(new Set(n)).join(`
4
+ `);h.value==="blacklist"?j.value=e:h.value==="whitelist"?A.value=e:h.value==="priority"&&(O.value=e),h.value=null,m("success","列表已暂存,请点击保存规则生效")}function m(n,e){M.type=n,M.message=e,M.show=true,setTimeout(()=>{M.show=false},2e3)}function ut(n){return n==="online"?"在线":n==="connecting"?"连接中":"离线"}function gt(){j.value=i.channelBlacklist.join(`
5
+ `),A.value=i.channelWhitelist.join(`
6
+ `),O.value=i.priorityChannels.join(`
7
+ `),E.value=Object.entries(i.botMaxLoad||{}).map(([n,e])=>({botId:n,maxLoad:Number(e)||0})),R.value=Object.entries(i.channelBotPriority||{}).map(([n,e])=>({channelId:n,botIds:Array.isArray(e)?[...e]:[]}))}function ht(){E.value.push({botId:"",maxLoad:0})}function Ct(n){E.value.splice(n,1)}function _t(){R.value.push({channelId:"",botIds:[]})}function wt(n){R.value.splice(n,1)}async function I(){if(!X){X=true;try{const n=await $("onebot-multi/state");g.value=(n==null?void 0:n.bots)||[],Object.assign(s,(n==null?void 0:n.runtime)||{}),Object.assign(i,(n==null?void 0:n.loadBalance)||{}),gt()}catch(n){m("error",(n==null?void 0:n.message)||"刷新失败")}finally{X=false}}}function dt(n){z.value="create",H.value=n,J.value="",w.value={token:"",protocol:n==="client"?"ws":"ws-reverse",endpoint:n==="client"?"":void 0,path:n==="server"?"/onebot":void 0,name:"",enabled:true}}function et(n){z.value="edit",H.value=n.protocol==="ws"?"client":"server",J.value=n.selfId||"",w.value={...n}}async function It(n){if(w.value=n,!!w.value)try{z.value==="create"?await $("onebot-multi/bots/create",w.value):await $("onebot-multi/bots/update",{oldSelfId:J.value,bot:w.value}),w.value=null,await I(),m("success","保存成功")}catch(e){m("error",(e==null?void 0:e.message)||"保存失败")}}async function lt(n){if(confirm(`确认删除 Bot ${n.selfId} 吗?`))try{await $("onebot-multi/bots/delete",{selfId:n.selfId}),await I(),m("success","删除成功")}catch(e){m("error",(e==null?void 0:e.message)||"删除失败")}}async function nt(n){try{await $("onebot-multi/bots/toggle",{selfId:n.selfId}),await I(),m("success","状态已更新")}catch(e){m("error",(e==null?void 0:e.message)||"更新失败")}}async function rt(n){try{await $("onebot-multi/bots/restart",{selfId:n.selfId}),await I(),m("success","重启已触发")}catch(e){m("error",(e==null?void 0:e.message)||"重启失败")}}function ct(n){B.value=n,N.value=n.nickname||""}async function $t(){if(B.value)try{const n=await $("onebot-multi/bots/profile",{selfId:B.value.selfId,nickname:N.value});if(!(n!=null&&n.success))throw new Error((n==null?void 0:n.error)||"保存失败");B.value=null,await I(),m("success","昵称已更新")}catch(n){m("error",(n==null?void 0:n.message)||"更新失败")}}function pt(n){V.value=n,P.value=""}function xt(n){var u;const k=(u=n.target.files)==null?void 0:u[0];if(!k){P.value="";return}const l=new FileReader;l.onload=r=>{var c;P.value=(c=r.target)==null?void 0:c.result},l.readAsDataURL(k)}async function Bt(){if(!V.value||!P.value.trim()){m("error","请先选择图片文件");return}try{const n=await $("onebot-multi/bots/avatar",{selfId:V.value.selfId,file:P.value});if(!(n!=null&&n.success))throw new Error((n==null?void 0:n.error)||"保存失败");V.value=null,m("success","头像已更新")}catch(n){m("error",(n==null?void 0:n.message)||"更新失败")}}async function Vt(){try{await $("onebot-multi/settings/runtime/update",{...s}),await I(),m("success","运行时设置已保存")}catch(n){m("error",(n==null?void 0:n.message)||"保存失败")}}async function Mt(){try{const n={};for(const l of E.value){const u=l.botId.trim();if(!u)continue;const r=Math.max(0,Number(l.maxLoad||0));n[u]=r}const e={};for(const l of R.value){const u=l.channelId.trim();if(!u)continue;const r=(l.botIds||[]).filter(Boolean);r.length>0&&(e[u]=r)}const k={...i,channelBlacklist:D(j.value),channelWhitelist:D(A.value),priorityChannels:D(O.value),botMaxLoad:n,channelBotPriority:e};await $("onebot-multi/settings/load-balance/update",k),await I(),m("success","负载均衡设置已保存")}catch(n){m("error",(n==null?void 0:n.message)||"保存失败")}}return Tt(async()=>{await I(),_.value=false,Q=setInterval(()=>{I()},5e3)}),Et(()=>{Q&&(clearInterval(Q),Q=null)}),(n,e)=>{const k=Rt("k-layout");return a(),vt(k,null,{default:St(()=>[e[75]||(e[75]=t("a",{class:"skip-link",href:"#main-content"},"跳到主要内容",-1)),t("div",qt,[_.value?(a(),d("div",Ht,"正在加载…")):(a(),d("main",Jt,[t("header",Xt,[e[30]||(e[30]=t("div",{class:"hero-copy"},[t("p",{class:"hero-kicker"},"OneBot Multi"),t("h1",null,"Bot 管理中心"),t("p",null,"管理 ws 客户端、ws 服务器与基础负载均衡规则")],-1)),t("div",Yt,[t("button",{type:"button",class:"action-button secondary",onClick:I},"刷新状态"),t("button",{type:"button",class:"action-button primary",onClick:e[0]||(e[0]=l=>dt("client"))},"新增 ws 客户端"),t("button",{type:"button",class:"action-button primary",onClick:e[1]||(e[1]=l=>dt("server"))},"新增 ws 服务器")])]),t("nav",Zt,[t("button",{type:"button",class:U(["tab-button",{active:p.value==="bots"}]),onClick:e[2]||(e[2]=l=>p.value="bots")},"Bot 管理",2),t("button",{type:"button",class:U(["tab-button",{active:p.value==="balance"}]),onClick:e[3]||(e[3]=l=>p.value="balance")},"负载均衡",2)]),v(t("section",te,[e[53]||(e[53]=t("div",{class:"panel-header"},[t("div",null,[t("h2",null,"Bot 状态"),t("p",null,"查看每个实例的在线状态、收发统计与连接方式")])],-1)),g.value.length===0?(a(),d("div",ee,"暂无实例,点击上方按钮新增 ws 客户端或 ws 服务器。")):(a(),d("div",le,[it.value.length?(a(),d("section",ne,[e[39]||(e[39]=t("div",{class:"section-title-row"},[t("h3",null,"ws 服务器"),t("span",{class:"section-note"},"按接入路径聚合,自动挂载连接进来的 QQ")],-1)),t("div",se,[(a(true),d(L,null,T(it.value,l=>{var u,r;return a(),d("article",{key:l.path,class:"server-group-card"},[t("div",oe,[t("div",null,[t("div",ae,[t("div",ie,o(((u=l.template)==null?void 0:u.name)||"ws 服务器"),1),e[31]||(e[31]=t("span",{class:"server-tag"},"共享 ws 服务器",-1)),t("span",ue,o(((r=l.template)==null?void 0:r.enabled)===false?"已禁用":"已启用"),1)]),e[32]||(e[32]=t("div",{class:"server-group-subtitle"},"接入路径",-1)),t("div",de,o(l.path),1)]),t("div",re,[t("span",ce,o(l.bots.length)+" 个 QQ",1),t("span",pe,o(l.onlineCount)+" 在线",1)])]),l.template?(a(),d("div",ve,[t("button",{type:"button",class:"mini-button",onClick:c=>et(l.template)},"编辑服务器",8,me),t("button",{type:"button",class:"mini-button",onClick:c=>nt(l.template)},o(l.template.enabled===false?"启用服务器":"禁用服务器"),9,be),t("button",{type:"button",class:"mini-button danger",onClick:c=>lt(l.template)},"删除服务器",8,fe)])):x("v-if",true),l.bots.length===0?(a(),d("div",ye,"暂无接入的 QQ")):(a(),d("div",ke,[(a(true),d(L,null,T(l.bots,c=>(a(),d("article",{key:c.selfId,class:U(["bot-card",{disabled:c.enabled===false}])},[t("div",ge,[t("img",{class:"bot-avatar",src:c.avatarUrl||"",alt:"Bot 头像",width:"64",height:"64",loading:"lazy"},null,8,he),t("div",Ce,[t("div",_e,o(c.name||`Bot ${c.selfId}`),1),t("div",we,o(c.nickname||"未获取昵称"),1),e[33]||(e[33]=t("div",{class:"bot-meta-line"},"挂载到 ws 服务器",-1)),t("div",Ie,o(c.selfId),1)]),t("span",{class:U(["status-pill",`status-${c.status||"offline"}`])},o(ut(c.status)),3)]),t("div",$e,[t("div",xe,[e[34]||(e[34]=t("span",null,"群组",-1)),t("strong",null,o(c.groupCount??"-"),1)]),t("div",Be,[e[35]||(e[35]=t("span",null,"好友",-1)),t("strong",null,o(c.friendCount??"-"),1)]),t("div",Ve,[e[36]||(e[36]=t("span",null,"接收",-1)),t("strong",null,o(c.messageReceived??"-"),1)]),t("div",Me,[e[37]||(e[37]=t("span",null,"发送",-1)),t("strong",null,o(c.messageSent??"-"),1)])]),t("div",Ue,[t("div",null,[e[38]||(e[38]=t("strong",null,"接入路径:",-1)),b(o(c.path||"/onebot"),1)])]),t("div",Le,[t("button",{type:"button",class:"mini-button",onClick:F=>et(c)},"编辑",8,Te),t("button",{type:"button",class:"mini-button",onClick:F=>nt(c)},o(c.enabled===false?"启用":"禁用"),9,Ee),t("button",{type:"button",class:"mini-button",onClick:F=>rt(c)},"重启",8,Re),t("button",{type:"button",class:"mini-button",onClick:F=>ct(c)},"昵称",8,Se),t("button",{type:"button",class:"mini-button",onClick:F=>pt(c)},"头像",8,je),t("button",{type:"button",class:"mini-button danger",onClick:F=>lt(c)},"删除",8,Ae)])],2))),128))]))])}),128))])])):x("v-if",true),at.value.length?(a(),d("section",Oe,[e[46]||(e[46]=t("div",{class:"section-title-row"},[t("h3",null,"ws 客户端"),t("span",{class:"section-note"},"主动连接到外部 OneBot 服务")],-1)),t("div",Pe,[(a(true),d(L,null,T(at.value,l=>(a(),d("article",{key:l.selfId,class:U(["bot-card",{disabled:l.enabled===false}])},[t("div",Fe,[t("img",{class:"bot-avatar",src:l.avatarUrl||"",alt:"Bot 头像",width:"64",height:"64",loading:"lazy"},null,8,ze),t("div",Ne,[t("div",Qe,o(l.name||`Bot ${l.selfId}`),1),t("div",De,o(l.nickname||"未获取昵称"),1),e[40]||(e[40]=t("div",{class:"bot-meta-line"},"ws 客户端",-1)),t("div",We,o(l.selfId),1)]),t("span",{class:U(["status-pill",`status-${l.status||"offline"}`])},o(ut(l.status)),3)]),t("div",Ge,[t("div",Ke,[e[41]||(e[41]=t("span",null,"群组",-1)),t("strong",null,o(l.groupCount??"-"),1)]),t("div",qe,[e[42]||(e[42]=t("span",null,"好友",-1)),t("strong",null,o(l.friendCount??"-"),1)]),t("div",He,[e[43]||(e[43]=t("span",null,"接收",-1)),t("strong",null,o(l.messageReceived??"-"),1)]),t("div",Je,[e[44]||(e[44]=t("span",null,"发送",-1)),t("strong",null,o(l.messageSent??"-"),1)])]),t("div",Xe,[t("div",null,[e[45]||(e[45]=t("strong",null,"连接地址:",-1)),b(o(l.endpoint||"-"),1)])]),t("div",Ye,[t("button",{type:"button",class:"mini-button",onClick:u=>et(l)},"编辑",8,Ze),t("button",{type:"button",class:"mini-button",onClick:u=>nt(l)},o(l.enabled===false?"启用":"禁用"),9,tl),t("button",{type:"button",class:"mini-button",onClick:u=>rt(l)},"重启",8,el),t("button",{type:"button",class:"mini-button",onClick:u=>ct(l)},"昵称",8,ll),t("button",{type:"button",class:"mini-button",onClick:u=>pt(l)},"头像",8,nl),t("button",{type:"button",class:"mini-button danger",onClick:u=>lt(l)},"删除",8,sl)])],2))),128))])])):x("v-if",true)])),e[54]||(e[54]=t("div",{class:"section-divider"},null,-1)),e[55]||(e[55]=t("div",{class:"panel-header compact"},[t("div",null,[t("h2",null,"运行参数"),t("p",null,"影响连接超时、重试频率与混合内容拆分")])],-1)),t("div",ol,[t("label",al,[e[47]||(e[47]=b("超时时间 (毫秒) ",-1)),v(t("input",{"onUpdate:modelValue":e[4]||(e[4]=l=>s.responseTimeout=l),name:"responseTimeout",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,s.responseTimeout,void 0,{number:true}]])]),t("label",il,[e[48]||(e[48]=b("心跳间隔 (毫秒) ",-1)),v(t("input",{"onUpdate:modelValue":e[5]||(e[5]=l=>s.heartbeatInterval=l),name:"heartbeatInterval",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,s.heartbeatInterval,void 0,{number:true}]])]),t("label",ul,[e[49]||(e[49]=b("重试次数 ",-1)),v(t("input",{"onUpdate:modelValue":e[6]||(e[6]=l=>s.retryTimes=l),name:"retryTimes",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,s.retryTimes,void 0,{number:true}]])]),t("label",dl,[e[50]||(e[50]=b("重试间隔 (毫秒) ",-1)),v(t("input",{"onUpdate:modelValue":e[7]||(e[7]=l=>s.retryInterval=l),name:"retryInterval",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,s.retryInterval,void 0,{number:true}]])]),t("label",rl,[e[51]||(e[51]=b("懒重试 (毫秒) ",-1)),v(t("input",{"onUpdate:modelValue":e[8]||(e[8]=l=>s.retryLazy=l),name:"retryLazy",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,s.retryLazy,void 0,{number:true}]])]),t("label",cl,[v(t("input",{"onUpdate:modelValue":e[9]||(e[9]=l=>s.advanced.splitMixedContent=l),name:"splitMixedContent",type:"checkbox"},null,512),[[q,s.advanced.splitMixedContent]]),e[52]||(e[52]=t("span",null,"拆分混合内容",-1))])]),t("div",{class:"footer-actions"},[t("button",{type:"button",class:"action-button primary",onClick:Vt},"保存运行参数")])],512),[[mt,p.value==="bots"]]),v(t("section",pl,[e[68]||(e[68]=t("div",{class:"panel-header"},[t("div",null,[t("h2",null,"负载均衡"),t("p",null,"控制群过滤、默认上限、优先群与专属 Bot 规则")])],-1)),t("div",vl,[t("label",ml,[v(t("input",{"onUpdate:modelValue":e[10]||(e[10]=l=>i.enabled=l),name:"lbEnabled",type:"checkbox"},null,512),[[q,i.enabled]]),e[56]||(e[56]=t("span",null,"启用负载均衡",-1))]),t("label",bl,[e[57]||(e[57]=b("均衡间隔 (秒) ",-1)),v(t("input",{"onUpdate:modelValue":e[11]||(e[11]=l=>i.balanceInterval=l),name:"balanceInterval",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,i.balanceInterval,void 0,{number:true}]])]),t("label",fl,[e[59]||(e[59]=b("过滤模式 ",-1)),v(t("select",{"onUpdate:modelValue":e[12]||(e[12]=l=>i.channelFilterMode=l),name:"channelFilterMode",class:"field-input field-select"},[...e[58]||(e[58]=[t("option",{value:"blacklist"},"黑名单",-1),t("option",{value:"whitelist"},"白名单",-1)])],512),[[bt,i.channelFilterMode]])]),t("label",yl,[e[60]||(e[60]=b("默认最大负载 (0=无限) ",-1)),v(t("input",{"onUpdate:modelValue":e[13]||(e[13]=l=>i.defaultMaxLoad=l),name:"defaultMaxLoad",autocomplete:"off",type:"number",inputmode:"numeric",class:"field-input"},null,512),[[y,i.defaultMaxLoad,void 0,{number:true}]])]),t("label",kl,[e[61]||(e[61]=b("未分配值 ",-1)),v(t("input",{"onUpdate:modelValue":e[14]||(e[14]=l=>i.unassignedValue=l),name:"unassignedValue",autocomplete:"off",type:"text",placeholder:"例如 0…",class:"field-input"},null,512),[[y,i.unassignedValue]])])]),t("div",gl,[t("div",hl,[t("div",null,[e[62]||(e[62]=t("strong",null,"群黑名单",-1)),t("p",null,"已配置 "+o(Z(j.value))+" 个群",1)]),t("button",{type:"button",class:"mini-button",onClick:e[15]||(e[15]=l=>tt("blacklist"))},"编辑")]),t("div",Cl,[t("div",null,[e[63]||(e[63]=t("strong",null,"群白名单",-1)),t("p",null,"已配置 "+o(Z(A.value))+" 个群",1)]),t("button",{type:"button",class:"mini-button",onClick:e[16]||(e[16]=l=>tt("whitelist"))},"编辑")]),t("div",_l,[t("div",null,[e[64]||(e[64]=t("strong",null,"优先群聊",-1)),t("p",null,"已配置 "+o(Z(O.value))+" 个群",1)]),t("button",{type:"button",class:"mini-button",onClick:e[17]||(e[17]=l=>tt("priority"))},"编辑")])]),t("div",wl,[t("section",Il,[t("div",{class:"sub-panel-header"},[e[65]||(e[65]=t("h3",null,"Bot 最大负载",-1)),t("button",{type:"button",class:"mini-button",onClick:ht},"添加行")]),t("div",$l,[E.value.length===0?(a(),d("div",xl,"暂无规则")):x("v-if",true),(a(true),d(L,null,T(E.value,(l,u)=>(a(),d("div",{key:`max-${u}`,class:"row-editor"},[v(t("select",{"onUpdate:modelValue":r=>l.botId=r,class:"field-input field-select compact-input"},[e[66]||(e[66]=t("option",{disabled:"",value:""},"选择 Bot",-1)),(a(true),d(L,null,T(ot.value,r=>(a(),d("option",{key:r.selfId,value:r.selfId},o(r.name||r.nickname||r.selfId),9,Vl))),128))],8,Bl),[[bt,l.botId]]),v(t("input",{"onUpdate:modelValue":r=>l.maxLoad=r,type:"number",inputmode:"numeric",class:"field-input compact-input",placeholder:"最大值"},null,8,Ml),[[y,l.maxLoad,void 0,{number:true}]]),t("button",{type:"button",class:"mini-button danger","aria-label":"删除负载规则",onClick:r=>Ct(u)},"删除",8,Ul)]))),128))])]),t("section",Ll,[t("div",{class:"sub-panel-header"},[e[67]||(e[67]=t("div",null,[t("h3",null,"群聊专属 Bot"),t("p",null,"为指定群配置优先使用的 Bot 列表")],-1)),t("button",{type:"button",class:"mini-button",onClick:_t},"添加行")]),t("div",Tl,[R.value.length===0?(a(),d("div",El,"暂无规则")):x("v-if",true),(a(true),d(L,null,T(R.value,(l,u)=>(a(),d("div",{key:`priority-${u}`,class:"priority-editor"},[t("div",Rl,[v(t("input",{"onUpdate:modelValue":r=>l.channelId=r,type:"text",inputmode:"numeric",class:"field-input",placeholder:"群号…"},null,8,Sl),[[y,l.channelId]]),t("button",{type:"button",class:"mini-button danger","aria-label":"删除群聊专属 Bot 规则",onClick:r=>wt(u)},"删除",8,jl)]),t("div",Al,[(a(true),d(L,null,T(ot.value,r=>(a(),d("label",{key:`${l.channelId}-${r.selfId}`,class:"choice-chip"},[v(t("input",{type:"checkbox",value:r.selfId,"onUpdate:modelValue":c=>l.botIds=c},null,8,Ol),[[q,l.botIds]]),t("span",null,o(r.name||r.nickname||r.selfId),1)]))),128))])]))),128))])])]),t("div",{class:"footer-actions"},[t("button",{type:"button",class:"action-button primary",onClick:Mt},"保存负载均衡规则")])],512),[[mt,p.value==="balance"]]),w.value?(a(),vt(Kt,{key:0,"model-value":w.value,mode:z.value,kind:H.value,onClose:e[18]||(e[18]=l=>w.value=null),onSave:It},null,8,["model-value","mode","kind"])):x("v-if",true),B.value?(a(),d("div",{key:1,class:"modal-overlay",onClick:e[22]||(e[22]=K(l=>B.value=null,["self"]))},[t("section",Pl,[t("header",Fl,[e[69]||(e[69]=t("h3",null,"修改昵称",-1)),t("button",{type:"button",class:"modal-close","aria-label":"关闭昵称弹窗",onClick:e[19]||(e[19]=l=>B.value=null)},"×")]),t("p",zl,o(B.value.selfId),1),t("label",Nl,[e[70]||(e[70]=b("昵称 ",-1)),v(t("input",{"onUpdate:modelValue":e[20]||(e[20]=l=>N.value=l),name:"profileNickname",autocomplete:"off",type:"text",class:"field-input",placeholder:"输入新的昵称…"},null,512),[[y,N.value]])]),t("div",Ql,[t("button",{type:"button",class:"action-button primary",onClick:$t},"保存"),t("button",{type:"button",class:"action-button",onClick:e[21]||(e[21]=l=>B.value=null)},"取消")])])])):x("v-if",true),V.value?(a(),d("div",{key:2,class:"modal-overlay",onClick:e[25]||(e[25]=K(l=>V.value=null,["self"]))},[t("section",Dl,[t("header",Wl,[e[71]||(e[71]=t("h3",null,"修改头像",-1)),t("button",{type:"button",class:"modal-close","aria-label":"关闭头像弹窗",onClick:e[23]||(e[23]=l=>V.value=null)},"×")]),t("p",Gl,o(V.value.selfId),1),t("label",Kl,[e[72]||(e[72]=b("选择图片文件 ",-1)),t("input",{class:"file-input",type:"file",accept:"image/*",onChange:xt},null,32)]),t("div",ql,[t("button",{type:"button",class:"action-button primary",onClick:Bt},"保存"),t("button",{type:"button",class:"action-button",onClick:e[24]||(e[24]=l=>V.value=null)},"取消")])])])):x("v-if",true),h.value?(a(),d("div",{key:3,class:"modal-overlay",onClick:e[29]||(e[29]=K(l=>h.value=null,["self"]))},[t("section",Hl,[t("header",Jl,[t("h3",null,o(yt.value),1),t("button",{type:"button",class:"modal-close","aria-label":"关闭群号编辑弹窗",onClick:e[26]||(e[26]=l=>h.value=null)},"×")]),e[74]||(e[74]=t("p",{class:"modal-note"},"每行输入一个群号,保存时会自动过滤非数字并去重。",-1)),t("label",Xl,[e[73]||(e[73]=b("群号列表 ",-1)),v(t("textarea",{"onUpdate:modelValue":e[27]||(e[27]=l=>S.value=l),rows:"10",class:"field-input textarea-input",placeholder:"例如:123456789…"},null,512),[[y,S.value]])]),t("div",Yl,[t("button",{type:"button",class:"action-button primary",onClick:kt},"确认保存"),t("button",{type:"button",class:"action-button",onClick:e[28]||(e[28]=l=>h.value=null)},"取消")])])])):x("v-if",true),M.show?(a(),d("div",{key:4,class:U(["toast",M.type]),"aria-live":"polite"},o(M.message),3)):x("v-if",true)]))])]),_:1})}}}),tn=st(Zl,[["__scopeId","data-v-cb21c318"]]),en={},ln={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 nn(C,_){return a(),d("svg",ln,[..._[0]||(_[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 sn=st(en,[["render",nn]]);Ut.register("activity:onebot-multi",sn);const un=C=>{C.page({name:"OneBot Multi",path:"/onebot-multi",component:tn,icon:"activity:onebot-multi",order:600})};export{un as default};
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- [data-v-3a32f70e] .k-layout,[data-v-3a32f70e] .k-layout__main{background:transparent!important;padding:0!important;margin:0!important;height:100%;position:relative}.pop-wrapper[data-v-3a32f70e]{--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-3a32f70e] *{box-sizing:border-box}.comic-panel[data-v-3a32f70e]{background:var(--pop-panel);border:var(--pop-border);box-shadow:4px 4px 0 var(--pop-shadow-color);border-radius:16px}.pop-loading[data-v-3a32f70e]{display:flex;justify-content:center;align-items:center;height:60vh}.comic-text[data-v-3a32f70e]{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-3a32f70e 1s infinite alternate}@keyframes pulse-3a32f70e{0%{transform:rotate(-5deg) scale(1)}to{transform:rotate(-5deg) scale(1.1)}}.pop-container[data-v-3a32f70e]{max-width:1200px;margin:0 auto;display:flex;flex-direction:column;gap:24px}.pop-header[data-v-3a32f70e]{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-3a32f70e]: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-3a32f70e]>*{position:relative;z-index:1}.brand[data-v-3a32f70e]{display:flex;align-items:center;gap:16px}.logo[data-v-3a32f70e]{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-3a32f70e]{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-3a32f70e]{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-3a32f70e]{display:flex;gap:12px;flex-wrap:wrap}.pop-btn[data-v-3a32f70e]{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-3a32f70e]:hover{transform:translate(-2px,-2px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn[data-v-3a32f70e]:active{transform:translate(4px,4px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.active[data-v-3a32f70e]{background:var(--pop-primary);color:#fff}.pop-btn.primary-btn[data-v-3a32f70e]{background:var(--pop-primary);color:#fff;font-size:18px}.pop-btn.action-btn[data-v-3a32f70e]{background:#ffb347;color:#fff}.pop-btn.mini[data-v-3a32f70e]{padding:6px 12px;font-size:13px;box-shadow:2px 2px 0 var(--pop-shadow-color);border-width:2px}.pop-btn.mini[data-v-3a32f70e]:hover{transform:translate(-1px,-1px);box-shadow:4px 4px 0 var(--pop-shadow-color)}.pop-btn.mini[data-v-3a32f70e]:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--pop-shadow-color)}.pop-btn.danger[data-v-3a32f70e]{background:var(--pop-danger);color:#fff}.pop-panel[data-v-3a32f70e]{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-3a32f70e]{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-3a32f70e]{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-3a32f70e]{margin:4px 0 0;font-size:16px;font-weight:700;text-transform:uppercase}.bot-grid[data-v-3a32f70e]{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:20px}.bot-card[data-v-3a32f70e]{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-3a32f70e]: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-3a32f70e]{background:#e5e7eb;opacity:.8}.bot-card.disabled .bot-avatar[data-v-3a32f70e]{filter:grayscale(1)}.bot-card[data-v-3a32f70e]:hover{transform:translate(-4px,-4px);box-shadow:6px 6px 0 var(--pop-shadow-color)}.bot-header[data-v-3a32f70e]{display:flex;align-items:center;gap:12px;margin-bottom:16px}.bot-avatar[data-v-3a32f70e]{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-3a32f70e]{flex:1;overflow:hidden}.bot-name[data-v-3a32f70e]{font-size:20px;font-weight:900;margin-bottom:4px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-transform:uppercase}.bot-sub[data-v-3a32f70e]{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-3a32f70e]{font-family:Courier New,Courier,monospace;font-size:12px;font-weight:700}.status-badge[data-v-3a32f70e]{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-3a32f70e]{background:var(--pop-success);color:var(--pop-text)}.status-offline[data-v-3a32f70e]{background:var(--pop-danger);color:#fff}.status-connecting[data-v-3a32f70e]{background:var(--pop-bg);color:var(--pop-text)}.bot-stats[data-v-3a32f70e]{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-bottom:16px}.stat-box[data-v-3a32f70e]{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-3a32f70e]{color:#666;font-size:12px;font-weight:700;text-transform:uppercase}.stat-box strong[data-v-3a32f70e]{font-size:16px}.bot-meta[data-v-3a32f70e]{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-3a32f70e]{display:flex;flex-wrap:wrap;gap:8px}.form-grid[data-v-3a32f70e]{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:24px}.modal-grid[data-v-3a32f70e]{grid-template-columns:1fr;gap:12px;max-height:50vh;overflow-y:auto;padding-right:8px}.pop-label[data-v-3a32f70e]{display:flex;flex-direction:column;gap:8px;font-size:16px;font-weight:700;text-transform:uppercase}.pop-label.hidden[data-v-3a32f70e]{display:none}.pop-input[data-v-3a32f70e],.pop-select[data-v-3a32f70e],.pop-textarea[data-v-3a32f70e]{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-3a32f70e]:focus,.pop-select[data-v-3a32f70e]:focus,.pop-textarea[data-v-3a32f70e]:focus{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-textarea[data-v-3a32f70e]{resize:vertical}.pop-file-input[data-v-3a32f70e]{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-3a32f70e]:focus,.pop-file-input[data-v-3a32f70e]:hover{outline:none;background:#fffde7;box-shadow:4px 4px 0 var(--pop-shadow-color);transform:translate(-2px,-2px)}.pop-file-input[data-v-3a32f70e]::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-3a32f70e]{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-3a32f70e]:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--pop-shadow-color)}.pop-check[data-v-3a32f70e]{width:20px;height:20px;accent-color:var(--pop-primary);border:2px solid var(--pop-text);cursor:pointer}.mini-checkbox[data-v-3a32f70e]{padding:4px 8px;border-radius:8px;font-size:13px;gap:4px;border-width:2px}.mini-check[data-v-3a32f70e]{width:14px;height:14px}.split-grid[data-v-3a32f70e]{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-bottom:24px}.list-summary-box[data-v-3a32f70e]{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-3a32f70e]{font-size:14px;font-weight:900;color:var(--pop-primary)}.pop-table-editor[data-v-3a32f70e]{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-3a32f70e]{grid-column:1/-1;background:#ffb3ff}.table-head[data-v-3a32f70e]{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-3a32f70e]{display:flex;flex-direction:column;gap:8px;max-height:250px;overflow-y:auto;padding-right:8px}.empty-row[data-v-3a32f70e]{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-3a32f70e]{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-3a32f70e]{grid-template-columns:1fr 2fr auto}.mini-input[data-v-3a32f70e]{padding:6px 10px;font-size:14px}.panel-footer[data-v-3a32f70e]{margin-top:24px;padding-top:20px;border-top:3px solid var(--pop-text);display:flex;justify-content:flex-end}.pop-modal-overlay[data-v-3a32f70e]{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-3a32f70e]{width:min(600px,90vw);position:relative;padding:32px}.pop-modal h3[data-v-3a32f70e]{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-3a32f70e]{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-3a32f70e]{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-3a32f70e .5s cubic-bezier(.175,.885,.32,1.275);text-transform:uppercase}@keyframes pop-3a32f70e{0%{transform:scale(0) rotate(0)}to{transform:scale(1) rotate(15deg)}}.modal-actions[data-v-3a32f70e]{display:flex;gap:12px;margin-top:24px;justify-content:flex-end}.pop-toast[data-v-3a32f70e]{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-3a32f70e .3s ease-out;text-transform:uppercase}.pop-toast.success[data-v-3a32f70e]{background:var(--pop-success);color:var(--pop-text)}.pop-toast.error[data-v-3a32f70e]{background:var(--pop-danger);color:#fff}@keyframes slideUp-3a32f70e{0%{transform:translate(-50%,100%);opacity:0}to{transform:translate(-50%);opacity:1}}.empty-state[data-v-3a32f70e]{display:flex;justify-content:center;padding:40px}.comic-speech[data-v-3a32f70e]{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-3a32f70e]: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-3a32f70e]: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-3a32f70e]::-webkit-scrollbar{width:12px}[data-v-3a32f70e]::-webkit-scrollbar-track{background:var(--pop-bg);border-left:3px solid var(--pop-text)}[data-v-3a32f70e]::-webkit-scrollbar-thumb{background:var(--pop-primary);border:3px solid var(--pop-text);border-radius:0}@media (max-width: 960px){.split-grid[data-v-3a32f70e]{grid-template-columns:1fr}}@media (max-width: 768px){.pop-wrapper[data-v-3a32f70e]{padding:12px}.pop-header[data-v-3a32f70e]{flex-direction:column;text-align:center}.pop-tabs[data-v-3a32f70e]{justify-content:center;width:100%}.pop-btn[data-v-3a32f70e]{flex:1;min-width:45%;text-align:center}.bot-actions .pop-btn[data-v-3a32f70e]{flex:1;min-width:30%}.pop-modal[data-v-3a32f70e]{padding:20px}.comic-speech[data-v-3a32f70e]{font-size:18px}.bot-grid[data-v-3a32f70e]{grid-template-columns:1fr}}
1
+ .editor-overlay[data-v-66180dfa]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px;background:#57402e59;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);overscroll-behavior:contain}.editor-card[data-v-66180dfa]{box-sizing:border-box;width:min(640px,100%);max-width:100%;max-height:88vh;overflow-x:hidden;overflow-y:auto;background:#fffdf7;border:3px solid #6b5243;border-radius:20px;padding:24px}.editor-header[data-v-66180dfa]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:18px}.editor-header h3[data-v-66180dfa]{margin:0;font-size:28px;color:#6b5243}.editor-header p[data-v-66180dfa]{margin:6px 0 0;color:#8b6b57;font-size:14px}.close-button[data-v-66180dfa]{width:40px;height:40px;border:3px solid #6b5243;border-radius:12px;background:#fff;color:#6b5243;font-size:24px;font-weight:900;line-height:1;cursor:pointer;transition:transform .12s ease}.close-button[data-v-66180dfa]:hover,.close-button[data-v-66180dfa]:focus-visible{transform:translate(-1px,-1px)}.close-button[data-v-66180dfa]:active{transform:translate(2px,2px)}.editor-grid[data-v-66180dfa]{display:grid;gap:14px;min-width:0}.field-label[data-v-66180dfa]{display:grid;gap:8px;min-width:0;font-weight:700;color:#6b5243}.hidden-field[data-v-66180dfa]{display:none}.field-input[data-v-66180dfa]{box-sizing:border-box;width:100%;min-width:0;max-width:100%;border:3px solid #6b5243;border-radius:16px;padding:12px 14px;background:#fff;color:#6b5243;font:inherit;transition:transform .12s ease}.field-input[data-v-66180dfa]:focus-visible{outline:none;transform:translate(-1px,-1px)}.field-checkbox[data-v-66180dfa]{display:flex;box-sizing:border-box;align-items:center;gap:10px;width:100%;min-width:0;max-width:100%;border:3px solid #6b5243;border-radius:16px;padding:10px 12px;background:#fff7df;color:#6b5243;font-weight:700;overflow:hidden}.editor-actions[data-v-66180dfa]{display:flex;justify-content:flex-end;gap:12px;margin-top:20px}.action-button[data-v-66180dfa]{border:3px solid #6b5243;border-radius:16px;padding:10px 18px;background:#fff;color:#6b5243;font:inherit;font-weight:800;cursor:pointer;transition:transform .12s ease}.action-button.primary[data-v-66180dfa]{background:#ffb870}.action-button[data-v-66180dfa]:hover,.action-button[data-v-66180dfa]:focus-visible{transform:translate(-1px,-1px)}.action-button[data-v-66180dfa]:active{transform:translate(2px,2px)}@media (max-width: 640px){.editor-card[data-v-66180dfa]{padding:18px}.editor-header[data-v-66180dfa]{align-items:center}.editor-header h3[data-v-66180dfa]{font-size:22px}.editor-actions[data-v-66180dfa]{flex-direction:column-reverse}.action-button[data-v-66180dfa]{width:100%}}[data-v-cb21c318] .k-layout,[data-v-cb21c318] .k-layout__main{background:transparent!important;padding:0!important;margin:0!important;height:100%;position:relative}.skip-link[data-v-cb21c318]{position:absolute;left:-9999px;top:0}.skip-link[data-v-cb21c318]:focus{left:16px;top:16px;z-index:1200;background:#fffdf7;color:#6b5243;border:3px solid #6b5243;border-radius:12px;padding:8px 12px}.page-shell[data-v-cb21c318]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;box-sizing:border-box;overflow-y:auto;overflow-x:hidden;padding:24px;background:#fffbeb;background-image:radial-gradient(rgba(107,82,67,.06) 15%,transparent 16%),radial-gradient(rgba(107,82,67,.06) 15%,transparent 16%);background-size:24px 24px;background-position:0 0,12px 12px;color:#6b5243}.page-body[data-v-cb21c318]{max-width:1200px;margin:0 auto;display:grid;gap:24px;overflow-x:hidden}.loading-state[data-v-cb21c318]{min-height:60vh;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800;color:#6b5243}.hero-card[data-v-cb21c318],.panel-card[data-v-cb21c318]{background:#fffdf7;border:3px solid #6b5243;border-radius:20px;overflow-x:hidden}.hero-card[data-v-cb21c318]{padding:24px;display:flex;justify-content:space-between;gap:20px;align-items:flex-start;flex-wrap:wrap}.hero-kicker[data-v-cb21c318]{margin:0 0 10px;display:inline-block;padding:4px 10px;border-radius:999px;border:2px solid #6b5243;background:#fff;font-size:13px;font-weight:800}.hero-copy h1[data-v-cb21c318]{margin:0;font-size:36px;text-wrap:balance}.hero-copy p[data-v-cb21c318]{margin:8px 0 0;color:#8b6b57}.hero-actions[data-v-cb21c318],.create-actions[data-v-cb21c318],.footer-actions[data-v-cb21c318],.compact-actions[data-v-cb21c318],.card-actions[data-v-cb21c318]{display:flex;gap:12px;flex-wrap:wrap}.tab-bar[data-v-cb21c318]{display:flex;gap:12px}.tab-button[data-v-cb21c318],.action-button[data-v-cb21c318],.mini-button[data-v-cb21c318]{border:3px solid #6b5243;border-radius:16px;background:#fff;color:#6b5243;font:inherit;font-weight:800;cursor:pointer;transition:transform .12s ease,background-color .12s ease;touch-action:manipulation}.tab-button[data-v-cb21c318],.action-button[data-v-cb21c318]{padding:10px 18px}.mini-button[data-v-cb21c318]{padding:8px 12px}.tab-button[data-v-cb21c318]:hover,.tab-button[data-v-cb21c318]:focus-visible,.action-button[data-v-cb21c318]:hover,.action-button[data-v-cb21c318]:focus-visible,.mini-button[data-v-cb21c318]:hover,.mini-button[data-v-cb21c318]:focus-visible{transform:translate(-1px,-1px)}.tab-button[data-v-cb21c318]:active,.action-button[data-v-cb21c318]:active,.mini-button[data-v-cb21c318]:active{transform:translate(2px,2px)}.tab-button.active[data-v-cb21c318],.action-button.primary[data-v-cb21c318]{background:#ffb870}.action-button.secondary[data-v-cb21c318]{background:#fff}.mini-button.danger[data-v-cb21c318]{background:#ffd6d9}.panel-card[data-v-cb21c318]{padding:24px}.panel-header[data-v-cb21c318]{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:20px}.panel-header.compact[data-v-cb21c318]{margin-bottom:16px}.panel-header h2[data-v-cb21c318],.sub-panel-header h3[data-v-cb21c318],.simple-modal-header h3[data-v-cb21c318]{margin:0;text-wrap:balance}.panel-header p[data-v-cb21c318],.sub-panel-header p[data-v-cb21c318]{margin:6px 0 0;color:#8b6b57}.empty-card[data-v-cb21c318]{padding:24px;border:2px dashed #6b5243;border-radius:16px;background:#fff;color:#8b6b57}.bot-sections[data-v-cb21c318]{display:grid;gap:24px}.bot-section-block[data-v-cb21c318]{display:grid;gap:16px}.section-title-row[data-v-cb21c318]{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.section-title-row h3[data-v-cb21c318]{margin:0}.section-note[data-v-cb21c318]{color:#8b6b57;font-size:14px}.server-group-list[data-v-cb21c318]{display:grid;gap:18px}.server-group-card[data-v-cb21c318]{padding:18px;border:3px solid #6b5243;border-radius:18px;background:#fff8e8;display:grid;gap:16px}.server-group-header[data-v-cb21c318]{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.server-group-title-row[data-v-cb21c318]{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.server-group-title[data-v-cb21c318]{font-size:22px;font-weight:900}.server-tag[data-v-cb21c318]{border:2px solid #6b5243;border-radius:999px;padding:4px 10px;background:#fffdf7;font-size:12px;font-weight:900}.server-group-subtitle[data-v-cb21c318]{color:#8b6b57;font-size:14px}.server-group-path[data-v-cb21c318]{margin-top:4px;font-family:Courier New,monospace;font-size:13px}.server-group-meta[data-v-cb21c318]{display:flex;gap:10px;flex-wrap:wrap}.server-count[data-v-cb21c318]{border:2px solid #6b5243;border-radius:999px;padding:6px 10px;background:#fffdf7;font-size:12px;font-weight:900}.section-actions[data-v-cb21c318]{margin-top:-4px}.inner-bot-grid[data-v-cb21c318]{margin-top:4px}.bot-grid[data-v-cb21c318]{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:18px}.bot-card[data-v-cb21c318]{padding:18px;border:3px solid #6b5243;border-radius:18px;background:#fff}.bot-card.disabled[data-v-cb21c318]{opacity:.7}.bot-card-header[data-v-cb21c318]{display:flex;gap:14px;align-items:flex-start}.bot-avatar[data-v-cb21c318]{width:64px;height:64px;border:3px solid #6b5243;border-radius:50%;object-fit:cover;background:#fff7df;flex:0 0 auto}.bot-summary[data-v-cb21c318]{min-width:0;flex:1}.bot-name[data-v-cb21c318]{font-size:20px;font-weight:900;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bot-subtitle[data-v-cb21c318],.bot-meta-line[data-v-cb21c318]{color:#8b6b57;font-size:14px}.bot-id[data-v-cb21c318]{margin-top:4px;font-family:Courier New,monospace;font-size:12px}.status-pill[data-v-cb21c318]{flex:0 0 auto;border:2px solid #6b5243;border-radius:999px;padding:6px 10px;font-size:12px;font-weight:900}.status-online[data-v-cb21c318]{background:#d9f6c8}.status-offline[data-v-cb21c318]{background:#ffd6d9}.status-connecting[data-v-cb21c318]{background:#fff4c2}.stat-grid[data-v-cb21c318]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:16px 0}.stat-item[data-v-cb21c318]{display:flex;justify-content:space-between;gap:12px;padding:10px 12px;border:2px solid #6b5243;border-radius:14px;background:#fffdf7}.stat-item span[data-v-cb21c318]{color:#8b6b57}.stat-item strong[data-v-cb21c318]{font-variant-numeric:tabular-nums}.detail-card[data-v-cb21c318]{padding:12px;border:2px solid #6b5243;border-radius:14px;background:#eef4ff;font-size:14px;line-height:1.6;word-break:break-word;margin-bottom:16px}.section-divider[data-v-cb21c318]{margin:28px 0 20px;border-top:3px dashed #d7c1a8}.runtime-grid[data-v-cb21c318],.balance-grid[data-v-cb21c318],.summary-grid[data-v-cb21c318],.config-grid[data-v-cb21c318]{display:grid;gap:16px}.runtime-grid[data-v-cb21c318],.balance-grid[data-v-cb21c318]{grid-template-columns:1fr}.runtime-grid[data-v-cb21c318]>*,.balance-grid[data-v-cb21c318]>*,.summary-grid[data-v-cb21c318]>*,.config-grid[data-v-cb21c318]>*{min-width:0}.runtime-grid .field-label[data-v-cb21c318],.balance-grid .field-label[data-v-cb21c318]{box-sizing:border-box;width:100%;max-width:100%;overflow:hidden;display:grid;gap:8px;min-width:0;padding:14px 16px;border:3px solid #6b5243;border-radius:18px;background:#fffdf7;font-weight:800;color:#6b5243;line-height:1.4}.runtime-grid .checkbox-card[data-v-cb21c318],.balance-grid .checkbox-card[data-v-cb21c318]{overflow:hidden;display:grid;grid-template-columns:20px minmax(0,1fr);box-sizing:border-box;align-items:center;gap:12px;width:100%;min-width:0;max-width:100%;padding:14px 16px;border:3px solid #6b5243;border-radius:18px;background:#fff7df;font-weight:800;color:#6b5243}.runtime-grid .checkbox-card input[data-v-cb21c318],.balance-grid .checkbox-card input[data-v-cb21c318]{width:20px;height:20px;margin:0}.runtime-grid .checkbox-card span[data-v-cb21c318],.balance-grid .checkbox-card span[data-v-cb21c318]{min-width:0;line-height:1.4;word-break:break-word}.summary-grid[data-v-cb21c318]{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:20px 0}.summary-card[data-v-cb21c318],.sub-panel[data-v-cb21c318],.simple-modal[data-v-cb21c318]{background:#fff;border:3px solid #6b5243;border-radius:18px}.summary-card[data-v-cb21c318]{padding:16px;display:flex;justify-content:space-between;gap:12px;align-items:center}.summary-card p[data-v-cb21c318]{margin:6px 0 0;color:#8b6b57;font-size:14px}.config-grid[data-v-cb21c318]{grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}.sub-panel[data-v-cb21c318]{padding:16px}.sub-panel-wide[data-v-cb21c318]{grid-column:1/-1}.sub-panel-header[data-v-cb21c318]{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:12px}.sub-panel-body[data-v-cb21c318]{display:grid;gap:10px}.empty-row[data-v-cb21c318]{padding:14px;text-align:center;color:#8b6b57;border:2px dashed #6b5243;border-radius:14px}.row-editor[data-v-cb21c318],.priority-editor[data-v-cb21c318]{display:grid;gap:10px;padding:12px;border:2px solid #6b5243;border-radius:14px;background:#fffdf7}.row-editor[data-v-cb21c318]{grid-template-columns:minmax(0,1fr) minmax(120px,180px) auto}.priority-top[data-v-cb21c318]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px}.bot-choice-list[data-v-cb21c318]{display:flex;flex-wrap:wrap;gap:10px}.choice-chip[data-v-cb21c318]{display:inline-flex;align-items:center;gap:8px;width:fit-content;max-width:100%;min-width:0;padding:10px 12px;border:2px solid #6b5243;border-radius:14px;background:#fff7df;font-weight:700}.field-input[data-v-cb21c318],.field-select[data-v-cb21c318],.row-input[data-v-cb21c318],.row-select[data-v-cb21c318]{box-sizing:border-box;display:block;width:100%;min-width:0;max-width:100%;border:3px solid #6b5243;border-radius:14px;padding:12px 14px;background:#fff;color:#6b5243;font:inherit;transition:transform .12s ease}.field-select[data-v-cb21c318],.row-select[data-v-cb21c318]{box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=number][data-v-cb21c318],select[data-v-cb21c318]{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.runtime-grid .field-label[data-v-cb21c318],.balance-grid .field-label[data-v-cb21c318]{box-sizing:border-box;width:100%;max-width:100%;overflow:hidden}.field-input[data-v-cb21c318]:focus-visible,.field-select[data-v-cb21c318]:focus-visible,.row-input[data-v-cb21c318]:focus-visible,.row-select[data-v-cb21c318]:focus-visible,.file-input[data-v-cb21c318]:focus-visible,textarea.field-input[data-v-cb21c318]:focus-visible{outline:none;transform:translate(-1px,-1px)}.compact-input[data-v-cb21c318]{padding:10px 12px}.footer-actions[data-v-cb21c318]{margin-top:20px;display:flex;justify-content:flex-end}@media (max-width: 900px){.config-grid[data-v-cb21c318],.summary-grid[data-v-cb21c318],.row-editor[data-v-cb21c318],.priority-top[data-v-cb21c318],.runtime-grid .field-label[data-v-cb21c318],.balance-grid .field-label[data-v-cb21c318]{box-sizing:border-box;width:100%;max-width:100%;overflow:hidden;grid-template-columns:1fr}}.modal-overlay[data-v-cb21c318]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px;background:#57402e59;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);overscroll-behavior:contain}.simple-modal[data-v-cb21c318]{width:min(560px,100%);max-height:88vh;overflow:auto;padding:22px;background:#fffdf7}.simple-modal-header[data-v-cb21c318]{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}.modal-close[data-v-cb21c318]{width:40px;height:40px;border:3px solid #6b5243;border-radius:12px;background:#fff;color:#6b5243;font-size:24px;font-weight:900;line-height:1;cursor:pointer}.modal-close[data-v-cb21c318]:hover,.modal-close[data-v-cb21c318]:focus-visible{transform:translate(-1px,-1px)}.modal-close[data-v-cb21c318]:active{transform:translate(2px,2px)}.modal-note[data-v-cb21c318]{margin:0 0 16px;color:#8b6b57;word-break:break-word}.file-input[data-v-cb21c318]{border:3px solid #6b5243;border-radius:16px;padding:10px;background:#fff}.textarea-input[data-v-cb21c318]{min-height:220px;resize:vertical}.toast[data-v-cb21c318]{position:fixed;bottom:24px;left:50%;transform:translate(-50%);z-index:1100;padding:12px 16px;border:3px solid #6b5243;border-radius:16px;background:#fff}.toast.success[data-v-cb21c318]{background:#d9f6c8}.toast.error[data-v-cb21c318]{background:#ffd6d9}@media (max-width: 900px){.config-grid[data-v-cb21c318],.summary-grid[data-v-cb21c318],.row-editor[data-v-cb21c318],.priority-top[data-v-cb21c318],.form-row[data-v-cb21c318]{grid-template-columns:1fr}.form-row[data-v-cb21c318]{align-items:start}}@media (max-width: 768px){.page-shell[data-v-cb21c318]{padding:12px}.hero-card[data-v-cb21c318],.panel-card[data-v-cb21c318]{padding:18px}.hero-card[data-v-cb21c318],.panel-header[data-v-cb21c318],.sub-panel-header[data-v-cb21c318],.summary-card[data-v-cb21c318],.section-title-row[data-v-cb21c318],.server-group-header[data-v-cb21c318]{flex-direction:column}.hero-actions[data-v-cb21c318],.create-actions[data-v-cb21c318],.card-actions[data-v-cb21c318],.compact-actions[data-v-cb21c318],.footer-actions[data-v-cb21c318]{width:100%}.hero-actions[data-v-cb21c318]>*,.create-actions[data-v-cb21c318]>*,.card-actions[data-v-cb21c318]>*,.compact-actions[data-v-cb21c318]>*,.footer-actions[data-v-cb21c318]>*{width:100%}.tab-bar[data-v-cb21c318]{display:grid}.bot-grid[data-v-cb21c318]{grid-template-columns:1fr}}
@@ -0,0 +1 @@
1
+ export {};
package/lib/index.js CHANGED
@@ -920,65 +920,103 @@ var WsClient = class extends import_koishi5.Adapter.WsClient {
920
920
  WsClient2.Options = import_koishi5.Schema.intersect([
921
921
  import_koishi5.Schema.object({
922
922
  protocol: import_koishi5.Schema.const("ws").required(process.env.KOISHI_ENV !== "browser"),
923
- endpoint: import_koishi5.Schema.string().description("OneBot 实现的 WebSocket 服务器地址。").required(),
924
- responseTimeout: import_koishi5.Schema.natural().role("time").default(import_koishi5.Time.minute).description("等待响应的时间 (单位为毫秒)")
925
- }).description("连接设置"),
923
+ endpoint: import_koishi5.Schema.string().description("OneBot ??? WebSocket ??????").required(),
924
+ responseTimeout: import_koishi5.Schema.natural().role("time").default(import_koishi5.Time.minute).description("??????? (?????)?")
925
+ }).description("????"),
926
926
  import_koishi5.HTTP.createConfig(true),
927
927
  import_koishi5.Adapter.WsClientConfig
928
928
  ]);
929
929
  })(WsClient || (WsClient = {}));
930
930
  var kSocket = Symbol("socket");
931
- var WsServer = class extends import_koishi5.Adapter {
932
- static {
933
- __name(this, "WsServer");
934
- }
935
- static inject = ["server"];
936
- logger;
937
- wsServer;
938
- constructor(ctx, bot) {
939
- super(ctx);
931
+ var reverseHubs = /* @__PURE__ */ new WeakMap();
932
+ var ReverseHub = class {
933
+ constructor(ctx, path2) {
934
+ this.ctx = ctx;
935
+ this.path = path2;
940
936
  this.logger = ctx.logger("onebot");
941
- const { path: path2 = "/onebot" } = bot.config;
942
937
  this.wsServer = ctx.server.ws(path2, (socket, { headers }) => {
943
938
  this.logger.debug("connected with", headers);
944
939
  if (headers["x-client-role"] !== "Universal") {
945
940
  return socket.close(1008, "invalid x-client-role");
946
941
  }
947
942
  const selfId = headers["x-self-id"]?.toString();
948
- let bot2 = this.bots.find((bot3) => bot3.selfId === selfId);
949
- if (!bot2 && selfId) {
950
- const pending = this.bots.find((item) => {
951
- const managedKey = String(item.config?.managedKey || "");
952
- return managedKey.startsWith("pending_") || String(item.selfId || "").startsWith("pending_");
953
- });
954
- if (pending) {
955
- this.logger.info(`Bot ${pending.selfId} 自动绑定真实 selfId: ${selfId}`);
956
- pending.selfId = selfId;
957
- pending.config.selfId = selfId;
958
- bot2 = pending;
959
- }
943
+ let bot = selfId ? this.findBot(selfId) : void 0;
944
+ if (!bot && selfId) {
945
+ const ensureReverseBot = this.ctx._onebotMultiEnsureReverseBot;
946
+ bot = ensureReverseBot?.(selfId, this.path);
960
947
  }
961
- if (!bot2) return socket.close(1008, "invalid x-self-id");
962
- this.logger.info(`Bot ${selfId} 已连接 (ws-reverse)`);
963
- bot2[kSocket] = socket;
964
- accept(socket, bot2);
948
+ if (!bot) return socket.close(1008, "invalid x-self-id");
949
+ this.logger.info(`Bot ${selfId} ??? (ws-reverse)`);
950
+ bot[kSocket] = socket;
951
+ accept(socket, bot);
965
952
  });
966
953
  ctx.on("dispose", () => {
967
954
  this.logger.debug("ws server closing");
968
- this.wsServer.close();
955
+ this.wsServer?.close();
956
+ });
957
+ }
958
+ static {
959
+ __name(this, "ReverseHub");
960
+ }
961
+ logger;
962
+ wsServer;
963
+ findBot(selfId) {
964
+ for (const bot of this.ctx.bots) {
965
+ if (bot.platform !== "onebot") continue;
966
+ if (String(bot.selfId) !== selfId) continue;
967
+ return bot;
968
+ }
969
+ return void 0;
970
+ }
971
+ register(_bot) {
972
+ }
973
+ unregister(_bot) {
974
+ }
975
+ };
976
+ function getReverseHub(ctx, path2) {
977
+ let byPath = reverseHubs.get(ctx);
978
+ if (!byPath) {
979
+ byPath = /* @__PURE__ */ new Map();
980
+ reverseHubs.set(ctx, byPath);
981
+ }
982
+ let hub = byPath.get(path2);
983
+ if (!hub) {
984
+ hub = new ReverseHub(ctx, path2);
985
+ byPath.set(path2, hub);
986
+ }
987
+ return hub;
988
+ }
989
+ __name(getReverseHub, "getReverseHub");
990
+ var WsServer = class extends import_koishi5.Adapter {
991
+ static {
992
+ __name(this, "WsServer");
993
+ }
994
+ static inject = ["server"];
995
+ logger;
996
+ hub;
997
+ constructor(ctx, bot) {
998
+ super(ctx);
999
+ this.logger = ctx.logger("onebot");
1000
+ const { path: path2 = "/onebot" } = bot.config;
1001
+ this.hub = getReverseHub(ctx, path2);
1002
+ this.hub.register(bot);
1003
+ ctx.on("dispose", () => {
1004
+ this.hub.unregister(bot);
969
1005
  });
970
1006
  }
971
1007
  async disconnect(bot) {
1008
+ ;
972
1009
  bot[kSocket]?.close();
973
1010
  bot[kSocket] = null;
1011
+ this.hub.unregister(bot);
974
1012
  }
975
1013
  };
976
1014
  ((WsServer2) => {
977
1015
  WsServer2.Options = import_koishi5.Schema.object({
978
1016
  protocol: import_koishi5.Schema.const("ws-reverse").required(process.env.KOISHI_ENV === "browser"),
979
- path: import_koishi5.Schema.string().description("服务器监听的路径。").default("/onebot"),
980
- responseTimeout: import_koishi5.Schema.natural().role("time").default(import_koishi5.Time.minute).description("等待响应的时间 (单位为毫秒)")
981
- }).description("连接设置");
1017
+ path: import_koishi5.Schema.string().description("?????????").default("/onebot"),
1018
+ responseTimeout: import_koishi5.Schema.natural().role("time").default(import_koishi5.Time.minute).description("??????? (?????)?")
1019
+ }).description("????");
982
1020
  })(WsServer || (WsServer = {}));
983
1021
  var counter = 0;
984
1022
  var listeners = {};
@@ -1000,15 +1038,15 @@ function accept(socket, bot) {
1000
1038
  }
1001
1039
  });
1002
1040
  socket.addEventListener("error", (event) => {
1003
- bot.logger.warn(`WebSocket 错误: ${event.message || "未知错误"}`);
1041
+ bot.logger.warn(`WebSocket ??: ${event.message || "????"}`);
1004
1042
  });
1005
1043
  socket.addEventListener("close", (event) => {
1006
1044
  delete bot.internal._request;
1007
- const closeInfo = `code: ${event.code}, reason: ${event.reason || ""}`;
1045
+ const closeInfo = `code: ${event.code}, reason: ${event.reason || "?"}`;
1008
1046
  if (event.code === 1009) {
1009
- bot.logger.error(`WebSocket 因消息过大断开 (${closeInfo}),协议端可能发送了超大消息`);
1047
+ bot.logger.error(`WebSocket ??????? (${closeInfo})?????????????`);
1010
1048
  } else if (event.code !== 1e3 && event.code !== 1001) {
1011
- bot.logger.warn(`WebSocket 连接关闭 (${closeInfo})`);
1049
+ bot.logger.warn(`WebSocket ???? (${closeInfo})`);
1012
1050
  }
1013
1051
  ;
1014
1052
  bot.ctx.emit("onebot-multi/bot-offline", bot);
@@ -1453,6 +1491,9 @@ var LoadBalancer = class {
1453
1491
  /**
1454
1492
  * 检查 Bot 是否在线
1455
1493
  */
1494
+ getEffectivePriorityChannels() {
1495
+ return new Set(this.config.priorityChannels || []);
1496
+ }
1456
1497
  isBotOnline(selfId) {
1457
1498
  const bot = this.ctx.bots.find((b) => b.selfId === selfId && b.platform === "onebot");
1458
1499
  return bot?.status === STATUS_ONLINE3;
@@ -1655,7 +1696,7 @@ var LoadBalancer = class {
1655
1696
  return;
1656
1697
  }
1657
1698
  const channels = [];
1658
- const prioritySet = new Set((this.config.priorityChannels || []).map((id) => String(id).trim()).filter(Boolean));
1699
+ const prioritySet = this.getEffectivePriorityChannels();
1659
1700
  for (const [channelId, bots] of this.allChannels.entries()) {
1660
1701
  channels.push({
1661
1702
  channelId,
@@ -1730,13 +1771,8 @@ var LoadBalancer = class {
1730
1771
  }
1731
1772
  }
1732
1773
  if (assignments.length > 0) {
1733
- const batchSize = 100;
1734
- for (let i = 0; i < assignments.length; i += batchSize) {
1735
- const slice = assignments.slice(i, i + batchSize);
1736
- await Promise.all(slice.map(async ({ channelId, assignee }) => {
1737
- await this.ctx.database.setChannel("onebot", channelId, { assignee });
1738
- this.lastAssignees.set(channelId, assignee);
1739
- }));
1774
+ for (const { channelId, assignee } of assignments) {
1775
+ this.lastAssignees.set(channelId, assignee);
1740
1776
  }
1741
1777
  }
1742
1778
  const botsWithData = onlineBots.filter((id) => {
@@ -2138,7 +2174,7 @@ var ConfigStore = class {
2138
2174
  var Config = import_koishi9.Schema.object({}).description("在侧边栏webui使用,配置文件在data/adapter-onebot-multi/config.yaml");
2139
2175
  var name = "adapter-onebot-multi";
2140
2176
  var inject = {
2141
- required: ["server", "database"],
2177
+ required: ["server"],
2142
2178
  optional: ["console"]
2143
2179
  };
2144
2180
  function apply(ctx, _config) {
@@ -2148,6 +2184,16 @@ function apply(ctx, _config) {
2148
2184
  const managedBotIds = /* @__PURE__ */ new Set();
2149
2185
  const botForks = /* @__PURE__ */ new Map();
2150
2186
  const getRuntimeConfig = /* @__PURE__ */ __name(() => configStore.getRuntime(), "getRuntimeConfig");
2187
+ const isReverseTemplateBot = /* @__PURE__ */ __name((bot) => {
2188
+ return (bot.protocol || "ws-reverse") === "ws-reverse" && String(bot.selfId || "").startsWith("pending_");
2189
+ }, "isReverseTemplateBot");
2190
+ const findReverseTemplate = /* @__PURE__ */ __name((path2) => {
2191
+ return configStore.getBots().find((bot) => {
2192
+ if (bot.enabled === false) return false;
2193
+ if (!isReverseTemplateBot(bot)) return false;
2194
+ return (bot.path || "/onebot") === path2;
2195
+ });
2196
+ }, "findReverseTemplate");
2151
2197
  const getGlobalConfig = /* @__PURE__ */ __name(() => {
2152
2198
  const runtime = getRuntimeConfig();
2153
2199
  return {
@@ -2246,6 +2292,38 @@ function apply(ctx, _config) {
2246
2292
  botForks.set(selfId, fork);
2247
2293
  managedBotIds.add(selfId);
2248
2294
  }, "startBot");
2295
+ const ensureReverseBot = /* @__PURE__ */ __name((selfId, path2) => {
2296
+ const normalizedSelfId = String(selfId || "").trim();
2297
+ const normalizedPath = path2 || "/onebot";
2298
+ if (!normalizedSelfId) return;
2299
+ const live = ctx.bots.find((bot) => bot.selfId === normalizedSelfId && bot.platform === "onebot");
2300
+ if (live) return live;
2301
+ const existing = configStore.getBots().find((bot) => {
2302
+ return bot.selfId === normalizedSelfId && (bot.protocol || "ws-reverse") === "ws-reverse";
2303
+ });
2304
+ if (existing) {
2305
+ startBot(existing);
2306
+ return ctx.bots.find((bot) => bot.selfId === normalizedSelfId && bot.platform === "onebot");
2307
+ }
2308
+ const template = findReverseTemplate(normalizedPath);
2309
+ if (!template) {
2310
+ logger.warn(`未找到 path=${normalizedPath} 的 ws-reverse 模板,拒绝动态创建 Bot ${normalizedSelfId}`);
2311
+ return;
2312
+ }
2313
+ const dynamicBot = {
2314
+ selfId: normalizedSelfId,
2315
+ token: template.token,
2316
+ protocol: "ws-reverse",
2317
+ path: normalizedPath,
2318
+ name: template.name && template.name !== "服务器" ? template.name : void 0,
2319
+ enabled: true
2320
+ };
2321
+ configStore.setBots([...configStore.getBots(), dynamicBot]);
2322
+ startBot(dynamicBot);
2323
+ logger.info(`已为反向 WS 连接动态创建 Bot ${normalizedSelfId} (${normalizedPath})`);
2324
+ return ctx.bots.find((bot) => bot.selfId === normalizedSelfId && bot.platform === "onebot");
2325
+ }, "ensureReverseBot");
2326
+ ctx._onebotMultiEnsureReverseBot = ensureReverseBot;
2249
2327
  const stopBot = /* @__PURE__ */ __name(async (selfId) => {
2250
2328
  try {
2251
2329
  const fork = botForks.get(selfId);
@@ -2312,39 +2390,39 @@ function apply(ctx, _config) {
2312
2390
  configStore.setBots(filtered);
2313
2391
  return nextSelfId;
2314
2392
  }, "upsertBot");
2315
- ctx.command("onebot.balance", "查看 OneBot 负载均衡状态").alias("ob.balance").alias("负载均衡").action(async () => {
2393
+ ctx.command("onebot.balance", "?? OneBot ??????").alias("ob.balance").alias("????").action(async () => {
2316
2394
  if (!configStore.getLoadBalance().enabled) {
2317
- return "负载均衡未启用。";
2395
+ return "????????";
2318
2396
  }
2319
2397
  const status = loadBalancer.getDetailedStatus();
2320
2398
  const elements = [];
2321
- elements.push(import_koishi9.h.text("═══ OneBot 负载均衡状态 ═══\n\n"));
2322
- elements.push(import_koishi9.h.text(`📊 总览
2399
+ elements.push(import_koishi9.h.text("??? OneBot ?????? ???\n\n"));
2400
+ elements.push(import_koishi9.h.text(`?? ??
2323
2401
  `));
2324
- elements.push(import_koishi9.h.text(` 在线 Bot: ${status.onlineBots}
2402
+ elements.push(import_koishi9.h.text(` ?? Bot: ${status.onlineBots} ?
2325
2403
  `));
2326
- elements.push(import_koishi9.h.text(` 管理群数: ${status.totalChannels}
2404
+ elements.push(import_koishi9.h.text(` ????: ${status.totalChannels} ?
2327
2405
  `));
2328
- elements.push(import_koishi9.h.text(` 已分配群: ${status.assignedChannels}
2406
+ elements.push(import_koishi9.h.text(` ????: ${status.assignedChannels} ?
2329
2407
  `));
2330
- elements.push(import_koishi9.h.text(` 未分配群: ${status.unassignedChannels}
2408
+ elements.push(import_koishi9.h.text(` ????: ${status.unassignedChannels} ?
2331
2409
 
2332
2410
  `));
2333
- elements.push(import_koishi9.h.text(`🤖 Bot 负载详情
2411
+ elements.push(import_koishi9.h.text(`?? Bot ????
2334
2412
  `));
2335
2413
  for (const bot of status.bots) {
2336
- const maxLoadStr = bot.maxLoad === 0 ? "无限制" : `${bot.maxLoad}`;
2337
- const remainingStr = bot.maxLoad === 0 ? "" : `${bot.remaining}`;
2414
+ const maxLoadStr = bot.maxLoad === 0 ? "???" : `${bot.maxLoad}`;
2415
+ const remainingStr = bot.maxLoad === 0 ? "?" : `${bot.remaining}`;
2338
2416
  const barLength = 20;
2339
2417
  const usedLength = bot.maxLoad === 0 ? Math.min(Math.round(bot.assignedCount / Math.max(bot.channelCount, 1) * barLength), barLength) : Math.round(bot.assignedCount / bot.maxLoad * barLength);
2340
- const bar = "".repeat(usedLength) + "".repeat(barLength - usedLength);
2418
+ const bar = "?".repeat(usedLength) + "?".repeat(barLength - usedLength);
2341
2419
  elements.push(import_koishi9.h.image(bot.avatarUrl));
2342
2420
  elements.push(import_koishi9.h.text("\n"));
2343
2421
  elements.push(import_koishi9.h.text(` ${bot.nickname} (${bot.selfId})
2344
2422
  `));
2345
- elements.push(import_koishi9.h.text(` 所在群: ${bot.channelCount} | 负责群: ${bot.assignedCount} | 上限: ${maxLoadStr}
2423
+ elements.push(import_koishi9.h.text(` ???: ${bot.channelCount} | ???: ${bot.assignedCount} | ??: ${maxLoadStr}
2346
2424
  `));
2347
- elements.push(import_koishi9.h.text(` 剩余容量: ${remainingStr}
2425
+ elements.push(import_koishi9.h.text(` ????: ${remainingStr}
2348
2426
  `));
2349
2427
  elements.push(import_koishi9.h.text(` [${bar}]
2350
2428
 
@@ -2407,7 +2485,7 @@ function apply(ctx, _config) {
2407
2485
  }, { authority: 4 });
2408
2486
  ctx2.console.addListener("onebot-multi/bots/profile", async ({ selfId, nickname }) => {
2409
2487
  const bot = ctx2.bots.find((b) => b.selfId === selfId && b.platform === "onebot");
2410
- if (!bot) return { success: false, error: `Bot ${selfId} 未在线` };
2488
+ if (!bot) return { success: false, error: `Bot ${selfId} ???` };
2411
2489
  await bot.internal.setQqProfile(nickname || "", "", "", "", "");
2412
2490
  const loginInfo = await bot.internal.getLoginInfo();
2413
2491
  if (loginInfo?.nickname) {
@@ -2417,7 +2495,7 @@ function apply(ctx, _config) {
2417
2495
  }, { authority: 4 });
2418
2496
  ctx2.console.addListener("onebot-multi/bots/avatar", async ({ selfId, file }) => {
2419
2497
  const bot = ctx2.bots.find((b) => b.selfId === selfId && b.platform === "onebot");
2420
- if (!bot) return { success: false, error: `Bot ${selfId} 未在线` };
2498
+ if (!bot) return { success: false, error: `Bot ${selfId} ???` };
2421
2499
  await bot.internal.setQqAvatar(file);
2422
2500
  return { success: true };
2423
2501
  }, { authority: 4 });
@@ -2443,7 +2521,7 @@ function apply(ctx, _config) {
2443
2521
  }, { authority: 4 });
2444
2522
  });
2445
2523
  ctx.on("ready", () => {
2446
- syncBots().catch((error) => logger.error("同步 Bot 启动状态失败: %s", error));
2524
+ syncBots().catch((error) => logger.error("?? Bot ??????: %s", error));
2447
2525
  });
2448
2526
  ctx.on("onebot-multi/bot-online", (bot) => {
2449
2527
  const configKey = String(bot.config?.managedKey || bot.selfId);
@@ -2458,7 +2536,7 @@ function apply(ctx, _config) {
2458
2536
  bot.config.managedKey = runtimeSelfId;
2459
2537
  managedBotIds.delete(configKey);
2460
2538
  managedBotIds.add(runtimeSelfId);
2461
- logger.info(`Bot 配置 selfId 自动更新: ${configKey} -> ${runtimeSelfId}`);
2539
+ logger.info(`Bot ?? selfId ????: ${configKey} -> ${runtimeSelfId}`);
2462
2540
  });
2463
2541
  ctx.on("dispose", async () => {
2464
2542
  stopConfigWatcher();
@@ -30,6 +30,7 @@ export declare class LoadBalancer {
30
30
  /**
31
31
  * 检查 Bot 是否在线
32
32
  */
33
+ private getEffectivePriorityChannels;
33
34
  private isBotOnline;
34
35
  /**
35
36
  * 获取所有在线的 OneBot
package/lib/ws.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Adapter, Context, HTTP, Logger, Schema, Universal } from 'koishi';
2
- import { WebSocketLayer } from '@koishijs/plugin-server';
3
2
  import type { OneBotBot } from './bot';
4
3
  export interface SharedConfig<T = 'ws' | 'ws-reverse'> {
5
4
  protocol: T;
@@ -19,7 +18,7 @@ export declare namespace WsClient {
19
18
  export declare class WsServer<C extends Context> extends Adapter<C, OneBotBot<C, any>> {
20
19
  static inject: string[];
21
20
  logger: Logger;
22
- wsServer?: WebSocketLayer;
21
+ private hub;
23
22
  constructor(ctx: C, bot: OneBotBot<C>);
24
23
  disconnect(bot: OneBotBot<C>): Promise<void>;
25
24
  }