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.
- package/client/vue/chat-logic.ts +14 -11
- package/dist/index.js +6 -6
- package/lib/api-handlers.d.ts +19 -0
- package/lib/config.d.ts +13 -0
- package/lib/file-manager.d.ts +18 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +40 -13
- package/lib/message-handler.d.ts +19 -0
- package/lib/types.d.ts +55 -0
- package/lib/utils.d.ts +9 -0
- package/package.json +1 -1
- package/src/api-handlers.ts +6 -1
- package/src/index.ts +1 -1
- package/src/message-handler.ts +48 -13
- package/src/types.ts +3 -1
package/client/vue/chat-logic.ts
CHANGED
|
@@ -23,8 +23,9 @@ export function useChatLogic() {
|
|
|
23
23
|
id: string
|
|
24
24
|
name: string
|
|
25
25
|
type: number | string
|
|
26
|
-
|
|
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.
|
|
2372
|
-
?
|
|
2373
|
-
:
|
|
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
|
-
|
|
2380
|
-
guildName: messageEvent.guildName ||
|
|
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.
|
|
2565
|
-
?
|
|
2566
|
-
:
|
|
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
|
-
|
|
2573
|
-
guildName: botMessageEvent.guildName ||
|
|
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-
|
|
24
|
-
top: ${t-
|
|
25
|
-
width: ${
|
|
26
|
-
height: ${
|
|
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
|
+
}
|
package/lib/config.d.ts
ADDED
|
@@ -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.
|
|
184
|
+
name: session.isDirect ? `私信 ${session.channelId}` : `${guildName} (${session.channelId})`,
|
|
174
185
|
type: session.type || 0,
|
|
175
|
-
|
|
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:
|
|
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:
|
|
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.
|
|
4
|
+
"version": "1.0.15",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
package/src/api-handlers.ts
CHANGED
|
@@ -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
|
// 初始化数据
|
package/src/message-handler.ts
CHANGED
|
@@ -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.
|
|
60
|
-
?
|
|
61
|
-
:
|
|
72
|
+
name: session.isDirect
|
|
73
|
+
? `私信 ${session.channelId}`
|
|
74
|
+
: `${guildName} (${session.channelId})`,
|
|
62
75
|
type: session.type || 0,
|
|
63
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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 {
|