koishi-plugin-chat-patch 1.0.14 → 1.0.15

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.
@@ -23,8 +23,9 @@ export function useChatLogic() {
23
23
  id: string
24
24
  name: string
25
25
  type: number | string
26
- guildId?: string
26
+ channelId?: string
27
27
  guildName?: string
28
+ isDirect?: boolean
28
29
  }
29
30
 
30
31
  interface MessageElement {
@@ -2368,16 +2369,17 @@ export function useChatLogic() {
2368
2369
  }
2369
2370
 
2370
2371
  if (messageEvent.channelId && !chatData.value.channels[messageEvent.selfId][messageEvent.channelId]) {
2371
- const channelName = messageEvent.guildId
2372
- ? `${messageEvent.guildName || messageEvent.guildId} (${messageEvent.channelId})`
2373
- : `私信 ${messageEvent.channelId}`
2372
+ const channelName = messageEvent.isDirect
2373
+ ? `私信 ${messageEvent.channelId}`
2374
+ : `${messageEvent.guildName || messageEvent.channelId} (${messageEvent.channelId})`
2374
2375
 
2375
2376
  chatData.value.channels[messageEvent.selfId][messageEvent.channelId] = {
2376
2377
  id: messageEvent.channelId,
2377
2378
  name: channelName,
2378
2379
  type: messageEvent.channelType || 0,
2379
- guildId: messageEvent.guildId,
2380
- guildName: messageEvent.guildName || messageEvent.guildId || '私聊'
2380
+ channelId: messageEvent.channelId,
2381
+ guildName: messageEvent.guildName || '群聊',
2382
+ isDirect: messageEvent.isDirect
2381
2383
  }
2382
2384
  }
2383
2385
 
@@ -2561,16 +2563,17 @@ export function useChatLogic() {
2561
2563
  }
2562
2564
 
2563
2565
  if (botMessageEvent.channelId && !chatData.value.channels[botMessageEvent.selfId][botMessageEvent.channelId]) {
2564
- const channelName = botMessageEvent.guildId
2565
- ? `${botMessageEvent.guildName || botMessageEvent.guildId} (${botMessageEvent.channelId})`
2566
- : `私信 ${botMessageEvent.channelId}`
2566
+ const channelName = botMessageEvent.isDirect
2567
+ ? `私信 ${botMessageEvent.channelId}`
2568
+ : `${botMessageEvent.guildName || botMessageEvent.channelId} (${botMessageEvent.channelId})`
2567
2569
 
2568
2570
  chatData.value.channels[botMessageEvent.selfId][botMessageEvent.channelId] = {
2569
2571
  id: botMessageEvent.channelId,
2570
2572
  name: channelName,
2571
2573
  type: botMessageEvent.channelType || 0,
2572
- guildId: botMessageEvent.guildId,
2573
- guildName: botMessageEvent.guildName || botMessageEvent.guildId || '私聊'
2574
+ channelId: botMessageEvent.channelId,
2575
+ guildName: botMessageEvent.guildName || '群聊',
2576
+ isDirect: botMessageEvent.isDirect
2574
2577
  }
2575
2578
  }
2576
2579
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{defineComponent as Ce,ref as v,onMounted as nt,h,computed as Q,watch as kt,nextTick as Ie,onUnmounted as ma,createElementBlock as x,openBlock as y,unref as r,normalizeStyle as st,normalizeClass as re,createElementVNode as f,createCommentVNode as xe,Fragment as E,renderList as De,createBlock as Ne,toDisplayString as _,withDirectives as bt,createTextVNode as ot,vShow as va,withModifiers as St,withKeys as ga,isRef as ya,vModelText as pa,resolveComponent as wa}from"vue";import{receive as rt,send as P,icons as Ia}from"@koishijs/client";function xa(){function ee(e){try{return new URL(e).protocol==="file:"}catch{return false}}const le=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=async()=>{try{t.value="loading";const i=await Ve(e.channelKey,e.src);if(i){a.value=i,t.value="loaded";return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const d=new Promise((k,w)=>{c.onload=()=>k(),c.onerror=()=>w(new Error("Direct load failed")),c.src=e.src}),p=new Promise((k,w)=>{setTimeout(()=>w(new Error("Timeout")),3e3)});try{await Promise.race([d,p]),a.value=e.src,t.value="loaded",we(e.channelKey,e.src).catch(k=>{console.warn("异步缓存头像失败:",k)})}catch{await s()}}catch(i){console.error("头像加载失败:",i),t.value="error",n.value="头像加载失败"}},s=async()=>{try{t.value="caching";const i=await we(e.channelKey,e.src);if(i)a.value=i,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(i){console.error("缓存系统加载头像失败:",i),t.value="error",n.value=(i==null?void 0:i.message)||"缓存加载失败"}};return nt(()=>{o()}),()=>{switch(t.value){case"loading":case"caching":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return h("img",{src:a.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),X=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=v(null),s=async()=>{try{t.value="loading";const c=await Ve(e.channelKey,e.src);if(c){a.value=c,t.value="loaded";return}if(ee(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await i();return}const d=new Image;d.crossOrigin="anonymous",d.referrerPolicy="no-referrer",d.draggable=false;const p=new Promise((w,R)=>{d.onload=()=>w(),d.onerror=()=>R(new Error("Direct load failed")),d.src=e.src}),k=new Promise((w,R)=>{setTimeout(()=>R(new Error("Timeout")),3e3)});try{await Promise.race([p,k]),a.value=e.src,t.value="loaded",we(e.channelKey,e.src).catch(w=>{console.warn("异步缓存图片失败:",w)})}catch{await i()}}catch(c){console.error("图片加载失败:",c),t.value="error",n.value="图片加载失败"}},i=async()=>{try{t.value="caching";const c=await we(e.channelKey,e.src);if(c)a.value=c,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(c){console.error("缓存系统加载图片失败:",c),t.value="error",n.value=(c==null?void 0:c.message)||"缓存加载失败"}};return nt(()=>{s()}),()=>{switch(t.value){case"loading":return h("div",{class:"message-image-loading"},"加载中...");case"caching":return h("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return h("img",{src:a.value,alt:e.alt,class:"message-image",loading:"lazy",ref:o,draggable:false,style:{"max-width":"min(400px, 66.67vw)","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return h("div",{class:"message-image-error"},["图片加载失败",h("br"),h("small",e.filename||e.alt||"未知图片"),h("br"),h("small",{style:"color: #ff9800;"},n.value)]);default:return h("div",{class:"message-image-error"},"未知状态")}}}}),ge=Ce({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const a=(()=>{try{const o=JSON.parse(e.data);if(o.meta&&o.meta.detail_1){const s=o.meta.detail_1;return{type:"share_card",title:s.title||o.prompt||"分享内容",desc:s.desc||"",preview:s.preview?s.preview.replace(/\\\//g,"/"):"",icon:s.icon?s.icon.replace(/\\\//g,"/"):"",url:s.qqdocurl?s.qqdocurl.replace(/\\\//g,"/"):s.url?s.url.replace(/\\\//g,"/"):"",appName:s.title||"应用"}}return{type:"raw",data:o}}catch(o){return console.error("解析JSON数据失败:",o),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{a.type==="share_card"&&a.url&&window.open(a.url,"_blank","noopener,noreferrer")};return()=>a.type==="share_card"&&a.preview?h("img",{src:a.preview,alt:a.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:a.url?"pointer":"default"},title:a.url?`点击打开: ${a.title||"链接"}`:a.title,onError:o=>{const i=o.target.parentElement;i&&(i.style.display="none")}}):a.type==="error"?h("div",{class:"message-json-error"},[h("span",{class:"json-error-text"},a.error),h("details",{class:"json-raw-data"},[h("summary","查看原始数据"),h("pre",{class:"json-raw-content"},e.data)])]):h("div",{class:"message-json-raw"},[h("div",{class:"json-label"},"[JSON数据]"),h("details",{class:"json-raw-data"},[h("summary","查看详情"),h("pre",{class:"json-raw-content"},JSON.stringify(a.data,null,2))])])}}),G=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=v(false),a=()=>{t.value=!t.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(d=>d.type==="message"),i=s.length;return{previews:s.slice(0,3).map(d=>{var w,R;const p=((w=d.attrs)==null?void 0:w.nickname)||"用户";let k="";if(d.children&&d.children.length>0){const z=d.children[0];z.type==="text"?(k=(((R=z.attrs)==null?void 0:R.content)||"").substring(0,20),k.length>15&&(k+="...")):z.type==="img"?k="[图片]":z.type==="video"?k="[视频]":k=`[${z.type}]`}return`${p}:${k}`}),messageCount:i}},o=(s,i)=>{var p,k,w;const c=((p=s.attrs)==null?void 0:p.nickname)||"用户",d=((k=s.attrs)==null?void 0:k.userId)||"unknown";return h("div",{key:i,class:"forwarded-message-item"},[h("div",{class:"forwarded-message-header"},[h("span",{class:"forwarded-message-nickname"},c),h("span",{class:"forwarded-message-userid"},`(${d})`)]),h("div",{class:"forwarded-message-content"},((w=s.children)==null?void 0:w.map((R,z)=>h(ke,{key:z,element:R,channelKey:e.channelKey})))||[])])};return()=>{var c;const{previews:s,messageCount:i}=n();return h("div",{class:"forward-message-container"},[h("div",{class:"forward-message-preview",onClick:a},[h("div",{class:"forward-message-title"},"聊天记录"),...s.map((d,p)=>h("div",{key:p,class:"forward-message-preview-item"},d)),h("div",{class:"forward-message-footer"},[h("span",{class:"forward-message-count"},`查看${i}条转发消息`),h("span",{class:"forward-message-toggle"},t.value?"▲":"▼")])]),t.value&&h("div",{class:"forward-message-expanded"},((c=e.element.children)==null?void 0:c.filter(d=>d.type==="message").map((d,p)=>o(d,p)))||[])])}}}),ke=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=a=>{var n,o,s,i,c,d;switch(a.type){case"text":return h("span",{class:"message-text-content"},a.attrs.content||"");case"forward":return h("span",{class:"message-text-content"},`[转发消息 ${a.attrs.id}]`||"[转发消息]");case"img":case"image":const p=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(X,{src:p,alt:a.attrs.summary||"图片",filename:a.attrs.filename||a.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const k=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(X,{src:k,alt:a.attrs.summary||"表情",filename:a.attrs.emojiId||a.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((o=(n=a.children[0])==null?void 0:n.attrs)!=null&&o.src){const w=((i=(s=a.children[0])==null?void 0:s.attrs)==null?void 0:i.src)||((d=(c=a.children[0])==null?void 0:c.attrs)==null?void 0:d.url);return h("div",{class:"message-image-container"},[h(X,{src:w,alt:a.attrs.name||a.attrs.id||"[表情]",filename:a.attrs.name||a.attrs.id||"[表情]",channelKey:e.channelKey})])}else return h("span",{class:"message-text-content"},`[${a.attrs.name||a.attrs.id}]`||"[表情]");case"at":return h("span",{class:"message-at",title:a.attrs.name},`${a.attrs.name||a.attrs.id}`);case"json":return h("div",{class:"message-image-container"},[h(ge,{data:a.attrs.data||"",channelKey:e.channelKey})]);case"p":if(a.children&&a.children.length>0){const w=a.children.map((R,z)=>h(ke,{key:z,element:R,channelKey:e.channelKey}));return h("div",{class:"message-paragraph"},w)}else return h("div",{class:"message-paragraph"},"");case"figure":return h(G,{element:a,channelKey:e.channelKey});default:return h("span",{class:"message-unknown",title:`未知消息类型: ${a.type}`},a.attrs.content||`[${a.type}]`)}};return()=>t(e.element)}}),u=v({bots:{},channels:{},messages:{}}),q=v({}),ce=v({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=v({}),be=100*1024*1024,ie=50;let ye=0,I=null;const Re="ChatImageCache",Oe=2,S="images",te=50*1024*1024,U=100,ue=500,Te=2*1024*1024,Fe=.8,We=60*1e3;let O=0,K=0,He=0;const g=v(""),$=v(""),Se=v(""),Y=v([]),de=v(false),Le=v(),L=v(false),V=v("bots"),F=v(null),ae=v(null),Be=v(false),fe=v({show:false,text:""}),B=v(),he=v(),$e=v(false),ne=v(false),me=v(false),se=v(""),M=v({x:0,y:0}),A=v({x:0,y:0}),_e=v({x:0,y:0}),pe=v({x:0,y:0}),H=80,qe=v(0),j=v(null),Z=v(false),C=v(null),N=v({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),W=v(new Set),oe=v(new Set),m=Q(()=>Object.values(u.value.bots).sort((t,a)=>{const n=W.value.has(t.selfId),o=W.value.has(a.selfId);return n&&!o?-1:!n&&o?1:0})),l=Q(()=>!g.value||!u.value.channels[g.value]?[]:Object.values(u.value.channels[g.value]).sort((t,a)=>{const n=oe.value.has(`${g.value}:${t.id}`),o=oe.value.has(`${g.value}:${a.id}`);return n&&!o?-1:!n&&o?1:0})),D=Q(()=>{if(!g.value||!$.value)return[];const e=`${g.value}:${$.value}`,t=u.value.messages[e]||[];return t.filter(a=>a.quote),t}),Ue=Q(()=>{var t;if(!g.value||!$.value)return"";const e=u.value.channels[g.value];return((t=e==null?void 0:e[$.value])==null?void 0:t.name)||""}),$t=Q(()=>!g.value||!$.value?"":`${g.value}:${$.value}`),lt=Q(()=>g.value&&$.value&&(Se.value.trim()||Y.value.length>0)&&!me.value),_t=Q(()=>g.value&&$.value&&!me.value),Dt=Q(()=>{if(!L.value)return"";switch(V.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),Tt=Q(()=>L.value?"输入消息...(屏幕左滑返回)":"输入消息..."),Lt=Q(()=>({}));function ct(e){return e.size||0}function Xe(e){ye+=e,ce.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(ye/1024/1024).toFixed(2)}MB`)}function it(e=10){const t=Object.entries(b.value);if(t.length<=e)return;const a=t.slice(0,t.length-e);let n=0;a.forEach(([o,s])=>{URL.revokeObjectURL(s),delete b.value[o],n+=500*1024,ce.value.loggerinfo&&console.log("清理旧blob URL:",o)}),Xe(-n)}function Je(){Object.keys(b.value).length>ie&&it(Math.floor(ie*.7)),ye>be&&it(Math.floor(ie*.5))}function qt(e){g.value=e,$.value="",L.value&&(V.value="channels")}function Ut(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="bot"&&N.value.targetId===t){J();return}Ge(e,"bot",t)}function Kt(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="channel"&&N.value.targetId===t){J();return}Ge(e,"channel",t)}function Ge(e,t,a){let s=e.clientX,i=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),i+80>window.innerHeight&&(i=window.innerHeight-80-10),N.value={show:true,x:s,y:i,type:t,targetId:a,isSecondClick:false},document.addEventListener("click",J,{once:true}),document.addEventListener("keydown",Ze)}function J(){N.value.show=false,document.removeEventListener("click",J),document.removeEventListener("keydown",Ze)}function Ze(e){e.key==="Escape"&&N.value.show&&J()}async function Mt(e){W.value.has(e)?W.value.delete(e):W.value.add(e),await P("set-pinned-bots",{pinnedBots:Array.from(W.value)}),J()}async function At(e){const t=`${g.value}:${e}`;oe.value.has(t)?oe.value.delete(t):oe.value.add(t),await P("set-pinned-channels",{pinnedChannels:Array.from(oe.value)}),J()}async function zt(e){try{const t=await P("delete-bot-data",{selfId:e});if(t.success){const a=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of a)delete u.value.messages[n],delete q.value[n],await je(n);delete u.value.bots[e],delete u.value.channels[e],g.value===e&&(g.value="",$.value=""),T(t.message||"已删除该机器人的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除机器人数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}J()}async function Pt(e){try{const t=await P("delete-channel-data",{selfId:g.value,channelId:e});if(t.success){const a=`${g.value}:${e}`;delete u.value.messages[a],delete q.value[a],u.value.channels[g.value]&&delete u.value.channels[g.value][e],await je(a),$.value===e&&($.value=""),T(t.message||"已删除该频道的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除频道数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}J()}async function jt(e){$.value=e,ne.value=false,L.value&&(V.value="messages"),g.value&&await It(g.value,e),Ie(()=>{ve(),!L.value&&he.value&&he.value.focus()})}async function Nt(){if(!lt.value)return;const e=Se.value.trim();if(!e&&Y.value.length===0)return;me.value=true;const t=[...Y.value];try{const a=await P("send-message",{selfId:g.value,channelId:$.value,content:e,images:t.map(n=>({tempId:n.tempId,filename:n.filename}))});if(a.success){if(Se.value="",t.forEach(n=>{URL.revokeObjectURL(n.preview)}),Y.value=[],de.value=false,a.tempImageIds&&a.tempImageIds.length>0)try{await P("cleanup-temp-images",{tempImageIds:a.tempImageIds}),console.log("临时图片清理完成:",a.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",a.error),T("发送失败: "+a.error,"error")}catch(a){console.error("发送消息时出错:",a),T("发送失败: "+((a==null?void 0:a.message)||String(a)),"error")}finally{me.value=false}}function Rt(){de.value=!de.value}function Ot(){Le.value&&Le.value.click(),de.value=false}async function Ft(e){const t=e.target,a=t.files;if(!(!a||a.length===0)){for(const n of Array.from(a))await Qe(n);t.value=""}}async function Ht(e){var a;const t=(a=e.clipboardData)==null?void 0:a.items;if(t){for(const n of Array.from(t))if(n.type.startsWith("image/")){e.preventDefault();const o=n.getAsFile();o&&await Qe(o)}}}async function Qe(e){try{if(e.size>10*1024*1024){T("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){T("请选择图片文件","error");return}const t=await ut(e),a=URL.createObjectURL(e),n=await P("upload-image",{file:t,filename:e.name,mimeType:e.type});n.success?Y.value.push({tempId:n.tempId,filename:e.name,preview:a,size:e.size}):(URL.revokeObjectURL(a),T("图片上传失败: "+n.error,"error"))}catch(t){console.error("上传图片失败:",t),T("图片上传失败: "+((t==null?void 0:t.message)||String(t)),"error")}}async function Xt(e){try{const t=Y.value.findIndex(a=>a.tempId===e);if(t!==-1){const a=Y.value[t];URL.revokeObjectURL(a.preview),Y.value.splice(t,1)}await P("delete-temp-image",{tempId:e})}catch(t){console.error("删除图片失败:",t)}}function ut(e){return new Promise((t,a)=>{const n=new FileReader;n.onload=()=>t(n.result),n.onerror=a,n.readAsDataURL(e)})}function Ee(e){const t=e.target;t.closest(".input-actions")||(de.value=false),t.closest(".context-menu")||J()}function Yt(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function Vt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function ve(){B.value&&(B.value.scrollTop=B.value.scrollHeight,$e.value=false,ne.value=false)}function Ke(){if(B.value){const{scrollTop:e,scrollHeight:t,clientHeight:a}=B.value,o=t-(e+a)<=50,s=!o;$e.value=s,o?ne.value=false:ne.value=true}}function Me(){if(!B.value)return true;const{scrollTop:e,scrollHeight:t,clientHeight:a}=B.value;return t-(e+a)<=200}function dt(e){var n;if(!g.value)return 0;const t=`${g.value}:${e}`,a=q.value[t];return a!==void 0?a:((n=u.value.messages[t])==null?void 0:n.length)||0}function Wt(e,t){e.preventDefault(),e.stopPropagation();const a="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;qe.value=Date.now(),M.value={x:a,y:n},A.value={x:a,y:n},Z.value=false;const s=e.target.getBoundingClientRect();_e.value={x:s.left,y:s.top},pe.value={x:a-s.left,y:n-s.top},j.value=window.setTimeout(()=>{if(qe.value>0){Z.value=true,se.value=t;const i=e.target,c=i.cloneNode(true);c.classList.add("dragging-clone"),c.style.position="fixed",c.style.zIndex="1000",c.style.pointerEvents="none";const d=i.getBoundingClientRect();c.style.left=`${d.left}px`,c.style.top=`${d.top}px`,c.style.width=`${d.width}px`,c.style.height=`${d.height}px`,document.body.appendChild(c),C.value=c,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),ht(M.value.x,M.value.y)}},60),document.addEventListener("mousemove",Ae),document.addEventListener("mouseup",ze),document.addEventListener("touchmove",Ae),document.addEventListener("touchend",ze)}function Ae(e){if(!Z.value||!C.value)return;e.preventDefault();const t="touches"in e?e.touches[0].clientX:e.clientX,a="touches"in e?e.touches[0].clientY:e.clientY;A.value={x:t,y:a};const n=A.value.x-M.value.x,o=A.value.y-M.value.y,s=Math.sqrt(n*n+o*o),i=Math.max(.3,1-s/(H*2)),c=Math.max(.8,1-s/(H*3)),d=s>H,p=A.value.x-pe.value.x,k=A.value.y-pe.value.y;C.value.style.left=`${p}px`,C.value.style.top=`${k}px`,C.value.style.transform=`scale(${c})`,C.value.style.opacity=`${i}`,C.value.style.backgroundColor=d?"#f44336":"#2196f3",C.value.style.boxShadow=d?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",d?C.value.classList.add("will-delete"):C.value.classList.remove("will-delete")}function ze(e){if(j.value&&(clearTimeout(j.value),j.value=null),j.value&&(clearTimeout(j.value),j.value=null),!Z.value||!se.value){Pe();return}const t=se.value;if(Math.sqrt(Math.pow(A.value.x-M.value.x,2)+Math.pow(A.value.y-M.value.y,2))>H)ft(t),Pe();else if(C.value){C.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${t}"] .channel-message-count`);if(n){const o=n.getBoundingClientRect();C.value.style.left=`${o.left}px`,C.value.style.top=`${o.top}px`,C.value.style.transform="scale(1)",C.value.style.opacity="1",C.value.style.backgroundColor="#2196f3",C.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{Pe()},300)}else Pe()}function Pe(){j.value&&(clearTimeout(j.value),j.value=null),se.value="",M.value={x:0,y:0},A.value={x:0,y:0},_e.value={x:0,y:0},qe.value=0,Z.value=false,document.removeEventListener("mousemove",Ae),document.removeEventListener("mouseup",ze),document.removeEventListener("touchmove",Ae),document.removeEventListener("touchend",ze),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),C.value&&C.value.parentNode&&(C.value.parentNode.removeChild(C.value),C.value=null),mt()}function Jt(e){return se.value===e&&Z.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function Gt(e){if(se.value!==e)return 0;const t=A.value.x-M.value.x,a=A.value.y-M.value.y;return Math.sqrt(t*t+a*a)}async function ft(e){if(g.value)try{const t=`${g.value}:${e}`,a=dt(e),n=ce.value.keepMessagesOnClear;if(n>0&&a<=n){T("当前消息还很少诶~ 无需清理","success");return}const o=await P("clear-channel-history",{selfId:g.value,channelId:e});if(o.success)if(o.clearedCount&&o.clearedCount>0){if(u.value.messages[t]){const i=[...u.value.messages[t]].sort((c,d)=>c.timestamp-d.timestamp);u.value.messages[t]=i.slice(-o.keptCount)}q.value[t]=o.keptCount,await je(t),T(`历史记录已清理,清理了 ${o.clearedCount} 条消息,保留最新 ${o.keptCount} 条`,"success")}else n===0?(u.value.messages[t]&&(u.value.messages[t]=[]),q.value[t]=0,await je(t),T("历史记录已清理,所有消息已删除","success")):T("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",o.error),T("清理失败: "+o.error,"error")}catch(t){console.error("清理历史记录时出错:",t),T("清理失败: "+((t==null?void 0:t.message)||String(t)),"error")}}function T(e,t="success"){const a=document.createElement("div");a.className=`notification ${t}`,a.textContent=e;let n="#4caf50";switch(t){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}a.style.cssText=`
1
+ import{defineComponent as Ce,ref as v,onMounted as nt,h,computed as E,watch as kt,nextTick as xe,onUnmounted as ma,createElementBlock as x,openBlock as y,unref as r,normalizeStyle as st,normalizeClass as le,createCommentVNode as S,createElementVNode as f,Fragment as ee,renderList as De,createBlock as Ne,toDisplayString as D,withDirectives as bt,createTextVNode as ot,vShow as va,withModifiers as St,withKeys as ga,isRef as ya,vModelText as pa,resolveComponent as wa}from"vue";import{receive as rt,send as j,icons as Ia}from"@koishijs/client";function xa(){function te(e){try{return new URL(e).protocol==="file:"}catch{return false}}const ce=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=async()=>{try{t.value="loading";const i=await Ve(e.channelKey,e.src);if(i){a.value=i,t.value="loaded";return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const d=new Promise((k,w)=>{c.onload=()=>k(),c.onerror=()=>w(new Error("Direct load failed")),c.src=e.src}),p=new Promise((k,w)=>{setTimeout(()=>w(new Error("Timeout")),3e3)});try{await Promise.race([d,p]),a.value=e.src,t.value="loaded",Ie(e.channelKey,e.src).catch(k=>{console.warn("异步缓存头像失败:",k)})}catch{await s()}}catch(i){console.error("头像加载失败:",i),t.value="error",n.value="头像加载失败"}},s=async()=>{try{t.value="caching";const i=await Ie(e.channelKey,e.src);if(i)a.value=i,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(i){console.error("缓存系统加载头像失败:",i),t.value="error",n.value=(i==null?void 0:i.message)||"缓存加载失败"}};return nt(()=>{o()}),()=>{switch(t.value){case"loading":case"caching":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return h("img",{src:a.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),Y=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=v(null),s=async()=>{try{t.value="loading";const c=await Ve(e.channelKey,e.src);if(c){a.value=c,t.value="loaded";return}if(te(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await i();return}const d=new Image;d.crossOrigin="anonymous",d.referrerPolicy="no-referrer",d.draggable=false;const p=new Promise((w,O)=>{d.onload=()=>w(),d.onerror=()=>O(new Error("Direct load failed")),d.src=e.src}),k=new Promise((w,O)=>{setTimeout(()=>O(new Error("Timeout")),3e3)});try{await Promise.race([p,k]),a.value=e.src,t.value="loaded",Ie(e.channelKey,e.src).catch(w=>{console.warn("异步缓存图片失败:",w)})}catch{await i()}}catch(c){console.error("图片加载失败:",c),t.value="error",n.value="图片加载失败"}},i=async()=>{try{t.value="caching";const c=await Ie(e.channelKey,e.src);if(c)a.value=c,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(c){console.error("缓存系统加载图片失败:",c),t.value="error",n.value=(c==null?void 0:c.message)||"缓存加载失败"}};return nt(()=>{s()}),()=>{switch(t.value){case"loading":return h("div",{class:"message-image-loading"},"加载中...");case"caching":return h("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return h("img",{src:a.value,alt:e.alt,class:"message-image",loading:"lazy",ref:o,draggable:false,style:{"max-width":"min(400px, 66.67vw)","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return h("div",{class:"message-image-error"},["图片加载失败",h("br"),h("small",e.filename||e.alt||"未知图片"),h("br"),h("small",{style:"color: #ff9800;"},n.value)]);default:return h("div",{class:"message-image-error"},"未知状态")}}}}),ye=Ce({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const a=(()=>{try{const o=JSON.parse(e.data);if(o.meta&&o.meta.detail_1){const s=o.meta.detail_1;return{type:"share_card",title:s.title||o.prompt||"分享内容",desc:s.desc||"",preview:s.preview?s.preview.replace(/\\\//g,"/"):"",icon:s.icon?s.icon.replace(/\\\//g,"/"):"",url:s.qqdocurl?s.qqdocurl.replace(/\\\//g,"/"):s.url?s.url.replace(/\\\//g,"/"):"",appName:s.title||"应用"}}return{type:"raw",data:o}}catch(o){return console.error("解析JSON数据失败:",o),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{a.type==="share_card"&&a.url&&window.open(a.url,"_blank","noopener,noreferrer")};return()=>a.type==="share_card"&&a.preview?h("img",{src:a.preview,alt:a.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:a.url?"pointer":"default"},title:a.url?`点击打开: ${a.title||"链接"}`:a.title,onError:o=>{const i=o.target.parentElement;i&&(i.style.display="none")}}):a.type==="error"?h("div",{class:"message-json-error"},[h("span",{class:"json-error-text"},a.error),h("details",{class:"json-raw-data"},[h("summary","查看原始数据"),h("pre",{class:"json-raw-content"},e.data)])]):h("div",{class:"message-json-raw"},[h("div",{class:"json-label"},"[JSON数据]"),h("details",{class:"json-raw-data"},[h("summary","查看详情"),h("pre",{class:"json-raw-content"},JSON.stringify(a.data,null,2))])])}}),Z=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=v(false),a=()=>{t.value=!t.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(d=>d.type==="message"),i=s.length;return{previews:s.slice(0,3).map(d=>{var w,O;const p=((w=d.attrs)==null?void 0:w.nickname)||"用户";let k="";if(d.children&&d.children.length>0){const P=d.children[0];P.type==="text"?(k=(((O=P.attrs)==null?void 0:O.content)||"").substring(0,20),k.length>15&&(k+="...")):P.type==="img"?k="[图片]":P.type==="video"?k="[视频]":k=`[${P.type}]`}return`${p}:${k}`}),messageCount:i}},o=(s,i)=>{var p,k,w;const c=((p=s.attrs)==null?void 0:p.nickname)||"用户",d=((k=s.attrs)==null?void 0:k.userId)||"unknown";return h("div",{key:i,class:"forwarded-message-item"},[h("div",{class:"forwarded-message-header"},[h("span",{class:"forwarded-message-nickname"},c),h("span",{class:"forwarded-message-userid"},`(${d})`)]),h("div",{class:"forwarded-message-content"},((w=s.children)==null?void 0:w.map((O,P)=>h(ke,{key:P,element:O,channelKey:e.channelKey})))||[])])};return()=>{var c;const{previews:s,messageCount:i}=n();return h("div",{class:"forward-message-container"},[h("div",{class:"forward-message-preview",onClick:a},[h("div",{class:"forward-message-title"},"聊天记录"),...s.map((d,p)=>h("div",{key:p,class:"forward-message-preview-item"},d)),h("div",{class:"forward-message-footer"},[h("span",{class:"forward-message-count"},`查看${i}条转发消息`),h("span",{class:"forward-message-toggle"},t.value?"▲":"▼")])]),t.value&&h("div",{class:"forward-message-expanded"},((c=e.element.children)==null?void 0:c.filter(d=>d.type==="message").map((d,p)=>o(d,p)))||[])])}}}),ke=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=a=>{var n,o,s,i,c,d;switch(a.type){case"text":return h("span",{class:"message-text-content"},a.attrs.content||"");case"forward":return h("span",{class:"message-text-content"},`[转发消息 ${a.attrs.id}]`||"[转发消息]");case"img":case"image":const p=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(Y,{src:p,alt:a.attrs.summary||"图片",filename:a.attrs.filename||a.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const k=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(Y,{src:k,alt:a.attrs.summary||"表情",filename:a.attrs.emojiId||a.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((o=(n=a.children[0])==null?void 0:n.attrs)!=null&&o.src){const w=((i=(s=a.children[0])==null?void 0:s.attrs)==null?void 0:i.src)||((d=(c=a.children[0])==null?void 0:c.attrs)==null?void 0:d.url);return h("div",{class:"message-image-container"},[h(Y,{src:w,alt:a.attrs.name||a.attrs.id||"[表情]",filename:a.attrs.name||a.attrs.id||"[表情]",channelKey:e.channelKey})])}else return h("span",{class:"message-text-content"},`[${a.attrs.name||a.attrs.id}]`||"[表情]");case"at":return h("span",{class:"message-at",title:a.attrs.name},`${a.attrs.name||a.attrs.id}`);case"json":return h("div",{class:"message-image-container"},[h(ye,{data:a.attrs.data||"",channelKey:e.channelKey})]);case"p":if(a.children&&a.children.length>0){const w=a.children.map((O,P)=>h(ke,{key:P,element:O,channelKey:e.channelKey}));return h("div",{class:"message-paragraph"},w)}else return h("div",{class:"message-paragraph"},"");case"figure":return h(Z,{element:a,channelKey:e.channelKey});default:return h("span",{class:"message-unknown",title:`未知消息类型: ${a.type}`},a.attrs.content||`[${a.type}]`)}};return()=>t(e.element)}}),u=v({bots:{},channels:{},messages:{}}),U=v({}),ie=v({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=v({}),be=100*1024*1024,ue=50;let pe=0,I=null;const Re="ChatImageCache",Oe=2,B="images",ae=50*1024*1024,K=100,de=500,Te=2*1024*1024,Fe=.8,We=60*1e3;let F=0,M=0,He=0;const g=v(""),_=v(""),Se=v(""),V=v([]),fe=v(false),Le=v(),q=v(false),W=v("bots"),H=v(null),ne=v(null),Be=v(false),he=v({show:false,text:""}),$=v(),me=v(),$e=v(false),se=v(false),ve=v(false),oe=v(""),A=v({x:0,y:0}),z=v({x:0,y:0}),_e=v({x:0,y:0}),we=v({x:0,y:0}),X=80,qe=v(0),N=v(null),Q=v(false),C=v(null),R=v({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),J=v(new Set),re=v(new Set),m=E(()=>Object.values(u.value.bots).sort((t,a)=>{const n=J.value.has(t.selfId),o=J.value.has(a.selfId);return n&&!o?-1:!n&&o?1:0})),l=E(()=>!g.value||!u.value.channels[g.value]?[]:Object.values(u.value.channels[g.value]).sort((t,a)=>{const n=re.value.has(`${g.value}:${t.id}`),o=re.value.has(`${g.value}:${a.id}`);return n&&!o?-1:!n&&o?1:0})),T=E(()=>{if(!g.value||!_.value)return[];const e=`${g.value}:${_.value}`,t=u.value.messages[e]||[];return t.filter(a=>a.quote),t}),Ue=E(()=>{var t;if(!g.value||!_.value)return"";const e=u.value.channels[g.value];return((t=e==null?void 0:e[_.value])==null?void 0:t.name)||""}),$t=E(()=>!g.value||!_.value?"":`${g.value}:${_.value}`),lt=E(()=>g.value&&_.value&&(Se.value.trim()||V.value.length>0)&&!ve.value),_t=E(()=>g.value&&_.value&&!ve.value),Dt=E(()=>{if(!q.value)return"";switch(W.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),Tt=E(()=>q.value?"输入消息...(屏幕左滑返回)":"输入消息..."),Lt=E(()=>({}));function ct(e){return e.size||0}function Xe(e){pe+=e,ie.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(pe/1024/1024).toFixed(2)}MB`)}function it(e=10){const t=Object.entries(b.value);if(t.length<=e)return;const a=t.slice(0,t.length-e);let n=0;a.forEach(([o,s])=>{URL.revokeObjectURL(s),delete b.value[o],n+=500*1024,ie.value.loggerinfo&&console.log("清理旧blob URL:",o)}),Xe(-n)}function Je(){Object.keys(b.value).length>ue&&it(Math.floor(ue*.7)),pe>be&&it(Math.floor(ue*.5))}function qt(e){g.value=e,_.value="",q.value&&(W.value="channels")}function Ut(e,t){if(e.preventDefault(),e.stopPropagation(),R.value.show&&R.value.type==="bot"&&R.value.targetId===t){G();return}Ge(e,"bot",t)}function Kt(e,t){if(e.preventDefault(),e.stopPropagation(),R.value.show&&R.value.type==="channel"&&R.value.targetId===t){G();return}Ge(e,"channel",t)}function Ge(e,t,a){let s=e.clientX,i=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),i+80>window.innerHeight&&(i=window.innerHeight-80-10),R.value={show:true,x:s,y:i,type:t,targetId:a,isSecondClick:false},document.addEventListener("click",G,{once:true}),document.addEventListener("keydown",Ze)}function G(){R.value.show=false,document.removeEventListener("click",G),document.removeEventListener("keydown",Ze)}function Ze(e){e.key==="Escape"&&R.value.show&&G()}async function Mt(e){J.value.has(e)?J.value.delete(e):J.value.add(e),await j("set-pinned-bots",{pinnedBots:Array.from(J.value)}),G()}async function At(e){const t=`${g.value}:${e}`;re.value.has(t)?re.value.delete(t):re.value.add(t),await j("set-pinned-channels",{pinnedChannels:Array.from(re.value)}),G()}async function zt(e){try{const t=await j("delete-bot-data",{selfId:e});if(t.success){const a=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of a)delete u.value.messages[n],delete U.value[n],await je(n);delete u.value.bots[e],delete u.value.channels[e],g.value===e&&(g.value="",_.value=""),L(t.message||"已删除该机器人的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除机器人数据失败:",t),L("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}G()}async function Pt(e){try{const t=await j("delete-channel-data",{selfId:g.value,channelId:e});if(t.success){const a=`${g.value}:${e}`;delete u.value.messages[a],delete U.value[a],u.value.channels[g.value]&&delete u.value.channels[g.value][e],await je(a),_.value===e&&(_.value=""),L(t.message||"已删除该频道的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除频道数据失败:",t),L("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}G()}async function jt(e){_.value=e,se.value=false,q.value&&(W.value="messages"),g.value&&await It(g.value,e),xe(()=>{ge(),!q.value&&me.value&&me.value.focus()})}async function Nt(){if(!lt.value)return;const e=Se.value.trim();if(!e&&V.value.length===0)return;ve.value=true;const t=[...V.value];try{const a=await j("send-message",{selfId:g.value,channelId:_.value,content:e,images:t.map(n=>({tempId:n.tempId,filename:n.filename}))});if(a.success){if(Se.value="",t.forEach(n=>{URL.revokeObjectURL(n.preview)}),V.value=[],fe.value=false,a.tempImageIds&&a.tempImageIds.length>0)try{await j("cleanup-temp-images",{tempImageIds:a.tempImageIds}),console.log("临时图片清理完成:",a.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",a.error),L("发送失败: "+a.error,"error")}catch(a){console.error("发送消息时出错:",a),L("发送失败: "+((a==null?void 0:a.message)||String(a)),"error")}finally{ve.value=false}}function Rt(){fe.value=!fe.value}function Ot(){Le.value&&Le.value.click(),fe.value=false}async function Ft(e){const t=e.target,a=t.files;if(!(!a||a.length===0)){for(const n of Array.from(a))await Qe(n);t.value=""}}async function Ht(e){var a;const t=(a=e.clipboardData)==null?void 0:a.items;if(t){for(const n of Array.from(t))if(n.type.startsWith("image/")){e.preventDefault();const o=n.getAsFile();o&&await Qe(o)}}}async function Qe(e){try{if(e.size>10*1024*1024){L("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){L("请选择图片文件","error");return}const t=await ut(e),a=URL.createObjectURL(e),n=await j("upload-image",{file:t,filename:e.name,mimeType:e.type});n.success?V.value.push({tempId:n.tempId,filename:e.name,preview:a,size:e.size}):(URL.revokeObjectURL(a),L("图片上传失败: "+n.error,"error"))}catch(t){console.error("上传图片失败:",t),L("图片上传失败: "+((t==null?void 0:t.message)||String(t)),"error")}}async function Xt(e){try{const t=V.value.findIndex(a=>a.tempId===e);if(t!==-1){const a=V.value[t];URL.revokeObjectURL(a.preview),V.value.splice(t,1)}await j("delete-temp-image",{tempId:e})}catch(t){console.error("删除图片失败:",t)}}function ut(e){return new Promise((t,a)=>{const n=new FileReader;n.onload=()=>t(n.result),n.onerror=a,n.readAsDataURL(e)})}function Ee(e){const t=e.target;t.closest(".input-actions")||(fe.value=false),t.closest(".context-menu")||G()}function Yt(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function Vt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function ge(){$.value&&($.value.scrollTop=$.value.scrollHeight,$e.value=false,se.value=false)}function Ke(){if($.value){const{scrollTop:e,scrollHeight:t,clientHeight:a}=$.value,o=t-(e+a)<=50,s=!o;$e.value=s,o?se.value=false:se.value=true}}function Me(){if(!$.value)return true;const{scrollTop:e,scrollHeight:t,clientHeight:a}=$.value;return t-(e+a)<=200}function dt(e){var n;if(!g.value)return 0;const t=`${g.value}:${e}`,a=U.value[t];return a!==void 0?a:((n=u.value.messages[t])==null?void 0:n.length)||0}function Wt(e,t){e.preventDefault(),e.stopPropagation();const a="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;qe.value=Date.now(),A.value={x:a,y:n},z.value={x:a,y:n},Q.value=false;const s=e.target.getBoundingClientRect();_e.value={x:s.left,y:s.top},we.value={x:a-s.left,y:n-s.top},N.value=window.setTimeout(()=>{if(qe.value>0){Q.value=true,oe.value=t;const i=e.target,c=i.cloneNode(true);c.classList.add("dragging-clone"),c.style.position="fixed",c.style.zIndex="1000",c.style.pointerEvents="none";const d=i.getBoundingClientRect();c.style.left=`${d.left}px`,c.style.top=`${d.top}px`,c.style.width=`${d.width}px`,c.style.height=`${d.height}px`,document.body.appendChild(c),C.value=c,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),ht(A.value.x,A.value.y)}},60),document.addEventListener("mousemove",Ae),document.addEventListener("mouseup",ze),document.addEventListener("touchmove",Ae),document.addEventListener("touchend",ze)}function Ae(e){if(!Q.value||!C.value)return;e.preventDefault();const t="touches"in e?e.touches[0].clientX:e.clientX,a="touches"in e?e.touches[0].clientY:e.clientY;z.value={x:t,y:a};const n=z.value.x-A.value.x,o=z.value.y-A.value.y,s=Math.sqrt(n*n+o*o),i=Math.max(.3,1-s/(X*2)),c=Math.max(.8,1-s/(X*3)),d=s>X,p=z.value.x-we.value.x,k=z.value.y-we.value.y;C.value.style.left=`${p}px`,C.value.style.top=`${k}px`,C.value.style.transform=`scale(${c})`,C.value.style.opacity=`${i}`,C.value.style.backgroundColor=d?"#f44336":"#2196f3",C.value.style.boxShadow=d?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",d?C.value.classList.add("will-delete"):C.value.classList.remove("will-delete")}function ze(e){if(N.value&&(clearTimeout(N.value),N.value=null),N.value&&(clearTimeout(N.value),N.value=null),!Q.value||!oe.value){Pe();return}const t=oe.value;if(Math.sqrt(Math.pow(z.value.x-A.value.x,2)+Math.pow(z.value.y-A.value.y,2))>X)ft(t),Pe();else if(C.value){C.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${t}"] .channel-message-count`);if(n){const o=n.getBoundingClientRect();C.value.style.left=`${o.left}px`,C.value.style.top=`${o.top}px`,C.value.style.transform="scale(1)",C.value.style.opacity="1",C.value.style.backgroundColor="#2196f3",C.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{Pe()},300)}else Pe()}function Pe(){N.value&&(clearTimeout(N.value),N.value=null),oe.value="",A.value={x:0,y:0},z.value={x:0,y:0},_e.value={x:0,y:0},qe.value=0,Q.value=false,document.removeEventListener("mousemove",Ae),document.removeEventListener("mouseup",ze),document.removeEventListener("touchmove",Ae),document.removeEventListener("touchend",ze),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),C.value&&C.value.parentNode&&(C.value.parentNode.removeChild(C.value),C.value=null),mt()}function Jt(e){return oe.value===e&&Q.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function Gt(e){if(oe.value!==e)return 0;const t=z.value.x-A.value.x,a=z.value.y-A.value.y;return Math.sqrt(t*t+a*a)}async function ft(e){if(g.value)try{const t=`${g.value}:${e}`,a=dt(e),n=ie.value.keepMessagesOnClear;if(n>0&&a<=n){L("当前消息还很少诶~ 无需清理","success");return}const o=await j("clear-channel-history",{selfId:g.value,channelId:e});if(o.success)if(o.clearedCount&&o.clearedCount>0){if(u.value.messages[t]){const i=[...u.value.messages[t]].sort((c,d)=>c.timestamp-d.timestamp);u.value.messages[t]=i.slice(-o.keptCount)}U.value[t]=o.keptCount,await je(t),L(`历史记录已清理,清理了 ${o.clearedCount} 条消息,保留最新 ${o.keptCount} 条`,"success")}else n===0?(u.value.messages[t]&&(u.value.messages[t]=[]),U.value[t]=0,await je(t),L("历史记录已清理,所有消息已删除","success")):L("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",o.error),L("清理失败: "+o.error,"error")}catch(t){console.error("清理历史记录时出错:",t),L("清理失败: "+((t==null?void 0:t.message)||String(t)),"error")}}function L(e,t="success"){const a=document.createElement("div");a.className=`notification ${t}`,a.textContent=e;let n="#4caf50";switch(t){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}a.style.cssText=`
2
2
  position: fixed;
3
3
  top: 20px;
4
4
  right: 20px;
@@ -20,8 +20,8 @@ import{defineComponent as Ce,ref as v,onMounted as nt,h,computed as Q,watch as k
20
20
  to { transform: translateX(100%); opacity: 0; }
21
21
  }
22
22
  `,document.head.appendChild(o),document.body.appendChild(a),setTimeout(()=>{a.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{a.parentNode&&a.parentNode.removeChild(a),o.parentNode&&o.parentNode.removeChild(o)},300)},3e3)}function ht(e,t){const a=document.createElement("div");a.className="drag-threshold-circle",a.style.cssText=`
23
- left: ${e-H}px;
24
- top: ${t-H}px;
25
- width: ${H*2}px;
26
- height: ${H*2}px;
27
- `,document.body.appendChild(a),window.dragThresholdCircle=a}function mt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function et(){try{if(!I)return false;const e=Date.now();if(e-He<We)return true;He=e;const t=await vt();O=t.totalSize,K=t.totalImages,console.log("数据库健康检查:",{大小:`${(O/1024/1024).toFixed(2)}MB / ${(te/1024/1024).toFixed(2)}MB`,图片数量:`${K} / ${ue}`,使用率:`${(O/te*100).toFixed(1)}%`});const a=O/te,n=K/ue;return(a>Fe||n>Fe)&&(console.warn("数据库使用率过高,开始自动清理"),await Ye()),(a>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Zt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function vt(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{const o=n.result||[];let s=0;const i={};o.forEach(c=>{s+=c.size||0,i[c.channelKey]=(i[c.channelKey]||0)+1}),e({totalSize:s,totalImages:o.length,channelStats:i})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function Ye(){try{console.log("开始自动清理...");const e=await gt();if(e.length===0)return;const t={};e.forEach(o=>{t[o.channelKey]||(t[o.channelKey]=[]),t[o.channelKey].push(o)});let a=0,n=0;for(const[o,s]of Object.entries(t))if(s.length>U){s.sort((c,d)=>c.timestamp-d.timestamp);const i=s.slice(0,s.length-U);for(const c of i)await tt(c.url),a++,n+=c.size||0,b.value[c.url]&&(URL.revokeObjectURL(b.value[c.url]),delete b.value[c.url])}console.log(`自动清理完成: 清理了 ${a} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),K-=a,O-=n}catch(e){console.error("自动清理失败:",e)}}async function Zt(){try{console.log("开始紧急清理...");const e=await gt();if(e.length===0)return;e.sort((s,i)=>i.timestamp-s.timestamp);const t=Math.floor(ue*.3),a=e.slice(t);let n=0,o=0;for(const s of a)await tt(s.url),n++,o+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(o/1024/1024).toFixed(2)}MB`),K=t,O-=o}catch(e){console.error("紧急清理失败:",e)}}async function gt(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Qt(){return new Promise(e=>{try{I&&(I.close(),I=null);const t=indexedDB.deleteDatabase(Re);t.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),O=0,K=0,e(true)},t.onerror=()=>{console.error("清理IndexedDB数据库失败:",t.error),e(false)},t.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(t){console.error("清理数据库时出错:",t),e(false)}})}async function Et(){try{return await yt()?(setTimeout(async()=>{const t=await vt();console.log("数据库初始状态:",{大小:`${(t.totalSize/1024/1024).toFixed(2)}MB`,图片数量:t.totalImages,频道分布:t.channelStats}),(t.totalSize>te*.9||t.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await Ye())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Qt(),await yt())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function yt(){return new Promise(e=>{try{const t=indexedDB.open(Re,Oe);t.onerror=()=>{console.error("IndexedDB打开失败:",t.error),e(false)},t.onsuccess=()=>{I=t.result,I.onerror=a=>{console.error("IndexedDB运行时错误:",a)},I.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),I==null||I.close(),I=null},e(true)},t.onupgradeneeded=a=>{const n=a.target.result;if(!n.objectStoreNames.contains(S)){const o=n.createObjectStore(S,{keyPath:"url"});o.createIndex("channelKey","channelKey",{unique:false}),o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},t.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(t){console.error("打开数据库时出错:",t),e(false)}})}async function ea(e){return I?new Promise((t,a)=>{const s=I.transaction([S],"readonly").objectStore(S).get(e);s.onsuccess=()=>{t(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),t(null)}}):null}async function pt(e){if(!I)return false;try{return e.size>Te?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Te/1024/1024).toFixed(2)}MB`),false):(await et(),O+e.size>te&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await Ye(),O+e.size>te)?(console.warn("清理后仍会超过限制,跳过此图片"),false):K>=ue&&(console.warn("图片数量已达上限,执行清理"),await Ye(),K>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(t=>{const o=I.transaction([S],"readwrite").objectStore(S).put(e);o.onsuccess=()=>{O+=e.size,K+=1,t(true)},o.onerror=()=>{console.error("保存图片到IndexedDB失败:",o.error),t(false)}}))}catch(t){return console.error("保存图片时出错:",t),false}}async function tt(e){return I?new Promise(t=>{const o=I.transaction([S],"readwrite").objectStore(S).delete(e);o.onsuccess=()=>{t(true)},o.onerror=()=>{console.error("从IndexedDB删除图片失败:",o.error),t(false)}}):false}async function ta(e){return I?new Promise(t=>{const s=I.transaction([S],"readonly").objectStore(S).index("channelKey").getAll(e);s.onsuccess=()=>{t(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),t([])}}):[]}async function Ve(e,t){const a=b.value[t];if(a)return a;const n=await ea(t);if(!n)return null;Je();const o=URL.createObjectURL(n.blob);return b.value[t]=o,Xe(ct(n.blob)),n.timestamp=Date.now(),await pt(n),o}async function we(e,t){try{const a=await Ve(e,t);if(a)return a;const n=await P("fetch-image",{url:t});if(!n.success)return console.error("获取图片失败:",n.error),null;const o=n.base64,s=n.contentType||"image/jpeg",i=atob(o),c=new Array(i.length);for(let z=0;z<i.length;z++)c[z]=i.charCodeAt(z);const d=new Uint8Array(c),p=new Blob([d],{type:s});if(p.size>Te)return console.warn(`图片过大,跳过缓存: ${(p.size/1024/1024).toFixed(2)}MB`),null;const k={url:t,blob:p,timestamp:Date.now(),size:p.size,channelKey:e};if(!await pt(k))return console.error("保存图片到IndexedDB失败"),null;Je();const R=URL.createObjectURL(p);return b.value[t]=R,Xe(ct(p)),R}catch(a){return console.error("缓存图片失败:",a),null}}async function je(e){try{const t=await ta(e);let a=0;for(const n of t)await tt(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],a+=n.size||0);a>0&&Xe(-a)}catch(t){console.error("清理频道图片缓存失败:",t)}}function aa(){const e=Object.keys(b.value).length;return{blobCount:e,estimatedMemoryUsage:ye,maxMemoryLimit:be,maxBlobLimit:ie,memoryUsagePercent:(ye/be*100).toFixed(1),blobUsagePercent:(e/ie*100).toFixed(1)}}async function na(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{const o=n.result||[],s=new Set;let i=0;o.forEach(c=>{s.add(c.channelKey),i+=c.size}),e({totalImages:o.length,totalSize:i,channels:s.size})},n.onerror=()=>{console.error("获取缓存统计失败:",n.error),e({totalImages:0,totalSize:0,channels:0})}}):{totalImages:0,totalSize:0,channels:0}}function wt(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),q.value[s]=d.length;const k=Me();Ie(()=>{setTimeout(()=>{k&&ve()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&we(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}function sa(e){const t=`${e.selfId}:${e.channelId}`;if(u.value.messages[t]||(u.value.messages[t]=[]),!u.value.messages[t].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},o=u.value.messages[t];let s=o.length;for(let c=o.length-1;c>=0;c--){if(o[c].timestamp<=e.timestamp){s=c+1;break}c===0&&(s=0)}o.splice(s,0,n),o.length>100&&(u.value.messages[t]=o.slice(-100)),q.value[t]=o.length;const i=Me();Ie(()=>{setTimeout(()=>{i&&ve()},10)})}u.value={...u.value}}function oa(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),q.value[s]=d.length;const k=Me();Ie(()=>{setTimeout(()=>{k&&ve()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&we(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}async function ra(){try{const e=await P("get-chat-data");if(e.success&&e.data){const t={};W.value=new Set(e.data.pinnedBots||[]),oe.value=new Set(e.data.pinnedChannels||[]);for(const[a,n]of Object.entries(e.data.messages||{})){const o=n.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));o.sort((s,i)=>s.timestamp-i.timestamp),t[a]=o}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:t},await la(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function la(){try{const e=await P("get-all-channel-message-counts");if(e.success&&e.counts){const t={};for(const[a,n]of Object.entries(e.counts))t[a]=n;q.value=t}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ca(){try{const e=await P("get-plugin-config");e.success&&e.config?ce.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function It(e,t){try{const a=await P("get-history-messages",{selfId:e,channelId:t});if(a.success&&a.messages){const n=`${e}:${t}`,o=a.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return o.sort((s,i)=>s.timestamp-i.timestamp),u.value.messages[n]=o,q.value[n]=o.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",a.error),false}catch(a){return console.error("获取历史消息时出错:",a),false}}function ia(e){if(!L.value||e.touches.length!==1)return;const t=e.touches[0];F.value={x:t.clientX,y:t.clientY,time:Date.now()},ae.value={x:t.clientX,y:t.clientY},Be.value=false}function ua(e){if(!L.value||!F.value||e.touches.length!==1)return;const t=e.touches[0];ae.value={x:t.clientX,y:t.clientY};const a=t.clientX-F.value.x,n=t.clientY-F.value.y;if(Math.abs(a)>Math.abs(n)&&Math.abs(a)>30){const o=a>0,s=V.value==="messages"||V.value==="channels";if(o&&s){Be.value=true;const i=Math.min(a,200),c=150;i>c?fe.value={show:true,text:"松开返回"}:fe.value={show:true,text:`滑动返回 ${Math.round(i/c*100)}%`},e.preventDefault()}else fe.value={show:false,text:""}}else fe.value={show:false,text:""}}function da(e){if(!L.value||!F.value)return;const a=Date.now()-F.value.time;if(ae.value){const n=ae.value.x-F.value.x,o=ae.value.y-F.value.y,s=n>150,i=Math.abs(n)>Math.abs(o),c=a<300&&n>80;(s&&i||c)&&fa()}F.value=null,ae.value=null,Be.value=false,fe.value={show:false,text:""}}function fa(){switch(V.value){case"messages":V.value="channels";break;case"channels":V.value="bots",g.value="",$.value="";break}}function at(){L.value=window.innerWidth<=768}function xt(){return!ne.value||Me()}const Ct=()=>{L.value&&B.value&&Ie(()=>{xt()&&ve()})},ha=()=>{L.value&&setTimeout(()=>{B.value&&xt()&&ve()},300)};return kt(D,(e,t)=>{t.length===0&&e.length>0&&Ie(()=>{ve()})}),nt(async()=>{at(),window.addEventListener("resize",at),window.visualViewport&&window.visualViewport.addEventListener("resize",Ct),document.addEventListener("click",Ee),await Et()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await et()},2e3),setInterval(async()=>{await et()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ca(),await ra();const t=rt("chat-message-event",wt),a=rt("bot-message-sent-event",sa),n=rt("chat-bot-message-event",oa);kt($,o=>{o&&Ie(()=>{B.value&&(B.value.removeEventListener("scroll",Ke),B.value.addEventListener("scroll",Ke),Ke()),!L.value&&he.value&&he.value.focus()})},{immediate:true}),setInterval(()=>{Je()},2*60*1e3),ma(()=>{window.removeEventListener("resize",at),window.visualViewport&&window.visualViewport.removeEventListener("resize",Ct),document.removeEventListener("click",Ee),t&&typeof t=="function"&&t(),a&&typeof a=="function"&&a(),n&&typeof n=="function"&&n(),B.value&&B.value.removeEventListener("scroll",Ke),Object.values(b.value).forEach(o=>{URL.revokeObjectURL(o)}),b.value={},I&&(I.close(),I=null)})}),{AvatarComponent:le,ImageComponent:X,JsonCardComponent:ge,ForwardMessageComponent:G,MessageElement:ke,chatData:u,channelMessageCounts:q,pluginConfig:ce,selectedBot:g,selectedChannel:$,inputMessage:Se,imageBlobUrls:b,pinnedBots:W,pinnedChannels:oe,uploadedImages:Y,showActionMenu:de,isMobile:L,mobileView:V,touchStart:F,touchCurrent:ae,isSwipeActive:Be,swipeIndicator:fe,messageHistory:B,messageInput:he,showScrollButton:$e,isUserScrolling:ne,isSending:me,draggingChannel:se,dragStartPos:M,dragCurrentPos:A,dragElementInitialPos:_e,dragOffset:pe,dragThreshold:H,isDragReady:Z,draggedBubbleElement:C,contextMenu:N,fileInput:Le,bots:m,currentChannels:l,currentMessages:D,currentChannelName:Ue,currentChannelKey:$t,canSendMessage:lt,canInputMessage:_t,mobileViewClass:Dt,inputPlaceholder:Tt,chatContainerStyle:Lt,selectBot:qt,selectChannel:jt,handleBotRightClick:Ut,handleChannelRightClick:Kt,showContextMenu:Ge,hideContextMenu:J,handleKeyDown:Ze,toggleBotPin:Mt,toggleChannelPin:At,deleteBotMessages:zt,deleteChannelMessages:Pt,sendMessage:Nt,toggleActionMenu:Rt,triggerImageUpload:Ot,handleFileSelect:Ft,handlePaste:Ht,uploadImage:Qe,removeImage:Xt,fileToBase64:ut,handleClickOutside:Ee,formatTime:Yt,getChannelTypeText:Vt,scrollToBottom:ve,checkScrollPosition:Ke,isNearBottom:Me,getChannelMessageCount:dt,startDrag:Wt,handleDragMove:Ae,handleDragEnd:ze,resetDragState:Pe,getDragStyle:Jt,getDragDistance:Gt,clearChannelHistory:ft,showNotification:T,createThresholdCircle:ht,removeThresholdCircle:mt,handleTouchStart:ia,handleTouchMove:ua,handleTouchEnd:da,handleInputFocus:ha,getCachedImageUrl:Ve,cacheImage:we,clearChannelImageCache:je,getMemoryStats:aa,getCacheStats:na,isFileUrl:ee,loadHistoryMessages:It,handleMessageEvent:wt}}const Ca={class:"bot-list"},ka={class:"bot-items"},ba=["onClick","onContextmenu"],Sa={class:"bot-avatar"},Ba={key:1,class:"avatar-placeholder"},$a={class:"bot-info"},_a={class:"bot-name"},Da={class:"bot-platform"},Ta={class:"channel-list"},La={key:0,class:"empty-state"},qa={key:1,class:"channel-items"},Ua=["data-channel-id","onClick","onContextmenu"],Ka={class:"channel-info"},Ma={class:"channel-name"},Aa={class:"channel-type"},za=["onMousedown","onTouchstart","title"],Pa={class:"message-area"},ja={class:"panel-header"},Na={key:0,class:"empty-state"},Ra={key:1,class:"message-content"},Oa={class:"message-avatar"},Fa={key:1,class:"avatar-placeholder"},Ha={class:"message-content-wrapper"},Xa={class:"message-header"},Ya={class:"message-username"},Va={class:"message-time"},Wa={key:0,class:"message-quote"},Ja={class:"quote-header"},Ga={class:"quote-avatar"},Za={key:1,class:"avatar-placeholder"},Qa={class:"quote-username"},Ea={class:"quote-time"},en={class:"quote-content"},tn={class:"message-text"},an={class:"message-input"},nn={key:0,class:"image-preview-container"},sn=["src","alt"],on=["onClick"],rn={class:"input-row"},ln={class:"input-actions"},cn=["placeholder","disabled"],un=["disabled"],dn=Ce({__name:"index",setup(ee){const le=xa(),{AvatarComponent:X,MessageElement:ge,selectedBot:G,selectedChannel:ke,inputMessage:u,pinnedBots:q,pinnedChannels:ce,uploadedImages:b,showActionMenu:be,swipeIndicator:ie,messageHistory:ye,messageInput:I,showScrollButton:Re,isSending:Oe,draggingChannel:S,dragThreshold:te,contextMenu:U,fileInput:ue,bots:Te,currentChannels:Fe,currentMessages:We,currentChannelName:O,currentChannelKey:K,canSendMessage:He,canInputMessage:g,mobileViewClass:$,inputPlaceholder:Se,chatContainerStyle:Y,selectBot:de,selectChannel:Le,handleBotRightClick:L,handleChannelRightClick:V,toggleBotPin:F,toggleChannelPin:ae,deleteBotMessages:Be,deleteChannelMessages:fe,sendMessage:B,toggleActionMenu:he,triggerImageUpload:$e,handleFileSelect:ne,handlePaste:me,removeImage:se,formatTime:M,getChannelTypeText:A,scrollToBottom:_e,getChannelMessageCount:pe,startDrag:H,getDragStyle:qe,getDragDistance:j,handleTouchStart:Z,handleTouchMove:C,handleTouchEnd:N,handleInputFocus:W}=le;return(oe,m)=>(y(),x("div",{class:re(["chat-container",r($)]),style:st(r(Y)),onTouchstart:m[15]||(m[15]=(...l)=>r(Z)&&r(Z)(...l)),onTouchmove:m[16]||(m[16]=(...l)=>r(C)&&r(C)(...l)),onTouchend:m[17]||(m[17]=(...l)=>r(N)&&r(N)(...l))},[f("div",Ca,[m[18]||(m[18]=f("div",{class:"panel-header"},[f("h3",null,"机器人")],-1)),f("div",ka,[(y(true),x(E,null,De(r(Te),l=>(y(),x("div",{key:l.selfId,class:re(["bot-item",{active:r(G)===l.selfId,pinned:r(q).has(l.selfId)}]),onClick:D=>r(de)(l.selfId),onContextmenu:D=>r(L)(D,l.selfId)},[f("div",Sa,[l.avatar?(y(),Ne(r(X),{key:0,src:l.avatar,alt:l.username,"channel-key":"bot-list"},null,8,["src","alt"])):(y(),x("div",Ba,_(l.username.charAt(0).toUpperCase()),1))]),f("div",$a,[f("div",_a,_(l.username),1),f("div",Da,_(l.platform),1)]),f("div",{class:re(["bot-status",l.status])},null,2)],42,ba))),128))])]),f("div",Ta,[m[19]||(m[19]=f("div",{class:"panel-header"},[f("h3",null,"频道")],-1)),r(G)?(y(),x("div",qa,[(y(true),x(E,null,De(r(Fe),l=>(y(),x("div",{key:l.id,class:re(["channel-item",{active:r(ke)===l.id,pinned:r(ce).has(`${r(G)}:${l.id}`)}]),"data-channel-id":l.id,onClick:D=>r(Le)(l.id),onContextmenu:D=>r(V)(D,l.id)},[f("div",Ka,[f("div",Ma,_(l.name),1),f("div",Aa,_(r(A)(l.type)),1)]),r(pe)(l.id)>0?(y(),x("div",{key:0,class:re(["channel-message-count draggable-bubble",{dragging:r(S)===l.id,"will-delete":r(S)===l.id&&r(j)(l.id)>r(te)}]),onMousedown:D=>r(H)(D,l.id),onTouchstart:D=>r(H)(D,l.id),style:st(r(qe)(l.id)),title:r(S)===l.id?r(j)(l.id)>r(te)?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},_(r(pe)(l.id)),47,za)):xe("",true)],42,Ua))),128))])):(y(),x("div",La," 请选择一个机器人 "))]),f("div",Pa,[f("div",ja,[f("h3",null,_(r(O)||"选择频道"),1)]),!r(G)||!r(ke)?(y(),x("div",Na," 请选择机器人和频道 ")):(y(),x("div",Ra,[f("div",{class:"message-history",ref_key:"messageHistory",ref:ye},[(y(true),x(E,null,De(r(We),l=>(y(),x("div",{key:l.id,class:re(["message-item",{"bot-message":l.isBot}])},[f("div",Oa,[l.avatar?(y(),Ne(r(X),{key:0,src:l.avatar,alt:l.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Fa,_(l.username.charAt(0).toUpperCase()),1))]),f("div",Ha,[f("div",Xa,[f("span",Ya,_(l.username),1),f("span",Va,_(r(M)(l.timestamp)),1)]),l.quote?(y(),x("div",Wa,[f("div",Ja,[f("div",Ga,[l.quote.user.avatar?(y(),Ne(r(X),{key:0,src:l.quote.user.avatar,alt:l.quote.user.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Za,_(l.quote.user.username.charAt(0).toUpperCase()),1))]),f("span",Qa,_(l.quote.user.username),1),f("span",Ea,_(r(M)(l.quote.timestamp)),1)]),f("div",en,[l.quote.elements&&l.quote.elements.length>0?(y(true),x(E,{key:0},De(l.quote.elements,(D,Ue)=>(y(),Ne(r(ge),{key:`quote-${Ue}`,element:D,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(E,{key:1},[ot(_(l.quote.content),1)],64))])])):xe("",true),f("div",tn,[l.elements&&l.elements.length>0?(y(true),x(E,{key:0},De(l.elements,(D,Ue)=>(y(),Ne(r(ge),{key:Ue,element:D,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(E,{key:1},[ot(_(l.content),1)],64))])])],2))),128))],512),bt(f("div",{class:"floating-scroll-button",onClick:m[0]||(m[0]=(...l)=>r(_e)&&r(_e)(...l))},m[20]||(m[20]=[f("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[va,r(Re)]]),f("div",an,[r(b).length>0?(y(),x("div",nn,[(y(true),x(E,null,De(r(b),l=>(y(),x("div",{key:l.tempId,class:"image-preview-item"},[f("img",{src:l.preview,alt:l.filename,class:"preview-image"},null,8,sn),f("button",{class:"remove-image-btn",onClick:D=>r(se)(l.tempId),title:"删除图片"},m[21]||(m[21]=[f("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})],-1)]),8,on)]))),128))])):xe("",true),f("div",rn,[f("div",ln,[f("button",{class:re(["add-button",{active:r(be)}]),onClick:m[1]||(m[1]=(...l)=>r(he)&&r(he)(...l)),title:"更多操作"},m[22]||(m[22]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[f("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),f("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),r(be)?(y(),x("div",{key:0,class:"action-menu",onClick:m[3]||(m[3]=St(()=>{},["stop"]))},[f("button",{class:"action-menu-item",onClick:m[2]||(m[2]=(...l)=>r($e)&&r($e)(...l))},m[23]||(m[23]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[f("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),f("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),f("polyline",{points:"21,15 16,10 5,21"})],-1),ot(" 上传图片 ",-1)]))])):xe("",true)]),bt(f("input",{"onUpdate:modelValue":m[4]||(m[4]=l=>ya(u)?u.value=l:null),type:"text",placeholder:r(Se),onKeyup:m[5]||(m[5]=ga((...l)=>r(B)&&r(B)(...l),["enter"])),disabled:!r(g),ref_key:"messageInput",ref:I,onPaste:m[6]||(m[6]=(...l)=>r(me)&&r(me)(...l)),onFocus:m[7]||(m[7]=(...l)=>r(W)&&r(W)(...l))},null,40,cn),[[pa,r(u)]]),f("button",{onClick:m[8]||(m[8]=(...l)=>r(B)&&r(B)(...l)),disabled:!r(He),class:re({"is-sending":r(Oe)})},_(r(Oe)?"发送中...":"发送"),11,un)]),f("input",{type:"file",ref_key:"fileInput",ref:ue,onChange:m[9]||(m[9]=(...l)=>r(ne)&&r(ne)(...l)),accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),r(U).show?(y(),x("div",{key:0,class:"context-menu",style:st({left:r(U).x+"px",top:r(U).y+"px"}),onClick:m[14]||(m[14]=St(()=>{},["stop"]))},[r(U).type==="bot"?(y(),x(E,{key:0},[f("div",{class:"context-menu-item",onClick:m[10]||(m[10]=l=>r(F)(r(U).targetId))},_(r(q).has(r(U).targetId)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[11]||(m[11]=l=>r(Be)(r(U).targetId))}," 彻底删除此机器人所有数据 ")],64)):xe("",true),r(U).type==="channel"?(y(),x(E,{key:1},[f("div",{class:"context-menu-item",onClick:m[12]||(m[12]=l=>r(ae)(r(U).targetId))},_(r(ce).has(`${r(G)}:${r(U).targetId}`)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[13]||(m[13]=l=>r(fe)(r(U).targetId))}," 彻底删除此频道所有数据 ")],64)):xe("",true)],4)):xe("",true),f("div",{class:re(["swipe-indicator",{show:r(ie).show}])},_(r(ie).text),3)],38))}}),Bt=(ee,le)=>{const X=ee.__vccOpts||ee;for(const[ge,G]of le)X[ge]=G;return X},fn=Bt(dn,[["__scopeId","data-v-de93bb69"]]),hn={},mn={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function vn(ee,le){return y(),x("svg",mn,le[0]||(le[0]=[f("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M17 3.33782C15.5291 2.48697 13.8214 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22C17.5228 22 22 17.5228 22 12C22 10.1786 21.513 8.47087 20.6622 7",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)]))}const gn=Bt(hn,[["render",vn]]);Ia.register("activity:chat",gn);const wn=ee=>{ee.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Ce({setup(){return()=>h(wa("k-layout"),{},{default:()=>h(fn)})}})})};export{wn as default};
23
+ left: ${e-X}px;
24
+ top: ${t-X}px;
25
+ width: ${X*2}px;
26
+ height: ${X*2}px;
27
+ `,document.body.appendChild(a),window.dragThresholdCircle=a}function mt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function et(){try{if(!I)return false;const e=Date.now();if(e-He<We)return true;He=e;const t=await vt();F=t.totalSize,M=t.totalImages,console.log("数据库健康检查:",{大小:`${(F/1024/1024).toFixed(2)}MB / ${(ae/1024/1024).toFixed(2)}MB`,图片数量:`${M} / ${de}`,使用率:`${(F/ae*100).toFixed(1)}%`});const a=F/ae,n=M/de;return(a>Fe||n>Fe)&&(console.warn("数据库使用率过高,开始自动清理"),await Ye()),(a>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Zt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function vt(){return I?new Promise(e=>{const n=I.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{const o=n.result||[];let s=0;const i={};o.forEach(c=>{s+=c.size||0,i[c.channelKey]=(i[c.channelKey]||0)+1}),e({totalSize:s,totalImages:o.length,channelStats:i})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function Ye(){try{console.log("开始自动清理...");const e=await gt();if(e.length===0)return;const t={};e.forEach(o=>{t[o.channelKey]||(t[o.channelKey]=[]),t[o.channelKey].push(o)});let a=0,n=0;for(const[o,s]of Object.entries(t))if(s.length>K){s.sort((c,d)=>c.timestamp-d.timestamp);const i=s.slice(0,s.length-K);for(const c of i)await tt(c.url),a++,n+=c.size||0,b.value[c.url]&&(URL.revokeObjectURL(b.value[c.url]),delete b.value[c.url])}console.log(`自动清理完成: 清理了 ${a} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),M-=a,F-=n}catch(e){console.error("自动清理失败:",e)}}async function Zt(){try{console.log("开始紧急清理...");const e=await gt();if(e.length===0)return;e.sort((s,i)=>i.timestamp-s.timestamp);const t=Math.floor(de*.3),a=e.slice(t);let n=0,o=0;for(const s of a)await tt(s.url),n++,o+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(o/1024/1024).toFixed(2)}MB`),M=t,F-=o}catch(e){console.error("紧急清理失败:",e)}}async function gt(){return I?new Promise(e=>{const n=I.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Qt(){return new Promise(e=>{try{I&&(I.close(),I=null);const t=indexedDB.deleteDatabase(Re);t.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),F=0,M=0,e(true)},t.onerror=()=>{console.error("清理IndexedDB数据库失败:",t.error),e(false)},t.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(t){console.error("清理数据库时出错:",t),e(false)}})}async function Et(){try{return await yt()?(setTimeout(async()=>{const t=await vt();console.log("数据库初始状态:",{大小:`${(t.totalSize/1024/1024).toFixed(2)}MB`,图片数量:t.totalImages,频道分布:t.channelStats}),(t.totalSize>ae*.9||t.totalImages>de*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await Ye())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Qt(),await yt())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function yt(){return new Promise(e=>{try{const t=indexedDB.open(Re,Oe);t.onerror=()=>{console.error("IndexedDB打开失败:",t.error),e(false)},t.onsuccess=()=>{I=t.result,I.onerror=a=>{console.error("IndexedDB运行时错误:",a)},I.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),I==null||I.close(),I=null},e(true)},t.onupgradeneeded=a=>{const n=a.target.result;if(!n.objectStoreNames.contains(B)){const o=n.createObjectStore(B,{keyPath:"url"});o.createIndex("channelKey","channelKey",{unique:false}),o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},t.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(t){console.error("打开数据库时出错:",t),e(false)}})}async function ea(e){return I?new Promise((t,a)=>{const s=I.transaction([B],"readonly").objectStore(B).get(e);s.onsuccess=()=>{t(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),t(null)}}):null}async function pt(e){if(!I)return false;try{return e.size>Te?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Te/1024/1024).toFixed(2)}MB`),false):(await et(),F+e.size>ae&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await Ye(),F+e.size>ae)?(console.warn("清理后仍会超过限制,跳过此图片"),false):M>=de&&(console.warn("图片数量已达上限,执行清理"),await Ye(),M>=de)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(t=>{const o=I.transaction([B],"readwrite").objectStore(B).put(e);o.onsuccess=()=>{F+=e.size,M+=1,t(true)},o.onerror=()=>{console.error("保存图片到IndexedDB失败:",o.error),t(false)}}))}catch(t){return console.error("保存图片时出错:",t),false}}async function tt(e){return I?new Promise(t=>{const o=I.transaction([B],"readwrite").objectStore(B).delete(e);o.onsuccess=()=>{t(true)},o.onerror=()=>{console.error("从IndexedDB删除图片失败:",o.error),t(false)}}):false}async function ta(e){return I?new Promise(t=>{const s=I.transaction([B],"readonly").objectStore(B).index("channelKey").getAll(e);s.onsuccess=()=>{t(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),t([])}}):[]}async function Ve(e,t){const a=b.value[t];if(a)return a;const n=await ea(t);if(!n)return null;Je();const o=URL.createObjectURL(n.blob);return b.value[t]=o,Xe(ct(n.blob)),n.timestamp=Date.now(),await pt(n),o}async function Ie(e,t){try{const a=await Ve(e,t);if(a)return a;const n=await j("fetch-image",{url:t});if(!n.success)return console.error("获取图片失败:",n.error),null;const o=n.base64,s=n.contentType||"image/jpeg",i=atob(o),c=new Array(i.length);for(let P=0;P<i.length;P++)c[P]=i.charCodeAt(P);const d=new Uint8Array(c),p=new Blob([d],{type:s});if(p.size>Te)return console.warn(`图片过大,跳过缓存: ${(p.size/1024/1024).toFixed(2)}MB`),null;const k={url:t,blob:p,timestamp:Date.now(),size:p.size,channelKey:e};if(!await pt(k))return console.error("保存图片到IndexedDB失败"),null;Je();const O=URL.createObjectURL(p);return b.value[t]=O,Xe(ct(p)),O}catch(a){return console.error("缓存图片失败:",a),null}}async function je(e){try{const t=await ta(e);let a=0;for(const n of t)await tt(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],a+=n.size||0);a>0&&Xe(-a)}catch(t){console.error("清理频道图片缓存失败:",t)}}function aa(){const e=Object.keys(b.value).length;return{blobCount:e,estimatedMemoryUsage:pe,maxMemoryLimit:be,maxBlobLimit:ue,memoryUsagePercent:(pe/be*100).toFixed(1),blobUsagePercent:(e/ue*100).toFixed(1)}}async function na(){return I?new Promise(e=>{const n=I.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{const o=n.result||[],s=new Set;let i=0;o.forEach(c=>{s.add(c.channelKey),i+=c.size}),e({totalImages:o.length,totalSize:i,channels:s.size})},n.onerror=()=>{console.error("获取缓存统计失败:",n.error),e({totalImages:0,totalSize:0,channels:0})}}):{totalImages:0,totalSize:0,channels:0}}function wt(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.isDirect?`私信 ${e.channelId}`:`${e.guildName||e.channelId} (${e.channelId})`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,channelId:e.channelId,guildName:e.guildName||"群聊",isDirect:e.isDirect}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const k=Me();xe(()=>{setTimeout(()=>{k&&ge()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&Ie(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}function sa(e){const t=`${e.selfId}:${e.channelId}`;if(u.value.messages[t]||(u.value.messages[t]=[]),!u.value.messages[t].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},o=u.value.messages[t];let s=o.length;for(let c=o.length-1;c>=0;c--){if(o[c].timestamp<=e.timestamp){s=c+1;break}c===0&&(s=0)}o.splice(s,0,n),o.length>100&&(u.value.messages[t]=o.slice(-100)),U.value[t]=o.length;const i=Me();xe(()=>{setTimeout(()=>{i&&ge()},10)})}u.value={...u.value}}function oa(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.isDirect?`私信 ${e.channelId}`:`${e.guildName||e.channelId} (${e.channelId})`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,channelId:e.channelId,guildName:e.guildName||"群聊",isDirect:e.isDirect}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const k=Me();xe(()=>{setTimeout(()=>{k&&ge()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&Ie(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}async function ra(){try{const e=await j("get-chat-data");if(e.success&&e.data){const t={};J.value=new Set(e.data.pinnedBots||[]),re.value=new Set(e.data.pinnedChannels||[]);for(const[a,n]of Object.entries(e.data.messages||{})){const o=n.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));o.sort((s,i)=>s.timestamp-i.timestamp),t[a]=o}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:t},await la(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function la(){try{const e=await j("get-all-channel-message-counts");if(e.success&&e.counts){const t={};for(const[a,n]of Object.entries(e.counts))t[a]=n;U.value=t}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ca(){try{const e=await j("get-plugin-config");e.success&&e.config?ie.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function It(e,t){try{const a=await j("get-history-messages",{selfId:e,channelId:t});if(a.success&&a.messages){const n=`${e}:${t}`,o=a.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return o.sort((s,i)=>s.timestamp-i.timestamp),u.value.messages[n]=o,U.value[n]=o.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",a.error),false}catch(a){return console.error("获取历史消息时出错:",a),false}}function ia(e){if(!q.value||e.touches.length!==1)return;const t=e.touches[0];H.value={x:t.clientX,y:t.clientY,time:Date.now()},ne.value={x:t.clientX,y:t.clientY},Be.value=false}function ua(e){if(!q.value||!H.value||e.touches.length!==1)return;const t=e.touches[0];ne.value={x:t.clientX,y:t.clientY};const a=t.clientX-H.value.x,n=t.clientY-H.value.y;if(Math.abs(a)>Math.abs(n)&&Math.abs(a)>30){const o=a>0,s=W.value==="messages"||W.value==="channels";if(o&&s){Be.value=true;const i=Math.min(a,200),c=150;i>c?he.value={show:true,text:"松开返回"}:he.value={show:true,text:`滑动返回 ${Math.round(i/c*100)}%`},e.preventDefault()}else he.value={show:false,text:""}}else he.value={show:false,text:""}}function da(e){if(!q.value||!H.value)return;const a=Date.now()-H.value.time;if(ne.value){const n=ne.value.x-H.value.x,o=ne.value.y-H.value.y,s=n>150,i=Math.abs(n)>Math.abs(o),c=a<300&&n>80;(s&&i||c)&&fa()}H.value=null,ne.value=null,Be.value=false,he.value={show:false,text:""}}function fa(){switch(W.value){case"messages":W.value="channels";break;case"channels":W.value="bots",g.value="",_.value="";break}}function at(){q.value=window.innerWidth<=768}function xt(){return!se.value||Me()}const Ct=()=>{q.value&&$.value&&xe(()=>{xt()&&ge()})},ha=()=>{q.value&&setTimeout(()=>{$.value&&xt()&&ge()},300)};return kt(T,(e,t)=>{t.length===0&&e.length>0&&xe(()=>{ge()})}),nt(async()=>{at(),window.addEventListener("resize",at),window.visualViewport&&window.visualViewport.addEventListener("resize",Ct),document.addEventListener("click",Ee),await Et()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await et()},2e3),setInterval(async()=>{await et()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ca(),await ra();const t=rt("chat-message-event",wt),a=rt("bot-message-sent-event",sa),n=rt("chat-bot-message-event",oa);kt(_,o=>{o&&xe(()=>{$.value&&($.value.removeEventListener("scroll",Ke),$.value.addEventListener("scroll",Ke),Ke()),!q.value&&me.value&&me.value.focus()})},{immediate:true}),setInterval(()=>{Je()},2*60*1e3),ma(()=>{window.removeEventListener("resize",at),window.visualViewport&&window.visualViewport.removeEventListener("resize",Ct),document.removeEventListener("click",Ee),t&&typeof t=="function"&&t(),a&&typeof a=="function"&&a(),n&&typeof n=="function"&&n(),$.value&&$.value.removeEventListener("scroll",Ke),Object.values(b.value).forEach(o=>{URL.revokeObjectURL(o)}),b.value={},I&&(I.close(),I=null)})}),{AvatarComponent:ce,ImageComponent:Y,JsonCardComponent:ye,ForwardMessageComponent:Z,MessageElement:ke,chatData:u,channelMessageCounts:U,pluginConfig:ie,selectedBot:g,selectedChannel:_,inputMessage:Se,imageBlobUrls:b,pinnedBots:J,pinnedChannels:re,uploadedImages:V,showActionMenu:fe,isMobile:q,mobileView:W,touchStart:H,touchCurrent:ne,isSwipeActive:Be,swipeIndicator:he,messageHistory:$,messageInput:me,showScrollButton:$e,isUserScrolling:se,isSending:ve,draggingChannel:oe,dragStartPos:A,dragCurrentPos:z,dragElementInitialPos:_e,dragOffset:we,dragThreshold:X,isDragReady:Q,draggedBubbleElement:C,contextMenu:R,fileInput:Le,bots:m,currentChannels:l,currentMessages:T,currentChannelName:Ue,currentChannelKey:$t,canSendMessage:lt,canInputMessage:_t,mobileViewClass:Dt,inputPlaceholder:Tt,chatContainerStyle:Lt,selectBot:qt,selectChannel:jt,handleBotRightClick:Ut,handleChannelRightClick:Kt,showContextMenu:Ge,hideContextMenu:G,handleKeyDown:Ze,toggleBotPin:Mt,toggleChannelPin:At,deleteBotMessages:zt,deleteChannelMessages:Pt,sendMessage:Nt,toggleActionMenu:Rt,triggerImageUpload:Ot,handleFileSelect:Ft,handlePaste:Ht,uploadImage:Qe,removeImage:Xt,fileToBase64:ut,handleClickOutside:Ee,formatTime:Yt,getChannelTypeText:Vt,scrollToBottom:ge,checkScrollPosition:Ke,isNearBottom:Me,getChannelMessageCount:dt,startDrag:Wt,handleDragMove:Ae,handleDragEnd:ze,resetDragState:Pe,getDragStyle:Jt,getDragDistance:Gt,clearChannelHistory:ft,showNotification:L,createThresholdCircle:ht,removeThresholdCircle:mt,handleTouchStart:ia,handleTouchMove:ua,handleTouchEnd:da,handleInputFocus:ha,getCachedImageUrl:Ve,cacheImage:Ie,clearChannelImageCache:je,getMemoryStats:aa,getCacheStats:na,isFileUrl:te,loadHistoryMessages:It,handleMessageEvent:wt}}const Ca={class:"bot-list"},ka={class:"bot-items"},ba=["onClick","onContextmenu"],Sa={class:"bot-avatar"},Ba={key:1,class:"avatar-placeholder"},$a={class:"bot-info"},_a={class:"bot-name"},Da={class:"bot-platform"},Ta={class:"channel-list"},La={key:0,class:"empty-state"},qa={key:1,class:"channel-items"},Ua=["data-channel-id","onClick","onContextmenu"],Ka={class:"channel-info"},Ma={class:"channel-name"},Aa={class:"channel-type"},za=["onMousedown","onTouchstart","title"],Pa={class:"message-area"},ja={class:"panel-header"},Na={key:0,class:"empty-state"},Ra={key:1,class:"message-content"},Oa={class:"message-avatar"},Fa={key:1,class:"avatar-placeholder"},Ha={class:"message-content-wrapper"},Xa={class:"message-header"},Ya={class:"message-username"},Va={class:"message-time"},Wa={key:0,class:"message-quote"},Ja={class:"quote-header"},Ga={class:"quote-avatar"},Za={key:1,class:"avatar-placeholder"},Qa={class:"quote-username"},Ea={class:"quote-time"},en={class:"quote-content"},tn={class:"message-text"},an={class:"message-input"},nn={key:0,class:"image-preview-container"},sn=["src","alt"],on=["onClick"],rn={class:"input-row"},ln={class:"input-actions"},cn=["placeholder","disabled"],un=["disabled"],dn=Ce({__name:"index",setup(te){const ce=xa(),{AvatarComponent:Y,MessageElement:ye,selectedBot:Z,selectedChannel:ke,inputMessage:u,pinnedBots:U,pinnedChannels:ie,uploadedImages:b,showActionMenu:be,swipeIndicator:ue,messageHistory:pe,messageInput:I,showScrollButton:Re,isSending:Oe,draggingChannel:B,dragThreshold:ae,contextMenu:K,fileInput:de,bots:Te,currentChannels:Fe,currentMessages:We,currentChannelName:F,currentChannelKey:M,canSendMessage:He,canInputMessage:g,mobileViewClass:_,inputPlaceholder:Se,chatContainerStyle:V,selectBot:fe,selectChannel:Le,handleBotRightClick:q,handleChannelRightClick:W,toggleBotPin:H,toggleChannelPin:ne,deleteBotMessages:Be,deleteChannelMessages:he,sendMessage:$,toggleActionMenu:me,triggerImageUpload:$e,handleFileSelect:se,handlePaste:ve,removeImage:oe,formatTime:A,getChannelTypeText:z,scrollToBottom:_e,getChannelMessageCount:we,startDrag:X,getDragStyle:qe,getDragDistance:N,handleTouchStart:Q,handleTouchMove:C,handleTouchEnd:R,handleInputFocus:J}=ce;return(re,m)=>(y(),x("div",{class:le(["chat-container",r(_)]),style:st(r(V)),onTouchstart:m[15]||(m[15]=(...l)=>r(Q)&&r(Q)(...l)),onTouchmove:m[16]||(m[16]=(...l)=>r(C)&&r(C)(...l)),onTouchend:m[17]||(m[17]=(...l)=>r(R)&&r(R)(...l))},[S(" 左侧机器人列表 "),f("div",Ca,[m[18]||(m[18]=f("div",{class:"panel-header"},[f("h3",null,"机器人")],-1)),f("div",ka,[(y(true),x(ee,null,De(r(Te),l=>(y(),x("div",{key:l.selfId,class:le(["bot-item",{active:r(Z)===l.selfId,pinned:r(U).has(l.selfId)}]),onClick:T=>r(fe)(l.selfId),onContextmenu:T=>r(q)(T,l.selfId)},[f("div",Sa,[l.avatar?(y(),Ne(r(Y),{key:0,src:l.avatar,alt:l.username,"channel-key":"bot-list"},null,8,["src","alt"])):(y(),x("div",Ba,D(l.username.charAt(0).toUpperCase()),1))]),f("div",$a,[f("div",_a,D(l.username),1),f("div",Da,D(l.platform),1)]),f("div",{class:le(["bot-status",l.status])},null,2)],42,ba))),128))])]),S(" 中间频道列表 "),f("div",Ta,[m[19]||(m[19]=f("div",{class:"panel-header"},[f("h3",null,"频道")],-1)),r(Z)?(y(),x("div",qa,[(y(true),x(ee,null,De(r(Fe),l=>(y(),x("div",{key:l.id,class:le(["channel-item",{active:r(ke)===l.id,pinned:r(ie).has(`${r(Z)}:${l.id}`)}]),"data-channel-id":l.id,onClick:T=>r(Le)(l.id),onContextmenu:T=>r(W)(T,l.id)},[f("div",Ka,[f("div",Ma,D(l.name),1),f("div",Aa,D(r(z)(l.type)),1)]),r(we)(l.id)>0?(y(),x("div",{key:0,class:le(["channel-message-count draggable-bubble",{dragging:r(B)===l.id,"will-delete":r(B)===l.id&&r(N)(l.id)>r(ae)}]),onMousedown:T=>r(X)(T,l.id),onTouchstart:T=>r(X)(T,l.id),style:st(r(qe)(l.id)),title:r(B)===l.id?r(N)(l.id)>r(ae)?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},D(r(we)(l.id)),47,za)):S("v-if",true)],42,Ua))),128))])):(y(),x("div",La," 请选择一个机器人 "))]),S(" 右侧消息区域 "),f("div",Pa,[f("div",ja,[f("h3",null,D(r(F)||"选择频道"),1)]),!r(Z)||!r(ke)?(y(),x("div",Na," 请选择机器人和频道 ")):(y(),x("div",Ra,[S(" 消息历史 "),f("div",{class:"message-history",ref_key:"messageHistory",ref:pe},[(y(true),x(ee,null,De(r(We),l=>(y(),x("div",{key:l.id,class:le(["message-item",{"bot-message":l.isBot}])},[f("div",Oa,[l.avatar?(y(),Ne(r(Y),{key:0,src:l.avatar,alt:l.username,"channel-key":r(M)},null,8,["src","alt","channel-key"])):(y(),x("div",Fa,D(l.username.charAt(0).toUpperCase()),1))]),f("div",Ha,[f("div",Xa,[f("span",Ya,D(l.username),1),f("span",Va,D(r(A)(l.timestamp)),1)]),S(" 引用消息显示 "),l.quote?(y(),x("div",Wa,[f("div",Ja,[f("div",Ga,[l.quote.user.avatar?(y(),Ne(r(Y),{key:0,src:l.quote.user.avatar,alt:l.quote.user.username,"channel-key":r(M)},null,8,["src","alt","channel-key"])):(y(),x("div",Za,D(l.quote.user.username.charAt(0).toUpperCase()),1))]),f("span",Qa,D(l.quote.user.username),1),f("span",Ea,D(r(A)(l.quote.timestamp)),1)]),f("div",en,[l.quote.elements&&l.quote.elements.length>0?(y(true),x(ee,{key:0},De(l.quote.elements,(T,Ue)=>(y(),Ne(r(ye),{key:`quote-${Ue}`,element:T,"channel-key":r(M)},null,8,["element","channel-key"]))),128)):(y(),x(ee,{key:1},[ot(D(l.quote.content),1)],64))])])):S("v-if",true),f("div",tn,[l.elements&&l.elements.length>0?(y(true),x(ee,{key:0},De(l.elements,(T,Ue)=>(y(),Ne(r(ye),{key:Ue,element:T,"channel-key":r(M)},null,8,["element","channel-key"]))),128)):(y(),x(ee,{key:1},[ot(D(l.content),1)],64))])])],2))),128))],512),S(" 悬浮的滚动到底部按钮 "),bt(f("div",{class:"floating-scroll-button",onClick:m[0]||(m[0]=(...l)=>r(_e)&&r(_e)(...l))},m[20]||(m[20]=[f("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[va,r(Re)]]),S(" 输入框 "),f("div",an,[S(" 图片预览区域 "),r(b).length>0?(y(),x("div",nn,[(y(true),x(ee,null,De(r(b),l=>(y(),x("div",{key:l.tempId,class:"image-preview-item"},[f("img",{src:l.preview,alt:l.filename,class:"preview-image"},null,8,sn),f("button",{class:"remove-image-btn",onClick:T=>r(oe)(l.tempId),title:"删除图片"},m[21]||(m[21]=[f("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})],-1)]),8,on)]))),128))])):S("v-if",true),f("div",rn,[S(" 加号按钮 "),f("div",ln,[f("button",{class:le(["add-button",{active:r(be)}]),onClick:m[1]||(m[1]=(...l)=>r(me)&&r(me)(...l)),title:"更多操作"},m[22]||(m[22]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[f("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),f("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),S(" 操作菜单 "),r(be)?(y(),x("div",{key:0,class:"action-menu",onClick:m[3]||(m[3]=St(()=>{},["stop"]))},[f("button",{class:"action-menu-item",onClick:m[2]||(m[2]=(...l)=>r($e)&&r($e)(...l))},m[23]||(m[23]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[f("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),f("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),f("polyline",{points:"21,15 16,10 5,21"})],-1),ot(" 上传图片 ",-1)]))])):S("v-if",true)]),bt(f("input",{"onUpdate:modelValue":m[4]||(m[4]=l=>ya(u)?u.value=l:null),type:"text",placeholder:r(Se),onKeyup:m[5]||(m[5]=ga((...l)=>r($)&&r($)(...l),["enter"])),disabled:!r(g),ref_key:"messageInput",ref:I,onPaste:m[6]||(m[6]=(...l)=>r(ve)&&r(ve)(...l)),onFocus:m[7]||(m[7]=(...l)=>r(J)&&r(J)(...l))},null,40,cn),[[pa,r(u)]]),f("button",{onClick:m[8]||(m[8]=(...l)=>r($)&&r($)(...l)),disabled:!r(He),class:le({"is-sending":r(Oe)})},D(r(Oe)?"发送中...":"发送"),11,un)]),S(" 隐藏的文件输入 "),f("input",{type:"file",ref_key:"fileInput",ref:de,onChange:m[9]||(m[9]=(...l)=>r(se)&&r(se)(...l)),accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),S(" 右键菜单 "),r(K).show?(y(),x("div",{key:0,class:"context-menu",style:st({left:r(K).x+"px",top:r(K).y+"px"}),onClick:m[14]||(m[14]=St(()=>{},["stop"]))},[S(" 机器人右键菜单 "),r(K).type==="bot"?(y(),x(ee,{key:0},[f("div",{class:"context-menu-item",onClick:m[10]||(m[10]=l=>r(H)(r(K).targetId))},D(r(U).has(r(K).targetId)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[11]||(m[11]=l=>r(Be)(r(K).targetId))}," 彻底删除此机器人所有数据 ")],64)):S("v-if",true),S(" 频道右键菜单 "),r(K).type==="channel"?(y(),x(ee,{key:1},[f("div",{class:"context-menu-item",onClick:m[12]||(m[12]=l=>r(ne)(r(K).targetId))},D(r(ie).has(`${r(Z)}:${r(K).targetId}`)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[13]||(m[13]=l=>r(he)(r(K).targetId))}," 彻底删除此频道所有数据 ")],64)):S("v-if",true)],4)):S("v-if",true),S(" 滑动指示器 "),f("div",{class:le(["swipe-indicator",{show:r(ue).show}])},D(r(ue).text),3)],38))}}),Bt=(te,ce)=>{const Y=te.__vccOpts||te;for(const[ye,Z]of ce)Y[ye]=Z;return Y},fn=Bt(dn,[["__scopeId","data-v-de93bb69"]]),hn={},mn={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function vn(te,ce){return y(),x("svg",mn,ce[0]||(ce[0]=[f("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M17 3.33782C15.5291 2.48697 13.8214 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22C17.5228 22 22 17.5228 22 12C22 10.1786 21.513 8.47087 20.6622 7",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)]))}const gn=Bt(hn,[["render",vn]]);Ia.register("activity:chat",gn);const wn=te=>{te.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Ce({setup(){return()=>h(wa("k-layout"),{},{default:()=>h(fn)})}})})};export{wn as default};
@@ -0,0 +1,19 @@
1
+ import { FileManager } from './file-manager';
2
+ import { MessageHandler } from './message-handler';
3
+ import { Context } from 'koishi';
4
+ import { Config } from './config';
5
+ export declare class ApiHandlers {
6
+ private ctx;
7
+ private config;
8
+ private fileManager;
9
+ private messageHandler;
10
+ private logger;
11
+ constructor(ctx: Context, config: Config, fileManager: FileManager, messageHandler: MessageHandler);
12
+ registerApiHandlers(): void;
13
+ private isFileUrl;
14
+ private createFileUrl;
15
+ private handleLocalFileRequest;
16
+ private setupTempFileCleanup;
17
+ private cleanupTempImagesByCount;
18
+ private logInfo;
19
+ }
@@ -0,0 +1,13 @@
1
+ import { Schema } from 'koishi';
2
+ export interface Config {
3
+ loggerinfo: boolean;
4
+ maxMessagesPerChannel: number;
5
+ keepMessagesOnClear: number;
6
+ keepTempImages: number;
7
+ blockedPlatforms: Array<{
8
+ platformName: string;
9
+ exactMatch: boolean;
10
+ }>;
11
+ chatContainerHeight: number;
12
+ }
13
+ export declare const Config: Schema<Config>;
@@ -0,0 +1,18 @@
1
+ import { ChatData, MessageInfo } from './types';
2
+ import { Context } from 'koishi';
3
+ import { Config } from './config';
4
+ export declare class FileManager {
5
+ private ctx;
6
+ private config;
7
+ private dataFilePath;
8
+ private fileOperationLock;
9
+ private logger;
10
+ private utils;
11
+ constructor(ctx: Context, config: Config);
12
+ private ensureDataDir;
13
+ readChatDataFromFile(): ChatData;
14
+ writeChatDataToFile(data: ChatData): void;
15
+ cleanExcessMessages(data: ChatData): ChatData;
16
+ addMessageToFile(messageInfo: MessageInfo): Promise<void>;
17
+ private logInfo;
18
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ export declare const name = "chat-patch";
4
+ export declare const reusable = false;
5
+ export declare const filter = true;
6
+ export declare const inject: {
7
+ required: string[];
8
+ };
9
+ export declare const usage = "\n\n---\n\n\u5F00\u542F\u540E\uFF0C\u5373\u53EF\u5728koishi\u63A7\u5236\u53F0\u64CD\u4F5C\u673A\u5668\u4EBA\u6536\u53D1\u6D88\u606F\u5566\n\n\u6682\u65F6\u53EA\u652F\u6301\u63A5\u53D7\u56FE\u6587\u6D88\u606F / \u53D1\u9001\u6587\u5B57\u6D88\u606F\n\n---\n";
10
+ export { Config } from './config';
11
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
package/lib/index.js CHANGED
@@ -138,6 +138,17 @@ var MessageHandler = class {
138
138
  }
139
139
  logger;
140
140
  utils;
141
+ // 存储正确的 channelId 映射,key 是 selfId,value 是正确的 channelId
142
+ correctChannelIds = /* @__PURE__ */ new Map();
143
+ // 设置正确的 channelId
144
+ setCorrectChannelId(selfId, channelId) {
145
+ this.correctChannelIds.set(selfId, channelId);
146
+ this.logInfo("设置正确的 channelId:", { selfId, channelId });
147
+ }
148
+ // 获取正确的 channelId
149
+ getCorrectChannelId(selfId) {
150
+ return this.correctChannelIds.get(selfId);
151
+ }
141
152
  // 更新机器人信息到JSON文件
142
153
  async updateBotInfoToFile(session) {
143
154
  const data = this.fileManager.readChatDataFromFile();
@@ -170,10 +181,11 @@ var MessageHandler = class {
170
181
  }
171
182
  const channelInfo = {
172
183
  id: session.channelId,
173
- name: session.guildId ? `${guildName} (${session.channelId})` : `私信 ${session.channelId}`,
184
+ name: session.isDirect ? `私信 ${session.channelId}` : `${guildName} (${session.channelId})`,
174
185
  type: session.type || 0,
175
- guildId: session.guildId,
176
- guildName
186
+ channelId: session.channelId,
187
+ guildName,
188
+ isDirect: session.isDirect
177
189
  };
178
190
  data.channels[session.selfId][session.channelId] = channelInfo;
179
191
  this.fileManager.writeChatDataToFile(data);
@@ -226,10 +238,10 @@ var MessageHandler = class {
226
238
  selfId: session.selfId,
227
239
  elements: this.utils.cleanBase64Content(elements),
228
240
  type: "user",
229
- guildId: session.guildId,
230
241
  guildName,
231
242
  platform: session.platform || "unknown",
232
- quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0
243
+ quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0,
244
+ isDirect: session.isDirect
233
245
  };
234
246
  await this.fileManager.addMessageToFile(messageInfo);
235
247
  const messageEvent = {
@@ -243,11 +255,11 @@ var MessageHandler = class {
243
255
  username: session.username || session.event?.user?.name || session.userId || "unknown",
244
256
  avatar: session.event?.user?.avatar,
245
257
  timestamp,
246
- guildId: session.guildId,
247
258
  guildName,
248
259
  channelType: session.type || 0,
249
260
  elements: this.utils.cleanBase64Content(elements),
250
261
  quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0,
262
+ isDirect: session.isDirect,
251
263
  bot: {
252
264
  avatar: session.bot.user?.avatar,
253
265
  name: session.bot.user?.name
@@ -261,6 +273,16 @@ var MessageHandler = class {
261
273
  // 处理机器人发送的消息
262
274
  async broadcastBotMessageEvent(session) {
263
275
  try {
276
+ const correctChannelId = this.getCorrectChannelId(session.selfId);
277
+ this.logInfo("机器人发送消息调试信息:", {
278
+ "session.channelId": session.channelId,
279
+ "session.event?.channel?.id": session.event?.channel?.id,
280
+ "correctChannelId": correctChannelId,
281
+ "session.guildId": session.guildId,
282
+ "session.isDirect": session.isDirect,
283
+ "session.platform": session.platform
284
+ });
285
+ const finalChannelId = correctChannelId || session.channelId;
264
286
  await this.updateBotInfoToFile(session);
265
287
  const guildName = await this.updateChannelInfoToFile(session);
266
288
  const timestamp = Date.now();
@@ -275,30 +297,30 @@ var MessageHandler = class {
275
297
  username: session.bot.user?.name || `Bot-${session.selfId}`,
276
298
  avatar: session.bot.user?.avatar,
277
299
  timestamp,
278
- channelId: session.event?.channel?.id || session.channelId,
300
+ channelId: finalChannelId,
279
301
  selfId: session.selfId,
280
302
  elements: this.utils.cleanBase64Content(session.event?.message?.elements),
281
303
  type: "bot",
282
- guildId: session.event?.guild?.id || session.guildId,
283
304
  guildName,
284
- platform: session.platform || "unknown"
305
+ platform: session.platform || "unknown",
306
+ isDirect: session.isDirect
285
307
  };
286
308
  await this.fileManager.addMessageToFile(messageInfo);
287
309
  const messageEvent = {
288
310
  type: "bot-message",
289
311
  selfId: session.selfId,
290
312
  platform: session.platform || "unknown",
291
- channelId: session.event?.channel?.id || session.channelId,
313
+ channelId: finalChannelId,
292
314
  messageId: `bot-msg-${timestamp}`,
293
315
  content,
294
316
  userId: session.selfId,
295
317
  username: session.bot.user?.name || `Bot-${session.selfId}`,
296
318
  avatar: session.bot.user?.avatar,
297
319
  timestamp,
298
- guildId: session.event?.guild?.id || session.guildId,
299
320
  guildName,
300
321
  channelType: session.event?.channel?.type || session.type || 0,
301
322
  elements: this.utils.cleanBase64Content(session.event?.message?.elements),
323
+ isDirect: session.isDirect,
302
324
  bot: {
303
325
  avatar: session.bot.user?.avatar,
304
326
  name: session.bot.user?.name
@@ -310,11 +332,14 @@ var MessageHandler = class {
310
332
  this.logInfo("机器人发送消息 (before-send):", {
311
333
  selfId: session.selfId,
312
334
  channelId: messageEvent.channelId,
335
+ originalChannelId: session.channelId,
336
+ correctedChannelId: finalChannelId,
313
337
  content,
314
338
  platform: session.platform,
315
339
  imageCount: imageElements.length,
316
340
  imageUrls: imageElements.map((el) => el.attrs?.src || el.attrs?.url || el.attrs?.file)
317
341
  });
342
+ this.correctChannelIds.delete(session.selfId);
318
343
  this.ctx.console.broadcast("chat-bot-message-event", messageEvent);
319
344
  } catch (error) {
320
345
  this.logger.error("广播机器人消息事件失败:", error);
@@ -474,10 +499,11 @@ var FileManager = class {
474
499
  var import_koishi = require("koishi");
475
500
  var import_node_url = require("node:url");
476
501
  var ApiHandlers = class {
477
- constructor(ctx, config, fileManager) {
502
+ constructor(ctx, config, fileManager, messageHandler) {
478
503
  this.ctx = ctx;
479
504
  this.config = config;
480
505
  this.fileManager = fileManager;
506
+ this.messageHandler = messageHandler;
481
507
  this.logger = ctx.logger("chat-patch");
482
508
  }
483
509
  static {
@@ -630,6 +656,7 @@ var ApiHandlers = class {
630
656
  }
631
657
  }
632
658
  }
659
+ this.messageHandler.setCorrectChannelId(data.selfId, data.channelId);
633
660
  const result = await bot.sendMessage(data.channelId, messageContent);
634
661
  this.logInfo("消息发送成功:", result);
635
662
  return {
@@ -972,7 +999,7 @@ async function apply(ctx, config) {
972
999
  const logger = ctx.logger("chat-patch");
973
1000
  const fileManager = new FileManager(ctx, config);
974
1001
  const messageHandler = new MessageHandler(ctx, config, fileManager);
975
- const apiHandlers = new ApiHandlers(ctx, config, fileManager);
1002
+ const apiHandlers = new ApiHandlers(ctx, config, fileManager, messageHandler);
976
1003
  const utils = new Utils(config);
977
1004
  const initialData = fileManager.readChatDataFromFile();
978
1005
  const cleanedData = fileManager.cleanExcessMessages(initialData);
@@ -0,0 +1,19 @@
1
+ import { Context, Session } from 'koishi';
2
+ import { FileManager } from './file-manager';
3
+ import { Config } from './config';
4
+ export declare class MessageHandler {
5
+ private ctx;
6
+ private config;
7
+ private fileManager;
8
+ private logger;
9
+ private utils;
10
+ private correctChannelIds;
11
+ constructor(ctx: Context, config: Config, fileManager: FileManager);
12
+ setCorrectChannelId(selfId: string, channelId: string): void;
13
+ getCorrectChannelId(selfId: string): string | undefined;
14
+ updateBotInfoToFile(session: Session): Promise<void>;
15
+ updateChannelInfoToFile(session: Session): Promise<string>;
16
+ broadcastMessageEvent(session: Session): Promise<void>;
17
+ broadcastBotMessageEvent(session: Session): Promise<void>;
18
+ private logInfo;
19
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { h } from 'koishi';
2
+ export interface BotInfo {
3
+ selfId: string;
4
+ platform: string;
5
+ username: string;
6
+ avatar?: string;
7
+ status: 'online' | 'offline';
8
+ }
9
+ export interface ChannelInfo {
10
+ id: string;
11
+ name: string;
12
+ type: number | string;
13
+ channelId?: string;
14
+ guildName?: string;
15
+ isDirect?: boolean;
16
+ }
17
+ export interface QuoteInfo {
18
+ messageId: string;
19
+ id: string;
20
+ content: string;
21
+ elements?: h[];
22
+ user: {
23
+ id: string;
24
+ name: string;
25
+ userId: string;
26
+ avatar?: string;
27
+ username: string;
28
+ };
29
+ timestamp: number;
30
+ }
31
+ export interface MessageInfo {
32
+ id: string;
33
+ content: string;
34
+ userId: string;
35
+ username: string;
36
+ avatar?: string;
37
+ timestamp: number;
38
+ channelId: string;
39
+ selfId: string;
40
+ elements?: h[];
41
+ type: 'user' | 'bot';
42
+ guildId?: string;
43
+ guildName?: string;
44
+ platform: string;
45
+ quote?: QuoteInfo;
46
+ isDirect?: boolean;
47
+ }
48
+ export interface ChatData {
49
+ bots: Record<string, BotInfo>;
50
+ channels: Record<string, Record<string, ChannelInfo>>;
51
+ messages: Record<string, MessageInfo[]>;
52
+ pinnedBots: string[];
53
+ pinnedChannels: string[];
54
+ lastSaveTime?: number;
55
+ }
package/lib/utils.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Config } from './config';
2
+ export declare class Utils {
3
+ private config;
4
+ constructor(config: Config);
5
+ isPlatformBlocked(platform: string): boolean;
6
+ extractTextContent(elements: any[]): string;
7
+ private isBase64;
8
+ cleanBase64Content(obj: any): any;
9
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-chat-patch",
3
3
  "description": "[<ruby>chat-patch<rp>(</rp><rt>点我预览效果</rt><rp>)</rp></ruby>](https://i0.hdslb.com/bfs/openplatform/71074dfc9e5256fc3333d8bd8478bec1af874046.png) 视奸小插件((bushi( (低性能警告)。手机端适配。灵感来自 chat 插件。",
4
- "version": "1.0.14",
4
+ "version": "1.0.15",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -1,4 +1,5 @@
1
1
  import { FileManager } from './file-manager'
2
+ import { MessageHandler } from './message-handler'
2
3
  import { Context, h, Logger } from 'koishi'
3
4
  import { Config } from './config'
4
5
 
@@ -10,7 +11,8 @@ export class ApiHandlers {
10
11
  constructor(
11
12
  private ctx: Context,
12
13
  private config: Config,
13
- private fileManager: FileManager
14
+ private fileManager: FileManager,
15
+ private messageHandler: MessageHandler
14
16
  ) {
15
17
  this.logger = ctx.logger('chat-patch')
16
18
  }
@@ -218,6 +220,9 @@ export class ApiHandlers {
218
220
  }
219
221
  }
220
222
 
223
+ // 在发送消息前,通知 MessageHandler 正确的 channelId
224
+ this.messageHandler.setCorrectChannelId(data.selfId, data.channelId)
225
+
221
226
  const result = await bot.sendMessage(data.channelId, messageContent)
222
227
  this.logInfo('消息发送成功:', result)
223
228
 
package/src/index.ts CHANGED
@@ -35,7 +35,7 @@ export async function apply(ctx: Context, config: Config) {
35
35
  // 初始化各个模块
36
36
  const fileManager = new FileManager(ctx, config)
37
37
  const messageHandler = new MessageHandler(ctx, config, fileManager)
38
- const apiHandlers = new ApiHandlers(ctx, config, fileManager)
38
+ const apiHandlers = new ApiHandlers(ctx, config, fileManager, messageHandler)
39
39
  const utils = new Utils(config)
40
40
 
41
41
  // 初始化数据
@@ -7,6 +7,8 @@ import { Utils } from './utils'
7
7
  export class MessageHandler {
8
8
  private logger: Logger
9
9
  private utils: Utils
10
+ // 存储正确的 channelId 映射,key 是 selfId,value 是正确的 channelId
11
+ private correctChannelIds: Map<string, string> = new Map()
10
12
 
11
13
  constructor(
12
14
  private ctx: Context,
@@ -17,6 +19,17 @@ export class MessageHandler {
17
19
  this.utils = new Utils(config)
18
20
  }
19
21
 
22
+ // 设置正确的 channelId
23
+ setCorrectChannelId(selfId: string, channelId: string) {
24
+ this.correctChannelIds.set(selfId, channelId)
25
+ this.logInfo('设置正确的 channelId:', { selfId, channelId })
26
+ }
27
+
28
+ // 获取正确的 channelId
29
+ getCorrectChannelId(selfId: string): string | undefined {
30
+ return this.correctChannelIds.get(selfId)
31
+ }
32
+
20
33
  // 更新机器人信息到JSON文件
21
34
  async updateBotInfoToFile(session: Session) {
22
35
  const data = this.fileManager.readChatDataFromFile()
@@ -56,12 +69,13 @@ export class MessageHandler {
56
69
 
57
70
  const channelInfo: ChannelInfo = {
58
71
  id: session.channelId,
59
- name: session.guildId
60
- ? `${guildName} (${session.channelId})`
61
- : `私信 ${session.channelId}`,
72
+ name: session.isDirect
73
+ ? `私信 ${session.channelId}`
74
+ : `${guildName} (${session.channelId})`,
62
75
  type: session.type || 0,
63
- guildId: session.guildId,
64
- guildName: guildName
76
+ channelId: session.channelId,
77
+ guildName: guildName,
78
+ isDirect: session.isDirect
65
79
  }
66
80
 
67
81
  data.channels[session.selfId][session.channelId] = channelInfo
@@ -129,10 +143,10 @@ export class MessageHandler {
129
143
  selfId: session.selfId,
130
144
  elements: this.utils.cleanBase64Content(elements),
131
145
  type: 'user',
132
- guildId: session.guildId,
133
146
  guildName: guildName,
134
147
  platform: session.platform || 'unknown',
135
- quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined
148
+ quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined,
149
+ isDirect: session.isDirect
136
150
  }
137
151
 
138
152
  await this.fileManager.addMessageToFile(messageInfo)
@@ -148,11 +162,11 @@ export class MessageHandler {
148
162
  username: session.username || session.event?.user?.name || session.userId || 'unknown',
149
163
  avatar: session.event?.user?.avatar,
150
164
  timestamp: timestamp,
151
- guildId: session.guildId,
152
165
  guildName: guildName,
153
166
  channelType: session.type || 0,
154
167
  elements: this.utils.cleanBase64Content(elements),
155
168
  quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined,
169
+ isDirect: session.isDirect,
156
170
  bot: {
157
171
  avatar: session.bot.user?.avatar,
158
172
  name: session.bot.user?.name,
@@ -168,6 +182,22 @@ export class MessageHandler {
168
182
  // 处理机器人发送的消息
169
183
  async broadcastBotMessageEvent(session: Session) {
170
184
  try {
185
+ // 获取正确的 channelId
186
+ const correctChannelId = this.getCorrectChannelId(session.selfId)
187
+
188
+ // 调试日志:检查 channelId 的来源
189
+ this.logInfo('机器人发送消息调试信息:', {
190
+ 'session.channelId': session.channelId,
191
+ 'session.event?.channel?.id': session.event?.channel?.id,
192
+ 'correctChannelId': correctChannelId,
193
+ 'session.guildId': session.guildId,
194
+ 'session.isDirect': session.isDirect,
195
+ 'session.platform': session.platform
196
+ })
197
+
198
+ // 使用正确的 channelId,如果没有则使用 session.channelId
199
+ const finalChannelId = correctChannelId || session.channelId
200
+
171
201
  await this.updateBotInfoToFile(session)
172
202
  const guildName = await this.updateChannelInfoToFile(session)
173
203
 
@@ -187,13 +217,13 @@ export class MessageHandler {
187
217
  username: session.bot.user?.name || `Bot-${session.selfId}`,
188
218
  avatar: session.bot.user?.avatar,
189
219
  timestamp: timestamp,
190
- channelId: session.event?.channel?.id || session.channelId,
220
+ channelId: finalChannelId,
191
221
  selfId: session.selfId,
192
222
  elements: this.utils.cleanBase64Content(session.event?.message?.elements),
193
223
  type: 'bot',
194
- guildId: session.event?.guild?.id || session.guildId,
195
224
  guildName: guildName,
196
- platform: session.platform || 'unknown'
225
+ platform: session.platform || 'unknown',
226
+ isDirect: session.isDirect
197
227
  }
198
228
 
199
229
  await this.fileManager.addMessageToFile(messageInfo)
@@ -202,17 +232,17 @@ export class MessageHandler {
202
232
  type: 'bot-message',
203
233
  selfId: session.selfId,
204
234
  platform: session.platform || 'unknown',
205
- channelId: session.event?.channel?.id || session.channelId,
235
+ channelId: finalChannelId,
206
236
  messageId: `bot-msg-${timestamp}`,
207
237
  content: content,
208
238
  userId: session.selfId,
209
239
  username: session.bot.user?.name || `Bot-${session.selfId}`,
210
240
  avatar: session.bot.user?.avatar,
211
241
  timestamp: timestamp,
212
- guildId: session.event?.guild?.id || session.guildId,
213
242
  guildName: guildName,
214
243
  channelType: session.event?.channel?.type || session.type || 0,
215
244
  elements: this.utils.cleanBase64Content(session.event?.message?.elements),
245
+ isDirect: session.isDirect,
216
246
  bot: {
217
247
  avatar: session.bot.user?.avatar,
218
248
  name: session.bot.user?.name,
@@ -227,12 +257,17 @@ export class MessageHandler {
227
257
  this.logInfo('机器人发送消息 (before-send):', {
228
258
  selfId: session.selfId,
229
259
  channelId: messageEvent.channelId,
260
+ originalChannelId: session.channelId,
261
+ correctedChannelId: finalChannelId,
230
262
  content: content,
231
263
  platform: session.platform,
232
264
  imageCount: imageElements.length,
233
265
  imageUrls: imageElements.map((el: any) => el.attrs?.src || el.attrs?.url || el.attrs?.file)
234
266
  })
235
267
 
268
+ // 清理已使用的 channelId 映射
269
+ this.correctChannelIds.delete(session.selfId)
270
+
236
271
  this.ctx.console.broadcast('chat-bot-message-event', messageEvent)
237
272
  } catch (error) {
238
273
  this.logger.error('广播机器人消息事件失败:', error)
package/src/types.ts CHANGED
@@ -12,8 +12,9 @@ export interface ChannelInfo {
12
12
  id: string
13
13
  name: string
14
14
  type: number | string
15
- guildId?: string
15
+ channelId?: string
16
16
  guildName?: string
17
+ isDirect?: boolean
17
18
  }
18
19
 
19
20
  export interface QuoteInfo {
@@ -46,6 +47,7 @@ export interface MessageInfo {
46
47
  guildName?: string
47
48
  platform: string
48
49
  quote?: QuoteInfo
50
+ isDirect?: boolean
49
51
  }
50
52
 
51
53
  export interface ChatData {