koishi-plugin-chat-patch 1.0.9 → 1.0.11
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/index.vue +0 -16
- package/dist/index.js +2 -2
- package/dist/style.css +1 -1
- package/lib/api-handlers.d.ts +17 -0
- package/lib/file-manager.d.ts +18 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +144 -146
- package/lib/message-handler.d.ts +16 -0
- package/package.json +1 -1
- package/src/api-handlers.ts +2 -1
- package/src/file-manager.ts +4 -3
- package/src/index.ts +5 -5
- package/src/message-handler.ts +2 -2
package/client/vue/index.vue
CHANGED
|
@@ -698,16 +698,6 @@ const MessageElement = defineComponent({
|
|
|
698
698
|
case 'img':
|
|
699
699
|
case 'image':
|
|
700
700
|
const imageUrl = element.attrs.src || element.attrs.url || element.attrs.file
|
|
701
|
-
|
|
702
|
-
// 调试信息:记录图片 URL 类型
|
|
703
|
-
if (imageUrl && isFileUrl(imageUrl)) {
|
|
704
|
-
console.log('检测到本地文件路径:', imageUrl)
|
|
705
|
-
} else if (imageUrl?.startsWith('http')) {
|
|
706
|
-
console.log('检测到网络图片:', imageUrl)
|
|
707
|
-
} else {
|
|
708
|
-
console.log('检测到其他类型图片URL:', imageUrl)
|
|
709
|
-
}
|
|
710
|
-
|
|
711
701
|
return h('div', { class: 'message-image-container' }, [
|
|
712
702
|
h(ImageComponent, {
|
|
713
703
|
src: imageUrl,
|
|
@@ -719,12 +709,6 @@ const MessageElement = defineComponent({
|
|
|
719
709
|
|
|
720
710
|
case 'mface':
|
|
721
711
|
const mfaceimageUrl = element.attrs.src || element.attrs.url || element.attrs.file
|
|
722
|
-
|
|
723
|
-
// 调试信息:记录表情图片 URL 类型
|
|
724
|
-
if (mfaceimageUrl && isFileUrl(mfaceimageUrl)) {
|
|
725
|
-
console.log('检测到本地表情文件路径:', mfaceimageUrl)
|
|
726
|
-
}
|
|
727
|
-
|
|
728
712
|
return h('div', { class: 'message-image-container' }, [
|
|
729
713
|
h(ImageComponent, {
|
|
730
714
|
src: mfaceimageUrl,
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{defineComponent as E,ref as f,onMounted as Pe,h as d,computed as O,watch as dt,nextTick as oe,onUnmounted as oa,createElementBlock as p,openBlock as v,normalizeStyle as Me,normalizeClass as W,createElementVNode as i,createCommentVNode as Q,Fragment as z,renderList as ce,createBlock as ve,unref as ge,toDisplayString as C,withDirectives as ft,createTextVNode as He,vShow as ca,withModifiers as ht,withKeys as ia,vModelText as ua,resolveComponent as da}from"vue";import{receive as Fe,send as S,icons as fa}from"@koishijs/client";const ha={class:"bot-list"},ma={class:"bot-items"},va=["onClick","onContextmenu"],ga={class:"bot-avatar"},ya={key:1,class:"avatar-placeholder"},pa={class:"bot-info"},wa={class:"bot-name"},Ia={class:"bot-platform"},xa={class:"channel-list"},Ca={key:0,class:"empty-state"},ka={key:1,class:"channel-items"},ba=["data-channel-id","onClick","onContextmenu"],_a={class:"channel-info"},$a={class:"channel-name"},Sa={class:"channel-type"},Ba=["onMousedown","onTouchstart","title"],Da={class:"message-area"},La={class:"panel-header"},Ta={key:0,class:"empty-state"},qa={key:1,class:"message-content"},Ka={class:"message-avatar"},Ua={key:1,class:"avatar-placeholder"},ja={class:"message-content-wrapper"},Aa={class:"message-header"},Na={class:"message-username"},Ra={class:"message-time"},Oa={key:0,class:"message-quote"},za={class:"quote-header"},Pa={class:"quote-avatar"},Ma={key:1,class:"avatar-placeholder"},Ha={class:"quote-username"},Fa={class:"quote-time"},Xa={class:"quote-content"},Ya={class:"message-text"},Wa={class:"message-input"},Ja={key:0,class:"image-preview-container"},Va=["src","alt"],Ga=["onClick"],Za={class:"input-row"},Qa={class:"input-actions"},Ea=["placeholder","disabled"],en=["disabled"],tn=100*1024*1024,Xe=50,mt="ChatImageCache",an=2,B="images",ie=50*1024*1024,vt=100,ue=500,Ye=2*1024*1024,gt=.8,nn=60*1e3,P=80,sn=E({__name:"index",setup(ee){function J(e){try{return new URL(e).protocol==="file:"}catch{return false}}const te=E({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=async()=>{try{a.value="loading";const o=await Oe(e.channelKey,e.src);if(o){t.value=o,a.value="loaded";return}const l=new Image;l.crossOrigin="anonymous",l.referrerPolicy="no-referrer",l.draggable=false;const c=new Promise((y,g)=>{l.onload=()=>y(),l.onerror=()=>g(new Error("Direct load failed")),l.src=e.src}),h=new Promise((y,g)=>{setTimeout(()=>g(new Error("Timeout")),3e3)});try{await Promise.race([c,h]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(y=>{console.warn("异步缓存头像失败:",y)})}catch{await s()}}catch(o){console.error("头像加载失败:",o),a.value="error",n.value="头像加载失败"}},s=async()=>{try{a.value="caching";const o=await le(e.channelKey,e.src);if(o)t.value=o,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(o){console.error("缓存系统加载头像失败:",o),a.value="error",n.value=(o==null?void 0:o.message)||"缓存加载失败"}};return Pe(()=>{r()}),()=>{switch(a.value){case"loading":case"caching":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return d("img",{src:t.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),de=E({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=f(null),s=async()=>{try{a.value="loading";const l=await Oe(e.channelKey,e.src);if(l){t.value=l,a.value="loaded";return}if(J(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await o();return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const h=new Promise((g,L)=>{c.onload=()=>g(),c.onerror=()=>L(new Error("Direct load failed")),c.src=e.src}),y=new Promise((g,L)=>{setTimeout(()=>L(new Error("Timeout")),3e3)});try{await Promise.race([h,y]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(g=>{console.warn("异步缓存图片失败:",g)})}catch{await o()}}catch(l){console.error("图片加载失败:",l),a.value="error",n.value="图片加载失败"}},o=async()=>{try{a.value="caching";const l=await le(e.channelKey,e.src);if(l)t.value=l,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(l){console.error("缓存系统加载图片失败:",l),a.value="error",n.value=(l==null?void 0:l.message)||"缓存加载失败"}};return Pe(()=>{s()}),()=>{switch(a.value){case"loading":return d("div",{class:"message-image-loading"},"加载中...");case"caching":return d("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return d("img",{src:t.value,alt:e.alt,class:"message-image",loading:"lazy",ref:r,draggable:false,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return d("div",{class:"message-image-error"},["图片加载失败",d("br"),d("small",e.filename||e.alt||"未知图片"),d("br"),d("small",{style:"color: #ff9800;"},n.value)]);default:return d("div",{class:"message-image-error"},"未知状态")}}}}),Se=E({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const t=(()=>{try{const r=JSON.parse(e.data);if(r.meta&&r.meta.detail_1){const s=r.meta.detail_1;return{type:"share_card",title:s.title||r.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:r}}catch(r){return console.error("解析JSON数据失败:",r),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{t.type==="share_card"&&t.url&&window.open(t.url,"_blank","noopener,noreferrer")};return()=>t.type==="share_card"&&t.preview?d("img",{src:t.preview,alt:t.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:t.url?"pointer":"default"},title:t.url?`点击打开: ${t.title||"链接"}`:t.title,onError:r=>{const o=r.target.parentElement;o&&(o.style.display="none")}}):t.type==="error"?d("div",{class:"message-json-error"},[d("span",{class:"json-error-text"},t.error),d("details",{class:"json-raw-data"},[d("summary","查看原始数据"),d("pre",{class:"json-raw-content"},e.data)])]):d("div",{class:"message-json-raw"},[d("div",{class:"json-label"},"[JSON数据]"),d("details",{class:"json-raw-data"},[d("summary","查看详情"),d("pre",{class:"json-raw-content"},JSON.stringify(t.data,null,2))])])}}),pt=E({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=f(false),t=()=>{a.value=!a.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(c=>c.type==="message"),o=s.length;return{previews:s.slice(0,3).map(c=>{var g,L;const h=((g=c.attrs)==null?void 0:g.nickname)||"用户";let y="";if(c.children&&c.children.length>0){const $=c.children[0];$.type==="text"?(y=(((L=$.attrs)==null?void 0:L.content)||"").substring(0,20),y.length>15&&(y+="...")):$.type==="img"?y="[图片]":$.type==="video"?y="[视频]":y=`[${$.type}]`}return`${h}:${y}`}),messageCount:o}},r=(s,o)=>{var h,y,g;const l=((h=s.attrs)==null?void 0:h.nickname)||"用户",c=((y=s.attrs)==null?void 0:y.userId)||"unknown";return d("div",{key:o,class:"forwarded-message-item"},[d("div",{class:"forwarded-message-header"},[d("span",{class:"forwarded-message-nickname"},l),d("span",{class:"forwarded-message-userid"},`(${c})`)]),d("div",{class:"forwarded-message-content"},((g=s.children)==null?void 0:g.map((L,$)=>d(ye,{key:$,element:L,channelKey:e.channelKey})))||[])])};return()=>{var l;const{previews:s,messageCount:o}=n();return d("div",{class:"forward-message-container"},[d("div",{class:"forward-message-preview",onClick:t},[d("div",{class:"forward-message-title"},"聊天记录"),...s.map((c,h)=>d("div",{key:h,class:"forward-message-preview-item"},c)),d("div",{class:"forward-message-footer"},[d("span",{class:"forward-message-count"},`查看${o}条转发消息`),d("span",{class:"forward-message-toggle"},a.value?"▲":"▼")])]),a.value&&d("div",{class:"forward-message-expanded"},((l=e.element.children)==null?void 0:l.filter(c=>c.type==="message").map((c,h)=>r(c,h)))||[])])}}}),ye=E({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=t=>{var n,r,s,o,l,c;switch(t.type){case"text":return d("span",{class:"message-text-content"},t.attrs.content||"");case"forward":return d("span",{class:"message-text-content"},`[转发消息 ${t.attrs.id}]`||"[转发消息]");case"img":case"image":const h=t.attrs.src||t.attrs.url||t.attrs.file;return h&&J(h)?console.log("检测到本地文件路径:",h):h!=null&&h.startsWith("http")?console.log("检测到网络图片:",h):console.log("检测到其他类型图片URL:",h),d("div",{class:"message-image-container"},[d(de,{src:h,alt:t.attrs.summary||"图片",filename:t.attrs.filename||t.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const y=t.attrs.src||t.attrs.url||t.attrs.file;return y&&J(y)&&console.log("检测到本地表情文件路径:",y),d("div",{class:"message-image-container"},[d(de,{src:y,alt:t.attrs.summary||"表情",filename:t.attrs.emojiId||t.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((r=(n=t.children[0])==null?void 0:n.attrs)!=null&&r.src){const g=((o=(s=t.children[0])==null?void 0:s.attrs)==null?void 0:o.src)||((c=(l=t.children[0])==null?void 0:l.attrs)==null?void 0:c.url);return d("div",{class:"message-image-container"},[d(de,{src:g,alt:t.attrs.name||t.attrs.id||"[表情]",filename:t.attrs.name||t.attrs.id||"[表情]",channelKey:e.channelKey})])}else return d("span",{class:"message-text-content"},`[${t.attrs.name||t.attrs.id}]`||"[表情]");case"at":return d("span",{class:"message-at",title:t.attrs.name},`${t.attrs.name||t.attrs.id}`);case"json":return d("div",{class:"message-image-container"},[d(Se,{data:t.attrs.data||"",channelKey:e.channelKey})]);case"p":if(t.children&&t.children.length>0){const g=t.children.map((L,$)=>d(ye,{key:$,element:L,channelKey:e.channelKey}));return d("div",{class:"message-paragraph"},g)}else return d("div",{class:"message-paragraph"},"");case"figure":return d(pt,{element:t,channelKey:e.channelKey});default:return d("span",{class:"message-unknown",title:`未知消息类型: ${t.type}`},t.attrs.content||`[${t.type}]`)}};return()=>a(e.element)}}),u=f({bots:{},channels:{},messages:{}}),K=f({}),fe=f({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=f({});let Be=0,w=null,U=0,M=0,We=0;const m=f(""),k=f(""),he=f("");function Je(e){return e.size||0}function pe(e){Be+=e,fe.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(Be/1024/1024).toFixed(2)}MB`)}function Ve(e=10){const a=Object.entries(b.value);if(a.length<=e)return;const t=a.slice(0,a.length-e);let n=0;t.forEach(([r,s])=>{URL.revokeObjectURL(s),delete b.value[r],n+=500*1024,fe.value.loggerinfo&&console.log("清理旧blob URL:",r)}),pe(-n)}function De(){Object.keys(b.value).length>Xe&&Ve(Math.floor(Xe*.7)),Be>tn&&Ve(Math.floor(Xe*.5))}const j=f([]),G=f(false),Le=f(),T=f(false),V=f("bots"),H=f(null),ae=f(null),Te=f(false),Z=f({show:false,text:""}),D=f(),me=f(),qe=f(false),we=f(false),ne=f(false),F=f(""),A=f({x:0,y:0}),q=f({x:0,y:0}),Ge=f({x:0,y:0}),Ke=f({x:0,y:0}),Ue=f(0),N=f(null),se=f(false),I=f(null),x=f({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),X=f(new Set),Y=f(new Set),wt=O(()=>Object.values(u.value.bots).sort((a,t)=>{const n=X.value.has(a.selfId),r=X.value.has(t.selfId);return n&&!r?-1:!n&&r?1:0})),It=O(()=>!m.value||!u.value.channels[m.value]?[]:Object.values(u.value.channels[m.value]).sort((a,t)=>{const n=Y.value.has(`${m.value}:${a.id}`),r=Y.value.has(`${m.value}:${t.id}`);return n&&!r?-1:!n&&r?1:0})),Ze=O(()=>{if(!m.value||!k.value)return[];const e=`${m.value}:${k.value}`,a=u.value.messages[e]||[];return a.filter(t=>t.quote),a}),xt=O(()=>{var a;if(!m.value||!k.value)return"";const e=u.value.channels[m.value];return((a=e==null?void 0:e[k.value])==null?void 0:a.name)||""}),Ie=O(()=>!m.value||!k.value?"":`${m.value}:${k.value}`),Qe=O(()=>m.value&&k.value&&(he.value.trim()||j.value.length>0)&&!ne.value),Ct=O(()=>m.value&&k.value&&!ne.value),kt=O(()=>{if(!T.value)return"";switch(V.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),bt=O(()=>T.value?"输入消息...(屏幕左滑返回)":"输入消息..."),_t=O(()=>{if(T.value){const e=fe.value.chatContainerHeight||80,a=100-e-19;return{height:`${e}vh`,marginTop:`${a}vh`}}return{}});function $t(e){m.value=e,k.value="",T.value&&(V.value="channels")}function St(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="bot"&&x.value.targetId===a){R();return}Ee(e,"bot",a)}function Bt(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="channel"&&x.value.targetId===a){R();return}Ee(e,"channel",a)}function Ee(e,a,t){let s=e.clientX,o=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),o+80>window.innerHeight&&(o=window.innerHeight-80-10),x.value={show:true,x:s,y:o,type:a,targetId:t,isSecondClick:false},document.addEventListener("click",R,{once:true}),document.addEventListener("keydown",et)}function R(){x.value.show=false,document.removeEventListener("click",R),document.removeEventListener("keydown",et)}function et(e){e.key==="Escape"&&x.value.show&&R()}async function Dt(e){X.value.has(e)?X.value.delete(e):X.value.add(e),await S("set-pinned-bots",{pinnedBots:Array.from(X.value)}),R()}async function Lt(e){const a=`${m.value}:${e}`;Y.value.has(a)?Y.value.delete(a):Y.value.add(a),await S("set-pinned-channels",{pinnedChannels:Array.from(Y.value)}),R()}async function Tt(e){try{const a=await S("delete-bot-data",{selfId:e});if(a.success){const t=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of t)delete u.value.messages[n],delete K.value[n],await $e(n);delete u.value.bots[e],delete u.value.channels[e],m.value===e&&(m.value="",k.value=""),_(a.message||"已删除该机器人的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除机器人数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}R()}async function qt(e){try{const a=await S("delete-channel-data",{selfId:m.value,channelId:e});if(a.success){const t=`${m.value}:${e}`;delete u.value.messages[t],delete K.value[t],u.value.channels[m.value]&&delete u.value.channels[m.value][e],await $e(t),k.value===e&&(k.value=""),_(a.message||"已删除该频道的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除频道数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}R()}async function Kt(e){k.value=e,we.value=false,T.value&&(V.value="messages"),m.value&&await aa(m.value,e),oe(()=>{re(),!T.value&&me.value&&me.value.focus()})}async function tt(){if(!Qe.value)return;const e=he.value.trim();if(!e&&j.value.length===0)return;ne.value=true;const a=[...j.value];try{const t=await S("send-message",{selfId:m.value,channelId:k.value,content:e,images:a.map(n=>({tempId:n.tempId,filename:n.filename}))});if(t.success){if(he.value="",a.forEach(n=>{URL.revokeObjectURL(n.preview)}),j.value=[],G.value=false,t.tempImageIds&&t.tempImageIds.length>0)try{await S("cleanup-temp-images",{tempImageIds:t.tempImageIds}),console.log("临时图片清理完成:",t.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",t.error),_("发送失败: "+t.error,"error")}catch(t){console.error("发送消息时出错:",t),_("发送失败: "+((t==null?void 0:t.message)||String(t)),"error")}finally{ne.value=false}}function Ut(){G.value=!G.value}function jt(){Le.value&&Le.value.click(),G.value=false}async function At(e){const a=e.target,t=a.files;if(!(!t||t.length===0)){for(const n of Array.from(t))await at(n);a.value=""}}async function Nt(e){var t;const a=(t=e.clipboardData)==null?void 0:t.items;if(a){for(const n of Array.from(a))if(n.type.startsWith("image/")){e.preventDefault();const r=n.getAsFile();r&&await at(r)}}}async function at(e){try{if(e.size>10*1024*1024){_("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){_("请选择图片文件","error");return}const a=await Ot(e),t=URL.createObjectURL(e),n=await S("upload-image",{file:a,filename:e.name,mimeType:e.type});n.success?j.value.push({tempId:n.tempId,filename:e.name,preview:t,size:e.size}):(URL.revokeObjectURL(t),_("图片上传失败: "+n.error,"error"))}catch(a){console.error("上传图片失败:",a),_("图片上传失败: "+((a==null?void 0:a.message)||String(a)),"error")}}async function Rt(e){try{const a=j.value.findIndex(t=>t.tempId===e);if(a!==-1){const t=j.value[a];URL.revokeObjectURL(t.preview),j.value.splice(a,1)}await S("delete-temp-image",{tempId:e})}catch(a){console.error("删除图片失败:",a)}}function Ot(e){return new Promise((a,t)=>{const n=new FileReader;n.onload=()=>a(n.result),n.onerror=t,n.readAsDataURL(e)})}function nt(e){const a=e.target;a.closest(".input-actions")||(G.value=false),a.closest(".context-menu")||R()}function st(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function zt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function re(){D.value&&(D.value.scrollTop=D.value.scrollHeight,qe.value=false,we.value=false)}function xe(){if(D.value){const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value,r=a-(e+t)<=50,s=!r;qe.value=s,r?we.value=false:we.value=true}}function je(){if(!D.value)return true;const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value;return a-(e+t)<=200}function Ae(e){var n;if(!m.value)return 0;const a=`${m.value}:${e}`,t=K.value[a];return t!==void 0?t:((n=u.value.messages[a])==null?void 0:n.length)||0}function rt(e,a){e.preventDefault(),e.stopPropagation();const t="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;Ue.value=Date.now(),A.value={x:t,y:n},q.value={x:t,y:n},se.value=false;const s=e.target.getBoundingClientRect();Ge.value={x:s.left,y:s.top},Ke.value={x:t-s.left,y:n-s.top},N.value=window.setTimeout(()=>{if(Ue.value>0){se.value=true,F.value=a;const o=e.target,l=o.cloneNode(true);l.classList.add("dragging-clone"),l.style.position="fixed",l.style.zIndex="1000",l.style.pointerEvents="none";const c=o.getBoundingClientRect();l.style.left=`${c.left}px`,l.style.top=`${c.top}px`,l.style.width=`${c.width}px`,l.style.height=`${c.height}px`,document.body.appendChild(l),I.value=l,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",Ce),document.addEventListener("mouseup",ke),document.addEventListener("touchmove",Ce),document.addEventListener("touchend",ke)}function Ce(e){if(!se.value||!I.value)return;e.preventDefault();const a="touches"in e?e.touches[0].clientX:e.clientX,t="touches"in e?e.touches[0].clientY:e.clientY;q.value={x:a,y:t};const n=q.value.x-A.value.x,r=q.value.y-A.value.y,s=Math.sqrt(n*n+r*r),o=Math.max(.3,1-s/(P*2)),l=Math.max(.8,1-s/(P*3)),c=s>P,h=q.value.x-Ke.value.x,y=q.value.y-Ke.value.y;I.value.style.left=`${h}px`,I.value.style.top=`${y}px`,I.value.style.transform=`scale(${l})`,I.value.style.opacity=`${o}`,I.value.style.backgroundColor=c?"#f44336":"#2196f3",I.value.style.boxShadow=c?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",c?I.value.classList.add("will-delete"):I.value.classList.remove("will-delete")}function ke(e){if(N.value&&(clearTimeout(N.value),N.value=null),N.value&&(clearTimeout(N.value),N.value=null),!se.value||!F.value){be();return}const a=F.value;if(Math.sqrt(Math.pow(q.value.x-A.value.x,2)+Math.pow(q.value.y-A.value.y,2))>P)Mt(a),be();else if(I.value){I.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${a}"] .channel-message-count`);if(n){const r=n.getBoundingClientRect();I.value.style.left=`${r.left}px`,I.value.style.top=`${r.top}px`,I.value.style.transform="scale(1)",I.value.style.opacity="1",I.value.style.backgroundColor="#2196f3",I.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{be()},300)}else be()}function be(){N.value&&(clearTimeout(N.value),N.value=null),F.value="",A.value={x:0,y:0},q.value={x:0,y:0},Ge.value={x:0,y:0},Ue.value=0,se.value=false,document.removeEventListener("mousemove",Ce),document.removeEventListener("mouseup",ke),document.removeEventListener("touchmove",Ce),document.removeEventListener("touchend",ke),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),I.value&&I.value.parentNode&&(I.value.parentNode.removeChild(I.value),I.value=null),Ft()}function Pt(e){return F.value===e&&se.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function lt(e){if(F.value!==e)return 0;const a=q.value.x-A.value.x,t=q.value.y-A.value.y;return Math.sqrt(a*a+t*t)}async function Mt(e){if(m.value)try{const a=`${m.value}:${e}`,t=Ae(e),n=fe.value.keepMessagesOnClear;if(n>0&&t<=n){_("当前消息还很少诶~ 无需清理","success");return}const r=await S("clear-channel-history",{selfId:m.value,channelId:e});if(r.success)if(r.clearedCount&&r.clearedCount>0){if(u.value.messages[a]){const o=[...u.value.messages[a]].sort((l,c)=>l.timestamp-c.timestamp);u.value.messages[a]=o.slice(-r.keptCount)}K.value[a]=r.keptCount,await $e(a),_(`历史记录已清理,清理了 ${r.clearedCount} 条消息,保留最新 ${r.keptCount} 条`,"success")}else n===0?(u.value.messages[a]&&(u.value.messages[a]=[]),K.value[a]=0,await $e(a),_("历史记录已清理,所有消息已删除","success")):_("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",r.error),_("清理失败: "+r.error,"error")}catch(a){console.error("清理历史记录时出错:",a),_("清理失败: "+((a==null?void 0:a.message)||String(a)),"error")}}function _(e,a="success"){const t=document.createElement("div");t.className=`notification ${a}`,t.textContent=e;let n="#4caf50";switch(a){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}t.style.cssText=`
|
|
1
|
+
import{defineComponent as Q,ref as f,onMounted as Pe,h as d,computed as R,watch as dt,nextTick as oe,onUnmounted as oa,createElementBlock as y,openBlock as m,normalizeStyle as Me,normalizeClass as W,createElementVNode as i,createCommentVNode as Z,Fragment as z,renderList as ce,createBlock as ve,unref as ge,toDisplayString as C,withDirectives as ft,createTextVNode as He,vShow as ca,withModifiers as ht,withKeys as ia,vModelText as ua,resolveComponent as da}from"vue";import{receive as Fe,send as S,icons as fa}from"@koishijs/client";const ha={class:"bot-list"},ma={class:"bot-items"},va=["onClick","onContextmenu"],ga={class:"bot-avatar"},ya={key:1,class:"avatar-placeholder"},pa={class:"bot-info"},wa={class:"bot-name"},Ia={class:"bot-platform"},xa={class:"channel-list"},Ca={key:0,class:"empty-state"},ka={key:1,class:"channel-items"},ba=["data-channel-id","onClick","onContextmenu"],_a={class:"channel-info"},$a={class:"channel-name"},Sa={class:"channel-type"},Ba=["onMousedown","onTouchstart","title"],Da={class:"message-area"},Ta={class:"panel-header"},La={key:0,class:"empty-state"},qa={key:1,class:"message-content"},Ua={class:"message-avatar"},Ka={key:1,class:"avatar-placeholder"},ja={class:"message-content-wrapper"},Aa={class:"message-header"},Na={class:"message-username"},Oa={class:"message-time"},Ra={key:0,class:"message-quote"},za={class:"quote-header"},Pa={class:"quote-avatar"},Ma={key:1,class:"avatar-placeholder"},Ha={class:"quote-username"},Fa={class:"quote-time"},Xa={class:"quote-content"},Ya={class:"message-text"},Wa={class:"message-input"},Ja={key:0,class:"image-preview-container"},Va=["src","alt"],Ga=["onClick"],Za={class:"input-row"},Qa={class:"input-actions"},Ea=["placeholder","disabled"],en=["disabled"],tn=100*1024*1024,Xe=50,mt="ChatImageCache",an=2,B="images",ie=50*1024*1024,vt=100,ue=500,Ye=2*1024*1024,gt=.8,nn=60*1e3,P=80,sn=Q({__name:"index",setup(E){function ee(e){try{return new URL(e).protocol==="file:"}catch{return false}}const te=Q({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=async()=>{try{a.value="loading";const o=await Re(e.channelKey,e.src);if(o){t.value=o,a.value="loaded";return}const l=new Image;l.crossOrigin="anonymous",l.referrerPolicy="no-referrer",l.draggable=false;const c=new Promise((p,g)=>{l.onload=()=>p(),l.onerror=()=>g(new Error("Direct load failed")),l.src=e.src}),v=new Promise((p,g)=>{setTimeout(()=>g(new Error("Timeout")),3e3)});try{await Promise.race([c,v]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(p=>{console.warn("异步缓存头像失败:",p)})}catch{await s()}}catch(o){console.error("头像加载失败:",o),a.value="error",n.value="头像加载失败"}},s=async()=>{try{a.value="caching";const o=await le(e.channelKey,e.src);if(o)t.value=o,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(o){console.error("缓存系统加载头像失败:",o),a.value="error",n.value=(o==null?void 0:o.message)||"缓存加载失败"}};return Pe(()=>{r()}),()=>{switch(a.value){case"loading":case"caching":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return d("img",{src:t.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),de=Q({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=f(null),s=async()=>{try{a.value="loading";const l=await Re(e.channelKey,e.src);if(l){t.value=l,a.value="loaded";return}if(ee(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await o();return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const v=new Promise((g,T)=>{c.onload=()=>g(),c.onerror=()=>T(new Error("Direct load failed")),c.src=e.src}),p=new Promise((g,T)=>{setTimeout(()=>T(new Error("Timeout")),3e3)});try{await Promise.race([v,p]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(g=>{console.warn("异步缓存图片失败:",g)})}catch{await o()}}catch(l){console.error("图片加载失败:",l),a.value="error",n.value="图片加载失败"}},o=async()=>{try{a.value="caching";const l=await le(e.channelKey,e.src);if(l)t.value=l,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(l){console.error("缓存系统加载图片失败:",l),a.value="error",n.value=(l==null?void 0:l.message)||"缓存加载失败"}};return Pe(()=>{s()}),()=>{switch(a.value){case"loading":return d("div",{class:"message-image-loading"},"加载中...");case"caching":return d("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return d("img",{src:t.value,alt:e.alt,class:"message-image",loading:"lazy",ref:r,draggable:false,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return d("div",{class:"message-image-error"},["图片加载失败",d("br"),d("small",e.filename||e.alt||"未知图片"),d("br"),d("small",{style:"color: #ff9800;"},n.value)]);default:return d("div",{class:"message-image-error"},"未知状态")}}}}),Se=Q({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const t=(()=>{try{const r=JSON.parse(e.data);if(r.meta&&r.meta.detail_1){const s=r.meta.detail_1;return{type:"share_card",title:s.title||r.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:r}}catch(r){return console.error("解析JSON数据失败:",r),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{t.type==="share_card"&&t.url&&window.open(t.url,"_blank","noopener,noreferrer")};return()=>t.type==="share_card"&&t.preview?d("img",{src:t.preview,alt:t.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:t.url?"pointer":"default"},title:t.url?`点击打开: ${t.title||"链接"}`:t.title,onError:r=>{const o=r.target.parentElement;o&&(o.style.display="none")}}):t.type==="error"?d("div",{class:"message-json-error"},[d("span",{class:"json-error-text"},t.error),d("details",{class:"json-raw-data"},[d("summary","查看原始数据"),d("pre",{class:"json-raw-content"},e.data)])]):d("div",{class:"message-json-raw"},[d("div",{class:"json-label"},"[JSON数据]"),d("details",{class:"json-raw-data"},[d("summary","查看详情"),d("pre",{class:"json-raw-content"},JSON.stringify(t.data,null,2))])])}}),pt=Q({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=f(false),t=()=>{a.value=!a.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(c=>c.type==="message"),o=s.length;return{previews:s.slice(0,3).map(c=>{var g,T;const v=((g=c.attrs)==null?void 0:g.nickname)||"用户";let p="";if(c.children&&c.children.length>0){const $=c.children[0];$.type==="text"?(p=(((T=$.attrs)==null?void 0:T.content)||"").substring(0,20),p.length>15&&(p+="...")):$.type==="img"?p="[图片]":$.type==="video"?p="[视频]":p=`[${$.type}]`}return`${v}:${p}`}),messageCount:o}},r=(s,o)=>{var v,p,g;const l=((v=s.attrs)==null?void 0:v.nickname)||"用户",c=((p=s.attrs)==null?void 0:p.userId)||"unknown";return d("div",{key:o,class:"forwarded-message-item"},[d("div",{class:"forwarded-message-header"},[d("span",{class:"forwarded-message-nickname"},l),d("span",{class:"forwarded-message-userid"},`(${c})`)]),d("div",{class:"forwarded-message-content"},((g=s.children)==null?void 0:g.map((T,$)=>d(ye,{key:$,element:T,channelKey:e.channelKey})))||[])])};return()=>{var l;const{previews:s,messageCount:o}=n();return d("div",{class:"forward-message-container"},[d("div",{class:"forward-message-preview",onClick:t},[d("div",{class:"forward-message-title"},"聊天记录"),...s.map((c,v)=>d("div",{key:v,class:"forward-message-preview-item"},c)),d("div",{class:"forward-message-footer"},[d("span",{class:"forward-message-count"},`查看${o}条转发消息`),d("span",{class:"forward-message-toggle"},a.value?"▲":"▼")])]),a.value&&d("div",{class:"forward-message-expanded"},((l=e.element.children)==null?void 0:l.filter(c=>c.type==="message").map((c,v)=>r(c,v)))||[])])}}}),ye=Q({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=t=>{var n,r,s,o,l,c;switch(t.type){case"text":return d("span",{class:"message-text-content"},t.attrs.content||"");case"forward":return d("span",{class:"message-text-content"},`[转发消息 ${t.attrs.id}]`||"[转发消息]");case"img":case"image":const v=t.attrs.src||t.attrs.url||t.attrs.file;return d("div",{class:"message-image-container"},[d(de,{src:v,alt:t.attrs.summary||"图片",filename:t.attrs.filename||t.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const p=t.attrs.src||t.attrs.url||t.attrs.file;return d("div",{class:"message-image-container"},[d(de,{src:p,alt:t.attrs.summary||"表情",filename:t.attrs.emojiId||t.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((r=(n=t.children[0])==null?void 0:n.attrs)!=null&&r.src){const g=((o=(s=t.children[0])==null?void 0:s.attrs)==null?void 0:o.src)||((c=(l=t.children[0])==null?void 0:l.attrs)==null?void 0:c.url);return d("div",{class:"message-image-container"},[d(de,{src:g,alt:t.attrs.name||t.attrs.id||"[表情]",filename:t.attrs.name||t.attrs.id||"[表情]",channelKey:e.channelKey})])}else return d("span",{class:"message-text-content"},`[${t.attrs.name||t.attrs.id}]`||"[表情]");case"at":return d("span",{class:"message-at",title:t.attrs.name},`${t.attrs.name||t.attrs.id}`);case"json":return d("div",{class:"message-image-container"},[d(Se,{data:t.attrs.data||"",channelKey:e.channelKey})]);case"p":if(t.children&&t.children.length>0){const g=t.children.map((T,$)=>d(ye,{key:$,element:T,channelKey:e.channelKey}));return d("div",{class:"message-paragraph"},g)}else return d("div",{class:"message-paragraph"},"");case"figure":return d(pt,{element:t,channelKey:e.channelKey});default:return d("span",{class:"message-unknown",title:`未知消息类型: ${t.type}`},t.attrs.content||`[${t.type}]`)}};return()=>a(e.element)}}),u=f({bots:{},channels:{},messages:{}}),U=f({}),fe=f({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=f({});let Be=0,w=null,K=0,M=0,We=0;const h=f(""),k=f(""),he=f("");function Je(e){return e.size||0}function pe(e){Be+=e,fe.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(Be/1024/1024).toFixed(2)}MB`)}function Ve(e=10){const a=Object.entries(b.value);if(a.length<=e)return;const t=a.slice(0,a.length-e);let n=0;t.forEach(([r,s])=>{URL.revokeObjectURL(s),delete b.value[r],n+=500*1024,fe.value.loggerinfo&&console.log("清理旧blob URL:",r)}),pe(-n)}function De(){Object.keys(b.value).length>Xe&&Ve(Math.floor(Xe*.7)),Be>tn&&Ve(Math.floor(Xe*.5))}const j=f([]),V=f(false),Te=f(),L=f(false),J=f("bots"),H=f(null),ae=f(null),Le=f(false),G=f({show:false,text:""}),D=f(),me=f(),qe=f(false),we=f(false),ne=f(false),F=f(""),A=f({x:0,y:0}),q=f({x:0,y:0}),Ge=f({x:0,y:0}),Ue=f({x:0,y:0}),Ke=f(0),N=f(null),se=f(false),I=f(null),x=f({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),X=f(new Set),Y=f(new Set),wt=R(()=>Object.values(u.value.bots).sort((a,t)=>{const n=X.value.has(a.selfId),r=X.value.has(t.selfId);return n&&!r?-1:!n&&r?1:0})),It=R(()=>!h.value||!u.value.channels[h.value]?[]:Object.values(u.value.channels[h.value]).sort((a,t)=>{const n=Y.value.has(`${h.value}:${a.id}`),r=Y.value.has(`${h.value}:${t.id}`);return n&&!r?-1:!n&&r?1:0})),Ze=R(()=>{if(!h.value||!k.value)return[];const e=`${h.value}:${k.value}`,a=u.value.messages[e]||[];return a.filter(t=>t.quote),a}),xt=R(()=>{var a;if(!h.value||!k.value)return"";const e=u.value.channels[h.value];return((a=e==null?void 0:e[k.value])==null?void 0:a.name)||""}),Ie=R(()=>!h.value||!k.value?"":`${h.value}:${k.value}`),Qe=R(()=>h.value&&k.value&&(he.value.trim()||j.value.length>0)&&!ne.value),Ct=R(()=>h.value&&k.value&&!ne.value),kt=R(()=>{if(!L.value)return"";switch(J.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),bt=R(()=>L.value?"输入消息...(屏幕左滑返回)":"输入消息..."),_t=R(()=>{if(L.value){const e=fe.value.chatContainerHeight||80,a=100-e-19;return{height:`${e}vh`,marginTop:`${a}vh`}}return{}});function $t(e){h.value=e,k.value="",L.value&&(J.value="channels")}function St(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="bot"&&x.value.targetId===a){O();return}Ee(e,"bot",a)}function Bt(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="channel"&&x.value.targetId===a){O();return}Ee(e,"channel",a)}function Ee(e,a,t){let s=e.clientX,o=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),o+80>window.innerHeight&&(o=window.innerHeight-80-10),x.value={show:true,x:s,y:o,type:a,targetId:t,isSecondClick:false},document.addEventListener("click",O,{once:true}),document.addEventListener("keydown",et)}function O(){x.value.show=false,document.removeEventListener("click",O),document.removeEventListener("keydown",et)}function et(e){e.key==="Escape"&&x.value.show&&O()}async function Dt(e){X.value.has(e)?X.value.delete(e):X.value.add(e),await S("set-pinned-bots",{pinnedBots:Array.from(X.value)}),O()}async function Tt(e){const a=`${h.value}:${e}`;Y.value.has(a)?Y.value.delete(a):Y.value.add(a),await S("set-pinned-channels",{pinnedChannels:Array.from(Y.value)}),O()}async function Lt(e){try{const a=await S("delete-bot-data",{selfId:e});if(a.success){const t=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of t)delete u.value.messages[n],delete U.value[n],await $e(n);delete u.value.bots[e],delete u.value.channels[e],h.value===e&&(h.value="",k.value=""),_(a.message||"已删除该机器人的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除机器人数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}O()}async function qt(e){try{const a=await S("delete-channel-data",{selfId:h.value,channelId:e});if(a.success){const t=`${h.value}:${e}`;delete u.value.messages[t],delete U.value[t],u.value.channels[h.value]&&delete u.value.channels[h.value][e],await $e(t),k.value===e&&(k.value=""),_(a.message||"已删除该频道的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除频道数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}O()}async function Ut(e){k.value=e,we.value=false,L.value&&(J.value="messages"),h.value&&await aa(h.value,e),oe(()=>{re(),!L.value&&me.value&&me.value.focus()})}async function tt(){if(!Qe.value)return;const e=he.value.trim();if(!e&&j.value.length===0)return;ne.value=true;const a=[...j.value];try{const t=await S("send-message",{selfId:h.value,channelId:k.value,content:e,images:a.map(n=>({tempId:n.tempId,filename:n.filename}))});if(t.success){if(he.value="",a.forEach(n=>{URL.revokeObjectURL(n.preview)}),j.value=[],V.value=false,t.tempImageIds&&t.tempImageIds.length>0)try{await S("cleanup-temp-images",{tempImageIds:t.tempImageIds}),console.log("临时图片清理完成:",t.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",t.error),_("发送失败: "+t.error,"error")}catch(t){console.error("发送消息时出错:",t),_("发送失败: "+((t==null?void 0:t.message)||String(t)),"error")}finally{ne.value=false}}function Kt(){V.value=!V.value}function jt(){Te.value&&Te.value.click(),V.value=false}async function At(e){const a=e.target,t=a.files;if(!(!t||t.length===0)){for(const n of Array.from(t))await at(n);a.value=""}}async function Nt(e){var t;const a=(t=e.clipboardData)==null?void 0:t.items;if(a){for(const n of Array.from(a))if(n.type.startsWith("image/")){e.preventDefault();const r=n.getAsFile();r&&await at(r)}}}async function at(e){try{if(e.size>10*1024*1024){_("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){_("请选择图片文件","error");return}const a=await Rt(e),t=URL.createObjectURL(e),n=await S("upload-image",{file:a,filename:e.name,mimeType:e.type});n.success?j.value.push({tempId:n.tempId,filename:e.name,preview:t,size:e.size}):(URL.revokeObjectURL(t),_("图片上传失败: "+n.error,"error"))}catch(a){console.error("上传图片失败:",a),_("图片上传失败: "+((a==null?void 0:a.message)||String(a)),"error")}}async function Ot(e){try{const a=j.value.findIndex(t=>t.tempId===e);if(a!==-1){const t=j.value[a];URL.revokeObjectURL(t.preview),j.value.splice(a,1)}await S("delete-temp-image",{tempId:e})}catch(a){console.error("删除图片失败:",a)}}function Rt(e){return new Promise((a,t)=>{const n=new FileReader;n.onload=()=>a(n.result),n.onerror=t,n.readAsDataURL(e)})}function nt(e){const a=e.target;a.closest(".input-actions")||(V.value=false),a.closest(".context-menu")||O()}function st(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function zt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function re(){D.value&&(D.value.scrollTop=D.value.scrollHeight,qe.value=false,we.value=false)}function xe(){if(D.value){const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value,r=a-(e+t)<=50,s=!r;qe.value=s,r?we.value=false:we.value=true}}function je(){if(!D.value)return true;const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value;return a-(e+t)<=200}function Ae(e){var n;if(!h.value)return 0;const a=`${h.value}:${e}`,t=U.value[a];return t!==void 0?t:((n=u.value.messages[a])==null?void 0:n.length)||0}function rt(e,a){e.preventDefault(),e.stopPropagation();const t="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;Ke.value=Date.now(),A.value={x:t,y:n},q.value={x:t,y:n},se.value=false;const s=e.target.getBoundingClientRect();Ge.value={x:s.left,y:s.top},Ue.value={x:t-s.left,y:n-s.top},N.value=window.setTimeout(()=>{if(Ke.value>0){se.value=true,F.value=a;const o=e.target,l=o.cloneNode(true);l.classList.add("dragging-clone"),l.style.position="fixed",l.style.zIndex="1000",l.style.pointerEvents="none";const c=o.getBoundingClientRect();l.style.left=`${c.left}px`,l.style.top=`${c.top}px`,l.style.width=`${c.width}px`,l.style.height=`${c.height}px`,document.body.appendChild(l),I.value=l,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",Ce),document.addEventListener("mouseup",ke),document.addEventListener("touchmove",Ce),document.addEventListener("touchend",ke)}function Ce(e){if(!se.value||!I.value)return;e.preventDefault();const a="touches"in e?e.touches[0].clientX:e.clientX,t="touches"in e?e.touches[0].clientY:e.clientY;q.value={x:a,y:t};const n=q.value.x-A.value.x,r=q.value.y-A.value.y,s=Math.sqrt(n*n+r*r),o=Math.max(.3,1-s/(P*2)),l=Math.max(.8,1-s/(P*3)),c=s>P,v=q.value.x-Ue.value.x,p=q.value.y-Ue.value.y;I.value.style.left=`${v}px`,I.value.style.top=`${p}px`,I.value.style.transform=`scale(${l})`,I.value.style.opacity=`${o}`,I.value.style.backgroundColor=c?"#f44336":"#2196f3",I.value.style.boxShadow=c?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",c?I.value.classList.add("will-delete"):I.value.classList.remove("will-delete")}function ke(e){if(N.value&&(clearTimeout(N.value),N.value=null),N.value&&(clearTimeout(N.value),N.value=null),!se.value||!F.value){be();return}const a=F.value;if(Math.sqrt(Math.pow(q.value.x-A.value.x,2)+Math.pow(q.value.y-A.value.y,2))>P)Mt(a),be();else if(I.value){I.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${a}"] .channel-message-count`);if(n){const r=n.getBoundingClientRect();I.value.style.left=`${r.left}px`,I.value.style.top=`${r.top}px`,I.value.style.transform="scale(1)",I.value.style.opacity="1",I.value.style.backgroundColor="#2196f3",I.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{be()},300)}else be()}function be(){N.value&&(clearTimeout(N.value),N.value=null),F.value="",A.value={x:0,y:0},q.value={x:0,y:0},Ge.value={x:0,y:0},Ke.value=0,se.value=false,document.removeEventListener("mousemove",Ce),document.removeEventListener("mouseup",ke),document.removeEventListener("touchmove",Ce),document.removeEventListener("touchend",ke),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),I.value&&I.value.parentNode&&(I.value.parentNode.removeChild(I.value),I.value=null),Ft()}function Pt(e){return F.value===e&&se.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function lt(e){if(F.value!==e)return 0;const a=q.value.x-A.value.x,t=q.value.y-A.value.y;return Math.sqrt(a*a+t*t)}async function Mt(e){if(h.value)try{const a=`${h.value}:${e}`,t=Ae(e),n=fe.value.keepMessagesOnClear;if(n>0&&t<=n){_("当前消息还很少诶~ 无需清理","success");return}const r=await S("clear-channel-history",{selfId:h.value,channelId:e});if(r.success)if(r.clearedCount&&r.clearedCount>0){if(u.value.messages[a]){const o=[...u.value.messages[a]].sort((l,c)=>l.timestamp-c.timestamp);u.value.messages[a]=o.slice(-r.keptCount)}U.value[a]=r.keptCount,await $e(a),_(`历史记录已清理,清理了 ${r.clearedCount} 条消息,保留最新 ${r.keptCount} 条`,"success")}else n===0?(u.value.messages[a]&&(u.value.messages[a]=[]),U.value[a]=0,await $e(a),_("历史记录已清理,所有消息已删除","success")):_("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",r.error),_("清理失败: "+r.error,"error")}catch(a){console.error("清理历史记录时出错:",a),_("清理失败: "+((a==null?void 0:a.message)||String(a)),"error")}}function _(e,a="success"){const t=document.createElement("div");t.className=`notification ${a}`,t.textContent=e;let n="#4caf50";switch(a){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}t.style.cssText=`
|
|
2
2
|
position: fixed;
|
|
3
3
|
top: 20px;
|
|
4
4
|
right: 20px;
|
|
@@ -24,4 +24,4 @@ import{defineComponent as E,ref as f,onMounted as Pe,h as d,computed as O,watch
|
|
|
24
24
|
top: ${a-P}px;
|
|
25
25
|
width: ${P*2}px;
|
|
26
26
|
height: ${P*2}px;
|
|
27
|
-
`,document.body.appendChild(t),window.dragThresholdCircle=t}function Ft(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function Ne(){try{if(!w)return false;const e=Date.now();if(e-We<nn)return true;We=e;const a=await ot();U=a.totalSize,M=a.totalImages,console.log("数据库健康检查:",{大小:`${(U/1024/1024).toFixed(2)}MB / ${(ie/1024/1024).toFixed(2)}MB`,图片数量:`${M} / ${ue}`,使用率:`${(U/ie*100).toFixed(1)}%`});const t=U/ie,n=M/ue;return(t>gt||n>gt)&&(console.warn("数据库使用率过高,开始自动清理"),await _e()),(t>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Xt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function ot(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{const r=n.result||[];let s=0;const o={};r.forEach(l=>{s+=l.size||0,o[l.channelKey]=(o[l.channelKey]||0)+1}),e({totalSize:s,totalImages:r.length,channelStats:o})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function _e(){try{console.log("开始自动清理...");const e=await ct();if(e.length===0)return;const a={};e.forEach(r=>{a[r.channelKey]||(a[r.channelKey]=[]),a[r.channelKey].push(r)});let t=0,n=0;for(const[r,s]of Object.entries(a))if(s.length>vt){s.sort((l,c)=>l.timestamp-c.timestamp);const o=s.slice(0,s.length-vt);for(const l of o)await Re(l.url),t++,n+=l.size||0,b.value[l.url]&&(URL.revokeObjectURL(b.value[l.url]),delete b.value[l.url])}console.log(`自动清理完成: 清理了 ${t} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),M-=t,U-=n}catch(e){console.error("自动清理失败:",e)}}async function Xt(){try{console.log("开始紧急清理...");const e=await ct();if(e.length===0)return;e.sort((s,o)=>o.timestamp-s.timestamp);const a=Math.floor(ue*.3),t=e.slice(a);let n=0,r=0;for(const s of t)await Re(s.url),n++,r+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(r/1024/1024).toFixed(2)}MB`),M=a,U-=r}catch(e){console.error("紧急清理失败:",e)}}async function ct(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Yt(){return new Promise(e=>{try{w&&(w.close(),w=null);const a=indexedDB.deleteDatabase(mt);a.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),U=0,M=0,e(true)},a.onerror=()=>{console.error("清理IndexedDB数据库失败:",a.error),e(false)},a.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(a){console.error("清理数据库时出错:",a),e(false)}})}async function Wt(){try{return await it()?(setTimeout(async()=>{const a=await ot();console.log("数据库初始状态:",{大小:`${(a.totalSize/1024/1024).toFixed(2)}MB`,图片数量:a.totalImages,频道分布:a.channelStats}),(a.totalSize>ie*.9||a.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await _e())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Yt(),await it())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function it(){return new Promise(e=>{try{const a=indexedDB.open(mt,an);a.onerror=()=>{console.error("IndexedDB打开失败:",a.error),e(false)},a.onsuccess=()=>{w=a.result,w.onerror=t=>{console.error("IndexedDB运行时错误:",t)},w.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),w==null||w.close(),w=null},e(true)},a.onupgradeneeded=t=>{const n=t.target.result;if(!n.objectStoreNames.contains(B)){const r=n.createObjectStore(B,{keyPath:"url"});r.createIndex("channelKey","channelKey",{unique:false}),r.createIndex("timestamp","timestamp",{unique:false}),r.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},a.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(a){console.error("打开数据库时出错:",a),e(false)}})}async function Jt(e){return w?new Promise((a,t)=>{const s=w.transaction([B],"readonly").objectStore(B).get(e);s.onsuccess=()=>{a(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),a(null)}}):null}async function ut(e){if(!w)return false;try{return e.size>Ye?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Ye/1024/1024).toFixed(2)}MB`),false):(await Ne(),U+e.size>ie&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await _e(),U+e.size>ie)?(console.warn("清理后仍会超过限制,跳过此图片"),false):M>=ue&&(console.warn("图片数量已达上限,执行清理"),await _e(),M>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).put(e);r.onsuccess=()=>{U+=e.size,M+=1,a(true)},r.onerror=()=>{console.error("保存图片到IndexedDB失败:",r.error),a(false)}}))}catch(a){return console.error("保存图片时出错:",a),false}}async function Re(e){return w?new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).delete(e);r.onsuccess=()=>{a(true)},r.onerror=()=>{console.error("从IndexedDB删除图片失败:",r.error),a(false)}}):false}async function Vt(e){return w?new Promise(a=>{const s=w.transaction([B],"readonly").objectStore(B).index("channelKey").getAll(e);s.onsuccess=()=>{a(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),a([])}}):[]}async function Oe(e,a){const t=b.value[a];if(t)return t;const n=await Jt(a);if(!n)return null;De();const r=URL.createObjectURL(n.blob);return b.value[a]=r,pe(Je(n.blob)),n.timestamp=Date.now(),await ut(n),r}async function le(e,a){try{const t=await Oe(e,a);if(t)return t;const n=await S("fetch-image",{url:a});if(!n.success)return console.error("获取图片失败:",n.error),null;const r=n.base64,s=n.contentType||"image/jpeg",o=atob(r),l=new Array(o.length);for(let $=0;$<o.length;$++)l[$]=o.charCodeAt($);const c=new Uint8Array(l),h=new Blob([c],{type:s});if(h.size>Ye)return console.warn(`图片过大,跳过缓存: ${(h.size/1024/1024).toFixed(2)}MB`),null;const y={url:a,blob:h,timestamp:Date.now(),size:h.size,channelKey:e};if(!await ut(y))return console.error("保存图片到IndexedDB失败"),null;De();const L=URL.createObjectURL(h);return b.value[a]=L,pe(Je(h)),L}catch(t){return console.error("缓存图片失败:",t),null}}async function $e(e){try{const a=await Vt(e);let t=0;for(const n of a)await Re(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],t+=n.size||0);t>0&&pe(-t)}catch(a){console.error("清理频道图片缓存失败:",a)}}function Gt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.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),(r=e.bot)!=null&&r.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(l=>l.id===e.messageId)){const l={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},c=u.value.messages[s];let h=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){h=g+1;break}g===0&&(h=0)}c.splice(h,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),K.value[s]=c.length;const y=je();oe(()=>{setTimeout(()=>{y&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}function Zt(e){const a=`${e.selfId}:${e.channelId}`;if(u.value.messages[a]||(u.value.messages[a]=[]),!u.value.messages[a].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},r=u.value.messages[a];let s=r.length;for(let l=r.length-1;l>=0;l--){if(r[l].timestamp<=e.timestamp){s=l+1;break}l===0&&(s=0)}r.splice(s,0,n),r.length>100&&(u.value.messages[a]=r.slice(-100)),K.value[a]=r.length;const o=je();oe(()=>{setTimeout(()=>{o&&re()},10)})}u.value={...u.value}}function Qt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.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),(r=e.bot)!=null&&r.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(l=>l.id===e.messageId)){const l={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},c=u.value.messages[s];let h=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){h=g+1;break}g===0&&(h=0)}c.splice(h,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),K.value[s]=c.length;const y=je();oe(()=>{setTimeout(()=>{y&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}dt(Ze,(e,a)=>{a.length===0&&e.length>0&&oe(()=>{re()})});async function Et(){try{const e=await S("get-chat-data");if(e.success&&e.data){const a={};X.value=new Set(e.data.pinnedBots||[]),Y.value=new Set(e.data.pinnedChannels||[]);for(const[t,n]of Object.entries(e.data.messages||{})){const r=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}));r.sort((s,o)=>s.timestamp-o.timestamp),a[t]=r}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:a},await ea(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function ea(){try{const e=await S("get-all-channel-message-counts");if(e.success&&e.counts){const a={};for(const[t,n]of Object.entries(e.counts))a[t]=n;K.value=a}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ta(){try{const e=await S("get-plugin-config");e.success&&e.config?fe.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function aa(e,a){try{const t=await S("get-history-messages",{selfId:e,channelId:a});if(t.success&&t.messages){const n=`${e}:${a}`,r=t.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 r.sort((s,o)=>s.timestamp-o.timestamp),u.value.messages[n]=r,K.value[n]=r.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",t.error),false}catch(t){return console.error("获取历史消息时出错:",t),false}}function na(e){if(!T.value||e.touches.length!==1)return;const a=e.touches[0];H.value={x:a.clientX,y:a.clientY,time:Date.now()},ae.value={x:a.clientX,y:a.clientY},Te.value=false}function sa(e){if(!T.value||!H.value||e.touches.length!==1)return;const a=e.touches[0];ae.value={x:a.clientX,y:a.clientY};const t=a.clientX-H.value.x,n=a.clientY-H.value.y;if(Math.abs(t)>Math.abs(n)&&Math.abs(t)>30){const r=t>0,s=V.value==="messages"||V.value==="channels";if(r&&s){Te.value=true;const o=Math.min(t,200),l=150;o>l?Z.value={show:true,text:"松开返回"}:Z.value={show:true,text:`滑动返回 ${Math.round(o/l*100)}%`},e.preventDefault()}else Z.value={show:false,text:""}}else Z.value={show:false,text:""}}function ra(e){if(!T.value||!H.value)return;const t=Date.now()-H.value.time;if(ae.value){const n=ae.value.x-H.value.x,r=ae.value.y-H.value.y,s=n>150,o=Math.abs(n)>Math.abs(r),l=t<300&&n>80;(s&&o||l)&&la()}H.value=null,ae.value=null,Te.value=false,Z.value={show:false,text:""}}function la(){switch(V.value){case"messages":V.value="channels";break;case"channels":V.value="bots",m.value="",k.value="";break}}function ze(){T.value=window.innerWidth<=768}return Pe(async()=>{ze(),window.addEventListener("resize",ze),document.addEventListener("click",nt),await Wt()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await Ne()},2e3),setInterval(async()=>{await Ne()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ta(),await Et();const a=Fe("chat-message-event",Gt),t=Fe("bot-message-sent-event",Zt),n=Fe("chat-bot-message-event",Qt);dt(k,r=>{r&&oe(()=>{D.value&&(D.value.removeEventListener("scroll",xe),D.value.addEventListener("scroll",xe),xe()),!T.value&&me.value&&me.value.focus()})},{immediate:true}),setInterval(()=>{De()},2*60*1e3),oa(()=>{window.removeEventListener("resize",ze),document.removeEventListener("click",nt),a&&typeof a=="function"&&a(),t&&typeof t=="function"&&t(),n&&typeof n=="function"&&n(),D.value&&D.value.removeEventListener("scroll",xe),Object.values(b.value).forEach(r=>{URL.revokeObjectURL(r)}),b.value={},w&&(w.close(),w=null)})}),(e,a)=>(v(),p("div",{class:W(["chat-container",kt.value]),style:Me(_t.value),onTouchstart:na,onTouchmove:sa,onTouchend:ra},[i("div",ha,[a[7]||(a[7]=i("div",{class:"panel-header"},[i("h3",null,"机器人")],-1)),i("div",ma,[(v(true),p(z,null,ce(wt.value,t=>(v(),p("div",{key:t.selfId,class:W(["bot-item",{active:m.value===t.selfId,pinned:X.value.has(t.selfId)}]),onClick:n=>$t(t.selfId),onContextmenu:n=>St(n,t.selfId)},[i("div",ga,[t.avatar?(v(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":"bot-list"},null,8,["src","alt"])):(v(),p("div",ya,C(t.username.charAt(0).toUpperCase()),1))]),i("div",pa,[i("div",wa,C(t.username),1),i("div",Ia,C(t.platform),1)]),i("div",{class:W(["bot-status",t.status])},null,2)],42,va))),128))])]),i("div",xa,[a[8]||(a[8]=i("div",{class:"panel-header"},[i("h3",null,"频道")],-1)),m.value?(v(),p("div",ka,[(v(true),p(z,null,ce(It.value,t=>(v(),p("div",{key:t.id,class:W(["channel-item",{active:k.value===t.id,pinned:Y.value.has(`${m.value}:${t.id}`)}]),"data-channel-id":t.id,onClick:n=>Kt(t.id),onContextmenu:n=>Bt(n,t.id)},[i("div",_a,[i("div",$a,C(t.name),1),i("div",Sa,C(zt(t.type)),1)]),Ae(t.id)>0?(v(),p("div",{key:0,class:W(["channel-message-count draggable-bubble",{dragging:F.value===t.id,"will-delete":F.value===t.id&<(t.id)>P}]),onMousedown:n=>rt(n,t.id),onTouchstart:n=>rt(n,t.id),style:Me(Pt(t.id)),title:F.value===t.id?lt(t.id)>P?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},C(Ae(t.id)),47,Ba)):Q("",true)],42,ba))),128))])):(v(),p("div",Ca," 请选择一个机器人 "))]),i("div",Da,[i("div",La,[i("h3",null,C(xt.value||"选择频道"),1)]),!m.value||!k.value?(v(),p("div",Ta," 请选择机器人和频道 ")):(v(),p("div",qa,[i("div",{class:"message-history",ref_key:"messageHistory",ref:D},[(v(true),p(z,null,ce(Ze.value,t=>(v(),p("div",{key:t.id,class:W(["message-item",{"bot-message":t.isBot}])},[i("div",Ka,[t.avatar?(v(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(v(),p("div",Ua,C(t.username.charAt(0).toUpperCase()),1))]),i("div",ja,[i("div",Aa,[i("span",Na,C(t.username),1),i("span",Ra,C(st(t.timestamp)),1)]),t.quote?(v(),p("div",Oa,[i("div",za,[i("div",Pa,[t.quote.user.avatar?(v(),ve(ge(te),{key:0,src:t.quote.user.avatar,alt:t.quote.user.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(v(),p("div",Ma,C(t.quote.user.username.charAt(0).toUpperCase()),1))]),i("span",Ha,C(t.quote.user.username),1),i("span",Fa,C(st(t.quote.timestamp)),1)]),i("div",Xa,[t.quote.elements&&t.quote.elements.length>0?(v(true),p(z,{key:0},ce(t.quote.elements,(n,r)=>(v(),ve(ge(ye),{key:`quote-${r}`,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(v(),p(z,{key:1},[He(C(t.quote.content),1)],64))])])):Q("",true),i("div",Ya,[t.elements&&t.elements.length>0?(v(true),p(z,{key:0},ce(t.elements,(n,r)=>(v(),ve(ge(ye),{key:r,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(v(),p(z,{key:1},[He(C(t.content),1)],64))])])],2))),128))],512),ft(i("div",{class:"floating-scroll-button",onClick:re},a[9]||(a[9]=[i("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[i("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[ca,qe.value]]),i("div",Wa,[j.value.length>0?(v(),p("div",Ja,[(v(true),p(z,null,ce(j.value,t=>(v(),p("div",{key:t.tempId,class:"image-preview-item"},[i("img",{src:t.preview,alt:t.filename,class:"preview-image"},null,8,Va),i("button",{class:"remove-image-btn",onClick:n=>Rt(t.tempId),title:"删除图片"},a[10]||(a[10]=[i("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[i("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,Ga)]))),128))])):Q("",true),i("div",Za,[i("div",Qa,[i("button",{class:W(["add-button",{active:G.value}]),onClick:Ut,title:"更多操作"},a[11]||(a[11]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[i("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),i("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),G.value?(v(),p("div",{key:0,class:"action-menu",onClick:a[0]||(a[0]=ht(()=>{},["stop"]))},[i("button",{class:"action-menu-item",onClick:jt},a[12]||(a[12]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[i("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),i("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),i("polyline",{points:"21,15 16,10 5,21"})],-1),He(" 上传图片 ",-1)]))])):Q("",true)]),ft(i("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>he.value=t),type:"text",placeholder:bt.value,onKeyup:ia(tt,["enter"]),disabled:!Ct.value,ref_key:"messageInput",ref:me,onPaste:Nt},null,40,Ea),[[ua,he.value]]),i("button",{onClick:tt,disabled:!Qe.value,class:W({"is-sending":ne.value})},C(ne.value?"发送中...":"发送"),11,en)]),i("input",{type:"file",ref_key:"fileInput",ref:Le,onChange:At,accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),x.value.show?(v(),p("div",{key:0,class:"context-menu",style:Me({left:x.value.x+"px",top:x.value.y+"px"}),onClick:a[6]||(a[6]=ht(()=>{},["stop"]))},[x.value.type==="bot"?(v(),p(z,{key:0},[i("div",{class:"context-menu-item",onClick:a[2]||(a[2]=t=>Dt(x.value.targetId))},C(X.value.has(x.value.targetId)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[3]||(a[3]=t=>Tt(x.value.targetId))}," 彻底删除此机器人所有数据 ")],64)):Q("",true),x.value.type==="channel"?(v(),p(z,{key:1},[i("div",{class:"context-menu-item",onClick:a[4]||(a[4]=t=>Lt(x.value.targetId))},C(Y.value.has(`${m.value}:${x.value.targetId}`)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[5]||(a[5]=t=>qt(x.value.targetId))}," 彻底删除此频道所有数据 ")],64)):Q("",true)],4)):Q("",true),i("div",{class:W(["swipe-indicator",{show:Z.value.show}])},C(Z.value.text),3)],38))}}),yt=(ee,J)=>{const te=ee.__vccOpts||ee;for(const[de,Se]of J)te[de]=Se;return te},rn=yt(sn,[["__scopeId","data-v-fbeb5b9c"]]),ln={},on={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function cn(ee,J){return v(),p("svg",on,J[0]||(J[0]=[i("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("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 un=yt(ln,[["render",cn]]);fa.register("activity:chat",un);const hn=ee=>{ee.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:E({setup(){return()=>d(da("k-layout"),{},{default:()=>d(rn)})}})})};export{hn as default};
|
|
27
|
+
`,document.body.appendChild(t),window.dragThresholdCircle=t}function Ft(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function Ne(){try{if(!w)return false;const e=Date.now();if(e-We<nn)return true;We=e;const a=await ot();K=a.totalSize,M=a.totalImages,console.log("数据库健康检查:",{大小:`${(K/1024/1024).toFixed(2)}MB / ${(ie/1024/1024).toFixed(2)}MB`,图片数量:`${M} / ${ue}`,使用率:`${(K/ie*100).toFixed(1)}%`});const t=K/ie,n=M/ue;return(t>gt||n>gt)&&(console.warn("数据库使用率过高,开始自动清理"),await _e()),(t>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Xt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function ot(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{const r=n.result||[];let s=0;const o={};r.forEach(l=>{s+=l.size||0,o[l.channelKey]=(o[l.channelKey]||0)+1}),e({totalSize:s,totalImages:r.length,channelStats:o})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function _e(){try{console.log("开始自动清理...");const e=await ct();if(e.length===0)return;const a={};e.forEach(r=>{a[r.channelKey]||(a[r.channelKey]=[]),a[r.channelKey].push(r)});let t=0,n=0;for(const[r,s]of Object.entries(a))if(s.length>vt){s.sort((l,c)=>l.timestamp-c.timestamp);const o=s.slice(0,s.length-vt);for(const l of o)await Oe(l.url),t++,n+=l.size||0,b.value[l.url]&&(URL.revokeObjectURL(b.value[l.url]),delete b.value[l.url])}console.log(`自动清理完成: 清理了 ${t} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),M-=t,K-=n}catch(e){console.error("自动清理失败:",e)}}async function Xt(){try{console.log("开始紧急清理...");const e=await ct();if(e.length===0)return;e.sort((s,o)=>o.timestamp-s.timestamp);const a=Math.floor(ue*.3),t=e.slice(a);let n=0,r=0;for(const s of t)await Oe(s.url),n++,r+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(r/1024/1024).toFixed(2)}MB`),M=a,K-=r}catch(e){console.error("紧急清理失败:",e)}}async function ct(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Yt(){return new Promise(e=>{try{w&&(w.close(),w=null);const a=indexedDB.deleteDatabase(mt);a.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),K=0,M=0,e(true)},a.onerror=()=>{console.error("清理IndexedDB数据库失败:",a.error),e(false)},a.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(a){console.error("清理数据库时出错:",a),e(false)}})}async function Wt(){try{return await it()?(setTimeout(async()=>{const a=await ot();console.log("数据库初始状态:",{大小:`${(a.totalSize/1024/1024).toFixed(2)}MB`,图片数量:a.totalImages,频道分布:a.channelStats}),(a.totalSize>ie*.9||a.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await _e())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Yt(),await it())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function it(){return new Promise(e=>{try{const a=indexedDB.open(mt,an);a.onerror=()=>{console.error("IndexedDB打开失败:",a.error),e(false)},a.onsuccess=()=>{w=a.result,w.onerror=t=>{console.error("IndexedDB运行时错误:",t)},w.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),w==null||w.close(),w=null},e(true)},a.onupgradeneeded=t=>{const n=t.target.result;if(!n.objectStoreNames.contains(B)){const r=n.createObjectStore(B,{keyPath:"url"});r.createIndex("channelKey","channelKey",{unique:false}),r.createIndex("timestamp","timestamp",{unique:false}),r.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},a.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(a){console.error("打开数据库时出错:",a),e(false)}})}async function Jt(e){return w?new Promise((a,t)=>{const s=w.transaction([B],"readonly").objectStore(B).get(e);s.onsuccess=()=>{a(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),a(null)}}):null}async function ut(e){if(!w)return false;try{return e.size>Ye?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Ye/1024/1024).toFixed(2)}MB`),false):(await Ne(),K+e.size>ie&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await _e(),K+e.size>ie)?(console.warn("清理后仍会超过限制,跳过此图片"),false):M>=ue&&(console.warn("图片数量已达上限,执行清理"),await _e(),M>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).put(e);r.onsuccess=()=>{K+=e.size,M+=1,a(true)},r.onerror=()=>{console.error("保存图片到IndexedDB失败:",r.error),a(false)}}))}catch(a){return console.error("保存图片时出错:",a),false}}async function Oe(e){return w?new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).delete(e);r.onsuccess=()=>{a(true)},r.onerror=()=>{console.error("从IndexedDB删除图片失败:",r.error),a(false)}}):false}async function Vt(e){return w?new Promise(a=>{const s=w.transaction([B],"readonly").objectStore(B).index("channelKey").getAll(e);s.onsuccess=()=>{a(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),a([])}}):[]}async function Re(e,a){const t=b.value[a];if(t)return t;const n=await Jt(a);if(!n)return null;De();const r=URL.createObjectURL(n.blob);return b.value[a]=r,pe(Je(n.blob)),n.timestamp=Date.now(),await ut(n),r}async function le(e,a){try{const t=await Re(e,a);if(t)return t;const n=await S("fetch-image",{url:a});if(!n.success)return console.error("获取图片失败:",n.error),null;const r=n.base64,s=n.contentType||"image/jpeg",o=atob(r),l=new Array(o.length);for(let $=0;$<o.length;$++)l[$]=o.charCodeAt($);const c=new Uint8Array(l),v=new Blob([c],{type:s});if(v.size>Ye)return console.warn(`图片过大,跳过缓存: ${(v.size/1024/1024).toFixed(2)}MB`),null;const p={url:a,blob:v,timestamp:Date.now(),size:v.size,channelKey:e};if(!await ut(p))return console.error("保存图片到IndexedDB失败"),null;De();const T=URL.createObjectURL(v);return b.value[a]=T,pe(Je(v)),T}catch(t){return console.error("缓存图片失败:",t),null}}async function $e(e){try{const a=await Vt(e);let t=0;for(const n of a)await Oe(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],t+=n.size||0);t>0&&pe(-t)}catch(a){console.error("清理频道图片缓存失败:",a)}}function Gt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.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),(r=e.bot)!=null&&r.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(l=>l.id===e.messageId)){const l={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},c=u.value.messages[s];let v=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){v=g+1;break}g===0&&(v=0)}c.splice(v,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),U.value[s]=c.length;const p=je();oe(()=>{setTimeout(()=>{p&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}function Zt(e){const a=`${e.selfId}:${e.channelId}`;if(u.value.messages[a]||(u.value.messages[a]=[]),!u.value.messages[a].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},r=u.value.messages[a];let s=r.length;for(let l=r.length-1;l>=0;l--){if(r[l].timestamp<=e.timestamp){s=l+1;break}l===0&&(s=0)}r.splice(s,0,n),r.length>100&&(u.value.messages[a]=r.slice(-100)),U.value[a]=r.length;const o=je();oe(()=>{setTimeout(()=>{o&&re()},10)})}u.value={...u.value}}function Qt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.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),(r=e.bot)!=null&&r.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(l=>l.id===e.messageId)){const l={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},c=u.value.messages[s];let v=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){v=g+1;break}g===0&&(v=0)}c.splice(v,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),U.value[s]=c.length;const p=je();oe(()=>{setTimeout(()=>{p&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}dt(Ze,(e,a)=>{a.length===0&&e.length>0&&oe(()=>{re()})});async function Et(){try{const e=await S("get-chat-data");if(e.success&&e.data){const a={};X.value=new Set(e.data.pinnedBots||[]),Y.value=new Set(e.data.pinnedChannels||[]);for(const[t,n]of Object.entries(e.data.messages||{})){const r=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}));r.sort((s,o)=>s.timestamp-o.timestamp),a[t]=r}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:a},await ea(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function ea(){try{const e=await S("get-all-channel-message-counts");if(e.success&&e.counts){const a={};for(const[t,n]of Object.entries(e.counts))a[t]=n;U.value=a}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ta(){try{const e=await S("get-plugin-config");e.success&&e.config?fe.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function aa(e,a){try{const t=await S("get-history-messages",{selfId:e,channelId:a});if(t.success&&t.messages){const n=`${e}:${a}`,r=t.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 r.sort((s,o)=>s.timestamp-o.timestamp),u.value.messages[n]=r,U.value[n]=r.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",t.error),false}catch(t){return console.error("获取历史消息时出错:",t),false}}function na(e){if(!L.value||e.touches.length!==1)return;const a=e.touches[0];H.value={x:a.clientX,y:a.clientY,time:Date.now()},ae.value={x:a.clientX,y:a.clientY},Le.value=false}function sa(e){if(!L.value||!H.value||e.touches.length!==1)return;const a=e.touches[0];ae.value={x:a.clientX,y:a.clientY};const t=a.clientX-H.value.x,n=a.clientY-H.value.y;if(Math.abs(t)>Math.abs(n)&&Math.abs(t)>30){const r=t>0,s=J.value==="messages"||J.value==="channels";if(r&&s){Le.value=true;const o=Math.min(t,200),l=150;o>l?G.value={show:true,text:"松开返回"}:G.value={show:true,text:`滑动返回 ${Math.round(o/l*100)}%`},e.preventDefault()}else G.value={show:false,text:""}}else G.value={show:false,text:""}}function ra(e){if(!L.value||!H.value)return;const t=Date.now()-H.value.time;if(ae.value){const n=ae.value.x-H.value.x,r=ae.value.y-H.value.y,s=n>150,o=Math.abs(n)>Math.abs(r),l=t<300&&n>80;(s&&o||l)&&la()}H.value=null,ae.value=null,Le.value=false,G.value={show:false,text:""}}function la(){switch(J.value){case"messages":J.value="channels";break;case"channels":J.value="bots",h.value="",k.value="";break}}function ze(){L.value=window.innerWidth<=768}return Pe(async()=>{ze(),window.addEventListener("resize",ze),document.addEventListener("click",nt),await Wt()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await Ne()},2e3),setInterval(async()=>{await Ne()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ta(),await Et();const a=Fe("chat-message-event",Gt),t=Fe("bot-message-sent-event",Zt),n=Fe("chat-bot-message-event",Qt);dt(k,r=>{r&&oe(()=>{D.value&&(D.value.removeEventListener("scroll",xe),D.value.addEventListener("scroll",xe),xe()),!L.value&&me.value&&me.value.focus()})},{immediate:true}),setInterval(()=>{De()},2*60*1e3),oa(()=>{window.removeEventListener("resize",ze),document.removeEventListener("click",nt),a&&typeof a=="function"&&a(),t&&typeof t=="function"&&t(),n&&typeof n=="function"&&n(),D.value&&D.value.removeEventListener("scroll",xe),Object.values(b.value).forEach(r=>{URL.revokeObjectURL(r)}),b.value={},w&&(w.close(),w=null)})}),(e,a)=>(m(),y("div",{class:W(["chat-container",kt.value]),style:Me(_t.value),onTouchstart:na,onTouchmove:sa,onTouchend:ra},[i("div",ha,[a[7]||(a[7]=i("div",{class:"panel-header"},[i("h3",null,"机器人")],-1)),i("div",ma,[(m(true),y(z,null,ce(wt.value,t=>(m(),y("div",{key:t.selfId,class:W(["bot-item",{active:h.value===t.selfId,pinned:X.value.has(t.selfId)}]),onClick:n=>$t(t.selfId),onContextmenu:n=>St(n,t.selfId)},[i("div",ga,[t.avatar?(m(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":"bot-list"},null,8,["src","alt"])):(m(),y("div",ya,C(t.username.charAt(0).toUpperCase()),1))]),i("div",pa,[i("div",wa,C(t.username),1),i("div",Ia,C(t.platform),1)]),i("div",{class:W(["bot-status",t.status])},null,2)],42,va))),128))])]),i("div",xa,[a[8]||(a[8]=i("div",{class:"panel-header"},[i("h3",null,"频道")],-1)),h.value?(m(),y("div",ka,[(m(true),y(z,null,ce(It.value,t=>(m(),y("div",{key:t.id,class:W(["channel-item",{active:k.value===t.id,pinned:Y.value.has(`${h.value}:${t.id}`)}]),"data-channel-id":t.id,onClick:n=>Ut(t.id),onContextmenu:n=>Bt(n,t.id)},[i("div",_a,[i("div",$a,C(t.name),1),i("div",Sa,C(zt(t.type)),1)]),Ae(t.id)>0?(m(),y("div",{key:0,class:W(["channel-message-count draggable-bubble",{dragging:F.value===t.id,"will-delete":F.value===t.id&<(t.id)>P}]),onMousedown:n=>rt(n,t.id),onTouchstart:n=>rt(n,t.id),style:Me(Pt(t.id)),title:F.value===t.id?lt(t.id)>P?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},C(Ae(t.id)),47,Ba)):Z("",true)],42,ba))),128))])):(m(),y("div",Ca," 请选择一个机器人 "))]),i("div",Da,[i("div",Ta,[i("h3",null,C(xt.value||"选择频道"),1)]),!h.value||!k.value?(m(),y("div",La," 请选择机器人和频道 ")):(m(),y("div",qa,[i("div",{class:"message-history",ref_key:"messageHistory",ref:D},[(m(true),y(z,null,ce(Ze.value,t=>(m(),y("div",{key:t.id,class:W(["message-item",{"bot-message":t.isBot}])},[i("div",Ua,[t.avatar?(m(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(m(),y("div",Ka,C(t.username.charAt(0).toUpperCase()),1))]),i("div",ja,[i("div",Aa,[i("span",Na,C(t.username),1),i("span",Oa,C(st(t.timestamp)),1)]),t.quote?(m(),y("div",Ra,[i("div",za,[i("div",Pa,[t.quote.user.avatar?(m(),ve(ge(te),{key:0,src:t.quote.user.avatar,alt:t.quote.user.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(m(),y("div",Ma,C(t.quote.user.username.charAt(0).toUpperCase()),1))]),i("span",Ha,C(t.quote.user.username),1),i("span",Fa,C(st(t.quote.timestamp)),1)]),i("div",Xa,[t.quote.elements&&t.quote.elements.length>0?(m(true),y(z,{key:0},ce(t.quote.elements,(n,r)=>(m(),ve(ge(ye),{key:`quote-${r}`,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(m(),y(z,{key:1},[He(C(t.quote.content),1)],64))])])):Z("",true),i("div",Ya,[t.elements&&t.elements.length>0?(m(true),y(z,{key:0},ce(t.elements,(n,r)=>(m(),ve(ge(ye),{key:r,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(m(),y(z,{key:1},[He(C(t.content),1)],64))])])],2))),128))],512),ft(i("div",{class:"floating-scroll-button",onClick:re},a[9]||(a[9]=[i("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[i("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[ca,qe.value]]),i("div",Wa,[j.value.length>0?(m(),y("div",Ja,[(m(true),y(z,null,ce(j.value,t=>(m(),y("div",{key:t.tempId,class:"image-preview-item"},[i("img",{src:t.preview,alt:t.filename,class:"preview-image"},null,8,Va),i("button",{class:"remove-image-btn",onClick:n=>Ot(t.tempId),title:"删除图片"},a[10]||(a[10]=[i("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[i("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,Ga)]))),128))])):Z("",true),i("div",Za,[i("div",Qa,[i("button",{class:W(["add-button",{active:V.value}]),onClick:Kt,title:"更多操作"},a[11]||(a[11]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[i("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),i("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),V.value?(m(),y("div",{key:0,class:"action-menu",onClick:a[0]||(a[0]=ht(()=>{},["stop"]))},[i("button",{class:"action-menu-item",onClick:jt},a[12]||(a[12]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[i("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),i("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),i("polyline",{points:"21,15 16,10 5,21"})],-1),He(" 上传图片 ",-1)]))])):Z("",true)]),ft(i("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>he.value=t),type:"text",placeholder:bt.value,onKeyup:ia(tt,["enter"]),disabled:!Ct.value,ref_key:"messageInput",ref:me,onPaste:Nt},null,40,Ea),[[ua,he.value]]),i("button",{onClick:tt,disabled:!Qe.value,class:W({"is-sending":ne.value})},C(ne.value?"发送中...":"发送"),11,en)]),i("input",{type:"file",ref_key:"fileInput",ref:Te,onChange:At,accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),x.value.show?(m(),y("div",{key:0,class:"context-menu",style:Me({left:x.value.x+"px",top:x.value.y+"px"}),onClick:a[6]||(a[6]=ht(()=>{},["stop"]))},[x.value.type==="bot"?(m(),y(z,{key:0},[i("div",{class:"context-menu-item",onClick:a[2]||(a[2]=t=>Dt(x.value.targetId))},C(X.value.has(x.value.targetId)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[3]||(a[3]=t=>Lt(x.value.targetId))}," 彻底删除此机器人所有数据 ")],64)):Z("",true),x.value.type==="channel"?(m(),y(z,{key:1},[i("div",{class:"context-menu-item",onClick:a[4]||(a[4]=t=>Tt(x.value.targetId))},C(Y.value.has(`${h.value}:${x.value.targetId}`)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[5]||(a[5]=t=>qt(x.value.targetId))}," 彻底删除此频道所有数据 ")],64)):Z("",true)],4)):Z("",true),i("div",{class:W(["swipe-indicator",{show:G.value.show}])},C(G.value.text),3)],38))}}),yt=(E,ee)=>{const te=E.__vccOpts||E;for(const[de,Se]of ee)te[de]=Se;return te},rn=yt(sn,[["__scopeId","data-v-323dce07"]]),ln={},on={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function cn(E,ee){return m(),y("svg",on,ee[0]||(ee[0]=[i("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("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 un=yt(ln,[["render",cn]]);fa.register("activity:chat",un);const hn=E=>{E.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Q({setup(){return()=>d(da("k-layout"),{},{default:()=>d(rn)})}})})};export{hn as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.message-quote[data-v-fbeb5b9c]{margin:8px 0;padding:8px 12px;background-color:#bebebe1a;border-left:4px solid rgba(151,152,152,.45);border-radius:6px;font-size:.9em;position:relative}.quote-indicator[data-v-fbeb5b9c]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-fbeb5b9c]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-fbeb5b9c]{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#6c757d;color:#fff;font-size:10px;font-weight:700}.quote-username[data-v-fbeb5b9c]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-fbeb5b9c]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-fbeb5b9c]{color:#7276b7;line-height:1.3;word-wrap:break-word}.quote-content .message-image[data-v-fbeb5b9c]{max-width:200px;max-height:100px}.quote-content .message-image-container[data-v-fbeb5b9c]{margin:2px 0}@media (prefers-color-scheme: dark){.message-quote[data-v-fbeb5b9c]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-fbeb5b9c]{color:#adb5bd}.quote-username[data-v-fbeb5b9c]{color:#0d6efd}}.chat-container[data-v-fbeb5b9c]{display:flex;height:100vh;background:transparent;margin-left:0%;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-fbeb5b9c],.channel-list[data-v-fbeb5b9c],.message-area[data-v-fbeb5b9c]{display:flex;flex-direction:column;background:transparent;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-fbeb5b9c]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-fbeb5b9c]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-fbeb5b9c]{flex:1;border-right:none}.panel-header[data-v-fbeb5b9c]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:transparent;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-fbeb5b9c]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-fbeb5b9c]{display:none;background:none;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-fbeb5b9c]:hover{background:#8080801a}.bot-items[data-v-fbeb5b9c],.channel-items[data-v-fbeb5b9c]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-fbeb5b9c],.channel-item[data-v-fbeb5b9c]{display:flex;align-items:center;padding:12px 16px;cursor:pointer;border-bottom:1px solid rgba(128,128,128,.1);transition:background-color .2s}.bot-item[data-v-fbeb5b9c]:hover,.channel-item[data-v-fbeb5b9c]:hover{background:#8080801a}.bot-item.active[data-v-fbeb5b9c],.channel-item.active[data-v-fbeb5b9c]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-fbeb5b9c]{width:40px;height:40px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0}.bot-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-fbeb5b9c]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-fbeb5b9c]{flex:1}.bot-name[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-fbeb5b9c]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-fbeb5b9c]{background:#4caf50}.bot-status.offline[data-v-fbeb5b9c]{background:#f44336}.channel-info[data-v-fbeb5b9c]{flex:1}.channel-name[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-fbeb5b9c]{background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;position:relative;transition:all .2s ease}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]:active,.channel-message-count.draggable-bubble.dragging[data-v-fbeb5b9c]{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-fbeb5b9c]{position:fixed;z-index:1000;pointer-events:none;transition:none;box-sizing:border-box;display:flex;align-items:center;justify-content:center;background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;box-shadow:0 4px 12px #2196f366}.dragging-clone.will-delete[data-v-fbeb5b9c]{background:#f44336!important;animation:shake-fbeb5b9c .3s ease-in-out infinite}@keyframes pulseThreshold-fbeb5b9c{0%,to{opacity:.4;transform:scale(.9);border-color:#f4433699;box-shadow:0 0 15px #f4433633}50%{opacity:.8;transform:scale(1.1);border-color:#f44336;box-shadow:0 0 25px #f4433666}}@keyframes menuSlideIn-fbeb5b9c{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-fbeb5b9c]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-fbeb5b9c]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-fbeb5b9c]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-fbeb5b9c]:hover{background-color:#8080801a}.message-item.new-message[data-v-fbeb5b9c]{background-color:#4caf5033;animation:highlight-fbeb5b9c 2s ease-out}.message-item.bot-message[data-v-fbeb5b9c]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-fbeb5b9c]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-fbeb5b9c]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-fbeb5b9c]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-fbeb5b9c]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-fbeb5b9c]{order:1}.message-item.bot-message .message-text[data-v-fbeb5b9c]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left}@keyframes highlight-fbeb5b9c{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-fbeb5b9c]{width:32px;height:32px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0;flex-shrink:0}.message-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-fbeb5b9c]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-fbeb5b9c]{flex:1}.message-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-fbeb5b9c]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;max-width:100%;overflow-wrap:break-word}.message-item:not(.bot-message) .message-text[data-v-fbeb5b9c]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%}.message-input[data-v-fbeb5b9c]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:transparent;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-fbeb5b9c]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-fbeb5b9c]{position:absolute;right:24px;bottom:18%;width:48px;height:48px;background:#2196f3;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px #2196f34d;color:#fff;transition:all .3s ease;z-index:100;border:2px solid rgba(255,255,255,.2)}.floating-scroll-button[data-v-fbeb5b9c]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-fbeb5b9c]:active{transform:scale(.95)}.input-row button[data-v-fbeb5b9c]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-fbeb5b9c]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-fbeb5b9c]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease}.message-image-loading[data-v-fbeb5b9c]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-fbeb5b9c]{display:inline-block;padding:8px 12px;background:#f443361a;border:1px solid rgba(244,67,54,.3);border-radius:4px;color:#f44336;font-size:12px;max-width:300px;word-break:break-word}.message-paragraph[data-v-fbeb5b9c]{display:block;margin-bottom:4px}.message-paragraph[data-v-fbeb5b9c]:last-child{margin-bottom:0}.forward-message-container[data-v-fbeb5b9c]{border:1px solid #ffffff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-fbeb5b9c]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-fbeb5b9c]:hover{background:#f0f0f0}.forward-message-title[data-v-fbeb5b9c]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-fbeb5b9c]{color:#666;font-size:13px;margin:2px 0;line-height:1.4}.forward-message-footer[data-v-fbeb5b9c]{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px solid #e8e8e8}.forward-message-count[data-v-fbeb5b9c]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-fbeb5b9c]{color:#666;font-size:12px}.forward-message-expanded[data-v-fbeb5b9c]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-fbeb5b9c]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-fbeb5b9c]:last-child{border-bottom:none}.forwarded-message-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-fbeb5b9c]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-fbeb5b9c]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-fbeb5b9c]{color:#555;font-size:13px;line-height:1.4}.message-at[data-v-fbeb5b9c]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-fbeb5b9c]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-fbeb5b9c]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:none;background:transparent;color:currentColor}.input-row input[data-v-fbeb5b9c]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-fbeb5b9c]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-fbeb5b9c]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;flex-shrink:0;white-space:nowrap}.input-row button[data-v-fbeb5b9c]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-fbeb5b9c]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-fbeb5b9c]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-fbeb5b9c]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-fbeb5b9c]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-fbeb5b9c]{display:inline}.message-image-container[data-v-fbeb5b9c]{display:block;margin:4px 0}.message-image[data-v-fbeb5b9c]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-fbeb5b9c]:hover{transform:scale(1.02)}.message-image-loading[data-v-fbeb5b9c]{height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3)}.message-image-error[data-v-fbeb5b9c]{min-height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3);padding:8px;text-align:center}.message-at[data-v-fbeb5b9c]{background:#2196f31a;color:#2196f3;padding:2px 6px;border-radius:4px;font-weight:500;cursor:pointer;display:inline-block;margin:0 2px}.message-at[data-v-fbeb5b9c]:hover{background:#2196f333}.message-unknown[data-v-fbeb5b9c]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-fbeb5b9c{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-fbeb5b9c]{background:#f44336!important;animation:shake-fbeb5b9c .3s ease-in-out infinite}@keyframes shake-fbeb5b9c{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-fbeb5b9c]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-fbeb5b9c]{position:fixed;pointer-events:none;border:3px dashed rgba(244,67,54,.8);border-radius:50%;z-index:999;background:#f443361a;box-shadow:0 0 20px #f443364d;animation:pulseThreshold-fbeb5b9c 1.5s ease-in-out infinite}.context-menu[data-v-fbeb5b9c]{position:fixed;background:#ffffffa6;border:1px solid rgba(0,0,0,.1);border-radius:8px;box-shadow:0 8px 32px #00000026;z-index:10000;min-width:180px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);overflow:hidden}.context-menu-item[data-v-fbeb5b9c]{padding:12px 16px;cursor:pointer;color:#333;font-size:14px;font-weight:500;transition:all .2s ease;border-bottom:1px solid rgba(0,0,0,.08);position:relative}.context-menu-item[data-v-fbeb5b9c]:last-child{border-bottom:none}.context-menu-item[data-v-fbeb5b9c]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-fbeb5b9c]{color:#d32f2f}.context-menu-item.danger[data-v-fbeb5b9c]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-fbeb5b9c]:before,.channel-item.pinned[data-v-fbeb5b9c]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{position:relative;padding-left:24px}@media (prefers-color-scheme: dark){.context-menu[data-v-fbeb5b9c]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-fbeb5b9c]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-fbeb5b9c]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-fbeb5b9c]{color:#ff8a80}.context-menu-item.danger[data-v-fbeb5b9c]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{background:#ffc10726}}.message-share-card[data-v-fbeb5b9c]{display:inline-block;width:75px;margin:8px 0;border:1px solid rgba(128,128,128,.2);border-radius:12px;background:#ffffff0d;transition:all .3s ease;cursor:pointer;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.message-share-card[data-v-fbeb5b9c]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-fbeb5b9c]{width:100%;position:relative;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:12px 12px 0 0}.share-card-image[data-v-fbeb5b9c]{max-width:calc(100% - 8px);width:auto;height:auto;object-fit:contain;transition:transform .3s ease;display:block;border-radius:4px}.message-share-card:hover .share-card-image[data-v-fbeb5b9c]{transform:scale(1.05)}.share-card-content[data-v-fbeb5b9c]{padding:8px}.share-card-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-fbeb5b9c]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-fbeb5b9c]{flex:1;min-width:0}.share-card-app-name[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-fbeb5b9c]{font-size:10px;font-weight:600;color:currentColor;line-height:1.2;word-wrap:break-word;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}.share-card-desc[data-v-fbeb5b9c]{font-size:14px;color:currentColor;opacity:.8;line-height:1.4;margin-bottom:12px;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;word-wrap:break-word}.share-card-link-hint[data-v-fbeb5b9c]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-fbeb5b9c]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-fbeb5b9c]:after{transform:translate(2px)}.message-json-error[data-v-fbeb5b9c],.message-json-raw[data-v-fbeb5b9c]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-fbeb5b9c]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-fbeb5b9c]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-fbeb5b9c]{margin-top:8px}.json-raw-data summary[data-v-fbeb5b9c]{cursor:pointer;font-size:12px;color:#2196f3;font-weight:500;padding:4px 8px;border-radius:4px;background:#2196f31a;display:inline-block;transition:background-color .2s ease}.json-raw-data summary[data-v-fbeb5b9c]:hover{background:#2196f333}.json-raw-content[data-v-fbeb5b9c]{margin-top:8px;padding:12px;background:#8080801a;border-radius:8px;font-family:Courier New,monospace;font-size:12px;color:currentColor;opacity:.8;white-space:pre-wrap;word-wrap:break-word;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme: dark){.message-share-card[data-v-fbeb5b9c]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-fbeb5b9c]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-fbeb5b9c]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width: 768px){.chat-container[data-v-fbeb5b9c]{position:relative}.bot-list[data-v-fbeb5b9c],.channel-list[data-v-fbeb5b9c],.message-area[data-v-fbeb5b9c]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.channel-list[data-v-fbeb5b9c]{transform:translate(100%);z-index:2}.message-area[data-v-fbeb5b9c]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-fbeb5b9c]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-fbeb5b9c]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-fbeb5b9c]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-fbeb5b9c]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.back-button[data-v-fbeb5b9c]{display:none!important}.panel-header[data-v-fbeb5b9c]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-fbeb5b9c]{text-align:right}.floating-scroll-button[data-v-fbeb5b9c]{right:16px;bottom:70px;width:40px;height:40px}.message-input[data-v-fbeb5b9c]{padding:8px 12px 12px;position:fixed;bottom:0;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10}.input-row input[data-v-fbeb5b9c]{font-size:16px;padding:10px 12px}.input-row button[data-v-fbeb5b9c]{padding:10px 16px;font-size:16px}.message-history[data-v-fbeb5b9c]{padding:12px 12px 80px;max-height:calc(100vh - 140px)}.message-item[data-v-fbeb5b9c]{margin-bottom:12px;padding:6px}.message-avatar[data-v-fbeb5b9c]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-fbeb5b9c]{margin-left:8px}.message-image[data-v-fbeb5b9c]{max-width:280px;max-height:160px}.quote-content .message-image[data-v-fbeb5b9c]{max-width:150px;max-height:80px}.context-menu[data-v-fbeb5b9c]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-fbeb5b9c]{padding:14px 16px;font-size:16px}.bot-item[data-v-fbeb5b9c],.channel-item[data-v-fbeb5b9c]{padding:14px 16px}.bot-avatar[data-v-fbeb5b9c]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-fbeb5b9c],.channel-name[data-v-fbeb5b9c]{font-size:15px}.bot-platform[data-v-fbeb5b9c],.channel-type[data-v-fbeb5b9c]{font-size:13px}}@media (min-width: 769px) and (max-width: 1024px){.bot-list[data-v-fbeb5b9c]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-fbeb5b9c]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-fbeb5b9c]{max-width:350px;max-height:180px}}.chat-container.swiping[data-v-fbeb5b9c]{overflow:hidden}.bot-list.swiping[data-v-fbeb5b9c],.channel-list.swiping[data-v-fbeb5b9c],.message-area.swiping[data-v-fbeb5b9c]{transition:none!important}.swipe-indicator[data-v-fbeb5b9c]{position:fixed;top:50%;left:20px;transform:translateY(-50%);background:#2196f3cc;color:#fff;padding:8px 12px;border-radius:20px;font-size:14px;z-index:1000;opacity:0;transition:opacity .2s ease;pointer-events:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.swipe-indicator.show[data-v-fbeb5b9c]{opacity:1}.message-area .message-content[data-v-fbeb5b9c]{padding-bottom:80px}.image-preview-container[data-v-fbeb5b9c]{display:flex;flex-wrap:wrap;gap:8px;padding:8px 0;margin-bottom:8px;border-bottom:1px solid rgba(128,128,128,.1)}.image-preview-item[data-v-fbeb5b9c]{position:relative;width:60px;height:60px;border-radius:8px;overflow:hidden;border:2px solid rgba(33,150,243,.3);background:#8080801a}.preview-image[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-fbeb5b9c]{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;background:#f44336;color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;transition:all .2s ease;box-shadow:0 2px 4px #0003}.remove-image-btn[data-v-fbeb5b9c]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-fbeb5b9c]{position:relative;margin-right:8px}.add-button[data-v-fbeb5b9c]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea,#764ba2);border:none;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;box-shadow:0 2px 8px #667eea4d;position:relative;overflow:hidden}.add-button[data-v-fbeb5b9c]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-fbeb5b9c]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-fbeb5b9c]:hover:before{opacity:1}.add-button.active[data-v-fbeb5b9c]{background:linear-gradient(135deg,#f093fb,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-fbeb5b9c]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-fbeb5b9c]{position:absolute;bottom:100%;left:0;margin-bottom:12px;background:#fffffffa;border:none;border-radius:16px;box-shadow:0 8px 32px #0000001f,0 2px 8px #00000014;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);overflow:hidden;z-index:1000;min-width:140px;transform:translateY(8px);opacity:0;animation:menuSlideIn-fbeb5b9c .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-fbeb5b9c]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:none;border:none;color:#333;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);width:100%;text-align:left;position:relative}.action-menu-item[data-v-fbeb5b9c]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-fbeb5b9c]:hover{background:linear-gradient(90deg,#667eea14,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-fbeb5b9c]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-fbeb5b9c]{flex-shrink:0}@media (prefers-color-scheme: dark){.action-menu[data-v-fbeb5b9c]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-fbeb5b9c]{color:#fff}.action-menu-item[data-v-fbeb5b9c]:before{background:linear-gradient(135deg,#4facfe,#00f2fe)}.action-menu-item[data-v-fbeb5b9c]:hover{background:linear-gradient(90deg,#4facfe1f,#00f2fe1f);color:#4facfe}.add-button[data-v-fbeb5b9c]{background:linear-gradient(135deg,#4facfe,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-fbeb5b9c]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-fbeb5b9c]{background:linear-gradient(135deg,#fa709a,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-fbeb5b9c]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width: 768px){.image-preview-container[data-v-fbeb5b9c]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-fbeb5b9c]{width:50px;height:50px}.add-button[data-v-fbeb5b9c]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-fbeb5b9c]{min-width:100px}.action-menu-item[data-v-fbeb5b9c]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-fbeb5b9c]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme: dark){.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#fff3}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
|
|
1
|
+
.message-quote[data-v-323dce07]{margin:8px 0;padding:8px 12px;background-color:#bebebe1a;border-left:4px solid rgba(151,152,152,.45);border-radius:6px;font-size:.9em;position:relative}.quote-indicator[data-v-323dce07]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-323dce07]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-323dce07]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-323dce07]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-323dce07]{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#6c757d;color:#fff;font-size:10px;font-weight:700}.quote-username[data-v-323dce07]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-323dce07]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-323dce07]{color:#7276b7;line-height:1.3;word-wrap:break-word}.quote-content .message-image[data-v-323dce07]{max-width:200px;max-height:100px}.quote-content .message-image-container[data-v-323dce07]{margin:2px 0}@media (prefers-color-scheme: dark){.message-quote[data-v-323dce07]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-323dce07]{color:#adb5bd}.quote-username[data-v-323dce07]{color:#0d6efd}}.chat-container[data-v-323dce07]{display:flex;height:100vh;background:transparent;margin-left:0%;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-323dce07],.channel-list[data-v-323dce07],.message-area[data-v-323dce07]{display:flex;flex-direction:column;background:transparent;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-323dce07]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-323dce07]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-323dce07]{flex:1;border-right:none}.panel-header[data-v-323dce07]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:transparent;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-323dce07]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-323dce07]{display:none;background:none;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-323dce07]:hover{background:#8080801a}.bot-items[data-v-323dce07],.channel-items[data-v-323dce07]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-323dce07],.channel-item[data-v-323dce07]{display:flex;align-items:center;padding:12px 16px;cursor:pointer;border-bottom:1px solid rgba(128,128,128,.1);transition:background-color .2s}.bot-item[data-v-323dce07]:hover,.channel-item[data-v-323dce07]:hover{background:#8080801a}.bot-item.active[data-v-323dce07],.channel-item.active[data-v-323dce07]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-323dce07]{width:40px;height:40px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0}.bot-avatar img[data-v-323dce07]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-323dce07]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-323dce07]{flex:1}.bot-name[data-v-323dce07]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-323dce07]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-323dce07]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-323dce07]{background:#4caf50}.bot-status.offline[data-v-323dce07]{background:#f44336}.channel-info[data-v-323dce07]{flex:1}.channel-name[data-v-323dce07]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-323dce07]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-323dce07]{background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;position:relative;transition:all .2s ease}.channel-message-count.draggable-bubble[data-v-323dce07]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-323dce07]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble[data-v-323dce07]:active,.channel-message-count.draggable-bubble.dragging[data-v-323dce07]{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-323dce07]{position:fixed;z-index:1000;pointer-events:none;transition:none;box-sizing:border-box;display:flex;align-items:center;justify-content:center;background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;box-shadow:0 4px 12px #2196f366}.dragging-clone.will-delete[data-v-323dce07]{background:#f44336!important;animation:shake-323dce07 .3s ease-in-out infinite}@keyframes pulseThreshold-323dce07{0%,to{opacity:.4;transform:scale(.9);border-color:#f4433699;box-shadow:0 0 15px #f4433633}50%{opacity:.8;transform:scale(1.1);border-color:#f44336;box-shadow:0 0 25px #f4433666}}@keyframes menuSlideIn-323dce07{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-323dce07]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-323dce07]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-323dce07]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-323dce07]:hover{background-color:#8080801a}.message-item.new-message[data-v-323dce07]{background-color:#4caf5033;animation:highlight-323dce07 2s ease-out}.message-item.bot-message[data-v-323dce07]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-323dce07]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-323dce07]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-323dce07]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-323dce07]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-323dce07]{order:1}.message-item.bot-message .message-text[data-v-323dce07]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left}@keyframes highlight-323dce07{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-323dce07]{width:32px;height:32px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0;flex-shrink:0}.message-avatar img[data-v-323dce07]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-323dce07]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-323dce07]{flex:1}.message-header[data-v-323dce07]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-323dce07]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-323dce07]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-323dce07]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;max-width:100%;overflow-wrap:break-word}.message-item:not(.bot-message) .message-text[data-v-323dce07]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%}.message-input[data-v-323dce07]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:transparent;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-323dce07]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-323dce07]{position:absolute;right:24px;bottom:18%;width:48px;height:48px;background:#2196f3;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px #2196f34d;color:#fff;transition:all .3s ease;z-index:100;border:2px solid rgba(255,255,255,.2)}.floating-scroll-button[data-v-323dce07]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-323dce07]:active{transform:scale(.95)}.input-row button[data-v-323dce07]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-323dce07]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-323dce07]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease}.message-image-loading[data-v-323dce07]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-323dce07]{display:inline-block;padding:8px 12px;background:#f443361a;border:1px solid rgba(244,67,54,.3);border-radius:4px;color:#f44336;font-size:12px;max-width:300px;word-break:break-word}.message-paragraph[data-v-323dce07]{display:block;margin-bottom:4px}.message-paragraph[data-v-323dce07]:last-child{margin-bottom:0}.forward-message-container[data-v-323dce07]{border:1px solid #ffffff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-323dce07]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-323dce07]:hover{background:#f0f0f0}.forward-message-title[data-v-323dce07]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-323dce07]{color:#666;font-size:13px;margin:2px 0;line-height:1.4}.forward-message-footer[data-v-323dce07]{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px solid #e8e8e8}.forward-message-count[data-v-323dce07]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-323dce07]{color:#666;font-size:12px}.forward-message-expanded[data-v-323dce07]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-323dce07]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-323dce07]:last-child{border-bottom:none}.forwarded-message-header[data-v-323dce07]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-323dce07]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-323dce07]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-323dce07]{color:#555;font-size:13px;line-height:1.4}.message-at[data-v-323dce07]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-323dce07]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-323dce07]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:none;background:transparent;color:currentColor}.input-row input[data-v-323dce07]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-323dce07]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-323dce07]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;flex-shrink:0;white-space:nowrap}.input-row button[data-v-323dce07]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-323dce07]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-323dce07]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-323dce07]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-323dce07]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-323dce07]{display:inline}.message-image-container[data-v-323dce07]{display:block;margin:4px 0}.message-image[data-v-323dce07]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-323dce07]:hover{transform:scale(1.02)}.message-image-loading[data-v-323dce07]{height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3)}.message-image-error[data-v-323dce07]{min-height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3);padding:8px;text-align:center}.message-at[data-v-323dce07]{background:#2196f31a;color:#2196f3;padding:2px 6px;border-radius:4px;font-weight:500;cursor:pointer;display:inline-block;margin:0 2px}.message-at[data-v-323dce07]:hover{background:#2196f333}.message-unknown[data-v-323dce07]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-323dce07{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-323dce07]{background:#f44336!important;animation:shake-323dce07 .3s ease-in-out infinite}@keyframes shake-323dce07{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-323dce07]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-323dce07]{position:fixed;pointer-events:none;border:3px dashed rgba(244,67,54,.8);border-radius:50%;z-index:999;background:#f443361a;box-shadow:0 0 20px #f443364d;animation:pulseThreshold-323dce07 1.5s ease-in-out infinite}.context-menu[data-v-323dce07]{position:fixed;background:#ffffffa6;border:1px solid rgba(0,0,0,.1);border-radius:8px;box-shadow:0 8px 32px #00000026;z-index:10000;min-width:180px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);overflow:hidden}.context-menu-item[data-v-323dce07]{padding:12px 16px;cursor:pointer;color:#333;font-size:14px;font-weight:500;transition:all .2s ease;border-bottom:1px solid rgba(0,0,0,.08);position:relative}.context-menu-item[data-v-323dce07]:last-child{border-bottom:none}.context-menu-item[data-v-323dce07]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-323dce07]{color:#d32f2f}.context-menu-item.danger[data-v-323dce07]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-323dce07],.channel-item.pinned[data-v-323dce07]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-323dce07]:before,.channel-item.pinned[data-v-323dce07]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-323dce07],.channel-item.pinned[data-v-323dce07]{position:relative;padding-left:24px}@media (prefers-color-scheme: dark){.context-menu[data-v-323dce07]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-323dce07]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-323dce07]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-323dce07]{color:#ff8a80}.context-menu-item.danger[data-v-323dce07]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-323dce07],.channel-item.pinned[data-v-323dce07]{background:#ffc10726}}.message-share-card[data-v-323dce07]{display:inline-block;width:75px;margin:8px 0;border:1px solid rgba(128,128,128,.2);border-radius:12px;background:#ffffff0d;transition:all .3s ease;cursor:pointer;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.message-share-card[data-v-323dce07]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-323dce07]{width:100%;position:relative;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:12px 12px 0 0}.share-card-image[data-v-323dce07]{max-width:calc(100% - 8px);width:auto;height:auto;object-fit:contain;transition:transform .3s ease;display:block;border-radius:4px}.message-share-card:hover .share-card-image[data-v-323dce07]{transform:scale(1.05)}.share-card-content[data-v-323dce07]{padding:8px}.share-card-header[data-v-323dce07]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-323dce07]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-323dce07]{flex:1;min-width:0}.share-card-app-name[data-v-323dce07]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-323dce07]{font-size:10px;font-weight:600;color:currentColor;line-height:1.2;word-wrap:break-word;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}.share-card-desc[data-v-323dce07]{font-size:14px;color:currentColor;opacity:.8;line-height:1.4;margin-bottom:12px;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;word-wrap:break-word}.share-card-link-hint[data-v-323dce07]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-323dce07]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-323dce07]:after{transform:translate(2px)}.message-json-error[data-v-323dce07],.message-json-raw[data-v-323dce07]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-323dce07]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-323dce07]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-323dce07]{margin-top:8px}.json-raw-data summary[data-v-323dce07]{cursor:pointer;font-size:12px;color:#2196f3;font-weight:500;padding:4px 8px;border-radius:4px;background:#2196f31a;display:inline-block;transition:background-color .2s ease}.json-raw-data summary[data-v-323dce07]:hover{background:#2196f333}.json-raw-content[data-v-323dce07]{margin-top:8px;padding:12px;background:#8080801a;border-radius:8px;font-family:Courier New,monospace;font-size:12px;color:currentColor;opacity:.8;white-space:pre-wrap;word-wrap:break-word;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme: dark){.message-share-card[data-v-323dce07]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-323dce07]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-323dce07]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width: 768px){.chat-container[data-v-323dce07]{position:relative}.bot-list[data-v-323dce07],.channel-list[data-v-323dce07],.message-area[data-v-323dce07]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-323dce07]{transform:translate(0);z-index:3}.channel-list[data-v-323dce07]{transform:translate(100%);z-index:2}.message-area[data-v-323dce07]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-323dce07]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-323dce07]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-323dce07]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-323dce07]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-323dce07]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-323dce07]{transform:translate(0);z-index:3}.back-button[data-v-323dce07]{display:none!important}.panel-header[data-v-323dce07]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-323dce07]{text-align:right}.floating-scroll-button[data-v-323dce07]{right:16px;bottom:70px;width:40px;height:40px}.message-input[data-v-323dce07]{padding:8px 12px 12px;position:fixed;bottom:0;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10}.input-row input[data-v-323dce07]{font-size:16px;padding:10px 12px}.input-row button[data-v-323dce07]{padding:10px 16px;font-size:16px}.message-history[data-v-323dce07]{padding:12px 12px 80px;max-height:calc(100vh - 140px)}.message-item[data-v-323dce07]{margin-bottom:12px;padding:6px}.message-avatar[data-v-323dce07]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-323dce07]{margin-left:8px}.message-image[data-v-323dce07]{max-width:280px;max-height:160px}.quote-content .message-image[data-v-323dce07]{max-width:150px;max-height:80px}.context-menu[data-v-323dce07]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-323dce07]{padding:14px 16px;font-size:16px}.bot-item[data-v-323dce07],.channel-item[data-v-323dce07]{padding:14px 16px}.bot-avatar[data-v-323dce07]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-323dce07],.channel-name[data-v-323dce07]{font-size:15px}.bot-platform[data-v-323dce07],.channel-type[data-v-323dce07]{font-size:13px}}@media (min-width: 769px) and (max-width: 1024px){.bot-list[data-v-323dce07]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-323dce07]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-323dce07]{max-width:350px;max-height:180px}}.chat-container.swiping[data-v-323dce07]{overflow:hidden}.bot-list.swiping[data-v-323dce07],.channel-list.swiping[data-v-323dce07],.message-area.swiping[data-v-323dce07]{transition:none!important}.swipe-indicator[data-v-323dce07]{position:fixed;top:50%;left:20px;transform:translateY(-50%);background:#2196f3cc;color:#fff;padding:8px 12px;border-radius:20px;font-size:14px;z-index:1000;opacity:0;transition:opacity .2s ease;pointer-events:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.swipe-indicator.show[data-v-323dce07]{opacity:1}.message-area .message-content[data-v-323dce07]{padding-bottom:80px}.image-preview-container[data-v-323dce07]{display:flex;flex-wrap:wrap;gap:8px;padding:8px 0;margin-bottom:8px;border-bottom:1px solid rgba(128,128,128,.1)}.image-preview-item[data-v-323dce07]{position:relative;width:60px;height:60px;border-radius:8px;overflow:hidden;border:2px solid rgba(33,150,243,.3);background:#8080801a}.preview-image[data-v-323dce07]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-323dce07]{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;background:#f44336;color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;transition:all .2s ease;box-shadow:0 2px 4px #0003}.remove-image-btn[data-v-323dce07]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-323dce07]{position:relative;margin-right:8px}.add-button[data-v-323dce07]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea,#764ba2);border:none;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;box-shadow:0 2px 8px #667eea4d;position:relative;overflow:hidden}.add-button[data-v-323dce07]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-323dce07]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-323dce07]:hover:before{opacity:1}.add-button.active[data-v-323dce07]{background:linear-gradient(135deg,#f093fb,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-323dce07]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-323dce07]{position:absolute;bottom:100%;left:0;margin-bottom:12px;background:#fffffffa;border:none;border-radius:16px;box-shadow:0 8px 32px #0000001f,0 2px 8px #00000014;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);overflow:hidden;z-index:1000;min-width:140px;transform:translateY(8px);opacity:0;animation:menuSlideIn-323dce07 .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-323dce07]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:none;border:none;color:#333;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);width:100%;text-align:left;position:relative}.action-menu-item[data-v-323dce07]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-323dce07]:hover{background:linear-gradient(90deg,#667eea14,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-323dce07]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-323dce07]{flex-shrink:0}@media (prefers-color-scheme: dark){.action-menu[data-v-323dce07]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-323dce07]{color:#fff}.action-menu-item[data-v-323dce07]:before{background:linear-gradient(135deg,#4facfe,#00f2fe)}.action-menu-item[data-v-323dce07]:hover{background:linear-gradient(90deg,#4facfe1f,#00f2fe1f);color:#4facfe}.add-button[data-v-323dce07]{background:linear-gradient(135deg,#4facfe,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-323dce07]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-323dce07]{background:linear-gradient(135deg,#fa709a,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-323dce07]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width: 768px){.image-preview-container[data-v-323dce07]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-323dce07]{width:50px;height:50px}.add-button[data-v-323dce07]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-323dce07]{min-width:100px}.action-menu-item[data-v-323dce07]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-323dce07]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-323dce07]::-webkit-scrollbar{width:6px}.message-history[data-v-323dce07]::-webkit-scrollbar-track{background:transparent}.message-history[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-323dce07]::-webkit-scrollbar{width:6px}.bot-items[data-v-323dce07]::-webkit-scrollbar-track{background:transparent}.bot-items[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-323dce07]::-webkit-scrollbar{width:6px}.channel-items[data-v-323dce07]::-webkit-scrollbar-track{background:transparent}.channel-items[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar-track{background:transparent}.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-323dce07]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-323dce07]::-webkit-scrollbar-track{background:transparent}.json-raw-content[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme: dark){.message-history[data-v-323dce07]::-webkit-scrollbar-thumb,.bot-items[data-v-323dce07]::-webkit-scrollbar-thumb,.channel-items[data-v-323dce07]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar-thumb,.json-raw-content[data-v-323dce07]::-webkit-scrollbar-thumb{background-color:#fff3}.message-history[data-v-323dce07]::-webkit-scrollbar-thumb:hover,.bot-items[data-v-323dce07]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-323dce07]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-323dce07]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-323dce07]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FileManager } from './file-manager';
|
|
2
|
+
import { Context } from 'koishi';
|
|
3
|
+
import { Config } from './config';
|
|
4
|
+
export declare class ApiHandlers {
|
|
5
|
+
private ctx;
|
|
6
|
+
private config;
|
|
7
|
+
private fileManager;
|
|
8
|
+
private logger;
|
|
9
|
+
constructor(ctx: Context, config: Config, fileManager: FileManager);
|
|
10
|
+
registerApiHandlers(): void;
|
|
11
|
+
private isFileUrl;
|
|
12
|
+
private createFileUrl;
|
|
13
|
+
private handleLocalFileRequest;
|
|
14
|
+
private setupTempFileCleanup;
|
|
15
|
+
private cleanupTempImagesByCount;
|
|
16
|
+
private logInfo;
|
|
17
|
+
}
|
|
@@ -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
|
@@ -41,10 +41,6 @@ __export(src_exports, {
|
|
|
41
41
|
module.exports = __toCommonJS(src_exports);
|
|
42
42
|
var import_node_path2 = __toESM(require("node:path"));
|
|
43
43
|
|
|
44
|
-
// src/file-manager.ts
|
|
45
|
-
var import_node_path = __toESM(require("node:path"));
|
|
46
|
-
var import_node_fs = __toESM(require("node:fs"));
|
|
47
|
-
|
|
48
44
|
// src/utils.ts
|
|
49
45
|
var Utils = class {
|
|
50
46
|
constructor(config) {
|
|
@@ -128,147 +124,6 @@ var Utils = class {
|
|
|
128
124
|
}
|
|
129
125
|
};
|
|
130
126
|
|
|
131
|
-
// src/file-manager.ts
|
|
132
|
-
var FileManager = class {
|
|
133
|
-
constructor(ctx, config) {
|
|
134
|
-
this.ctx = ctx;
|
|
135
|
-
this.config = config;
|
|
136
|
-
this.dataFilePath = import_node_path.default.resolve(ctx.baseDir, "data", "chat-patch", "chat-data.json");
|
|
137
|
-
this.logger = ctx.logger("chat-patch");
|
|
138
|
-
this.utils = new Utils(config);
|
|
139
|
-
}
|
|
140
|
-
static {
|
|
141
|
-
__name(this, "FileManager");
|
|
142
|
-
}
|
|
143
|
-
dataFilePath;
|
|
144
|
-
fileOperationLock = Promise.resolve();
|
|
145
|
-
logger;
|
|
146
|
-
utils;
|
|
147
|
-
// 确保目录存在
|
|
148
|
-
ensureDataDir() {
|
|
149
|
-
const dir = import_node_path.default.dirname(this.dataFilePath);
|
|
150
|
-
if (!import_node_fs.default.existsSync(dir)) {
|
|
151
|
-
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// 从JSON文件读取数据
|
|
155
|
-
readChatDataFromFile() {
|
|
156
|
-
try {
|
|
157
|
-
if (import_node_fs.default.existsSync(this.dataFilePath)) {
|
|
158
|
-
const jsonData = import_node_fs.default.readFileSync(this.dataFilePath, "utf8");
|
|
159
|
-
const data = JSON.parse(jsonData);
|
|
160
|
-
return {
|
|
161
|
-
bots: data.bots || {},
|
|
162
|
-
channels: data.channels || {},
|
|
163
|
-
messages: data.messages || {},
|
|
164
|
-
pinnedBots: data.pinnedBots || [],
|
|
165
|
-
pinnedChannels: data.pinnedChannels || [],
|
|
166
|
-
lastSaveTime: data.lastSaveTime
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
} catch (error) {
|
|
170
|
-
this.logger.error("读取聊天数据失败:", error);
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
bots: {},
|
|
174
|
-
channels: {},
|
|
175
|
-
messages: {},
|
|
176
|
-
pinnedBots: [],
|
|
177
|
-
pinnedChannels: []
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
// 写入数据到JSON文件
|
|
181
|
-
writeChatDataToFile(data) {
|
|
182
|
-
try {
|
|
183
|
-
this.ensureDataDir();
|
|
184
|
-
data.lastSaveTime = Date.now();
|
|
185
|
-
const jsonData = JSON.stringify(data, null, 2);
|
|
186
|
-
import_node_fs.default.writeFileSync(this.dataFilePath, jsonData, "utf8");
|
|
187
|
-
} catch (error) {
|
|
188
|
-
this.logger.error("写入聊天数据失败:", error);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// 清理超量消息
|
|
192
|
-
cleanExcessMessages(data) {
|
|
193
|
-
let cleanedCount = 0;
|
|
194
|
-
const cleanedMessages = {};
|
|
195
|
-
for (const [channelKey, messages] of Object.entries(data.messages)) {
|
|
196
|
-
if (messages.length > this.config.maxMessagesPerChannel) {
|
|
197
|
-
const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp);
|
|
198
|
-
const keptMessages = sortedMessages.slice(-this.config.maxMessagesPerChannel);
|
|
199
|
-
cleanedCount += messages.length - keptMessages.length;
|
|
200
|
-
cleanedMessages[channelKey] = keptMessages;
|
|
201
|
-
this.logInfo(`频道 ${channelKey} 清理了 ${messages.length - keptMessages.length} 条旧消息,保留最新 ${keptMessages.length} 条`);
|
|
202
|
-
} else {
|
|
203
|
-
cleanedMessages[channelKey] = messages;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (cleanedCount > 0) {
|
|
207
|
-
this.logInfo("总共清理超量消息:", cleanedCount, "条");
|
|
208
|
-
}
|
|
209
|
-
return {
|
|
210
|
-
...data,
|
|
211
|
-
messages: cleanedMessages
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
// 添加消息到JSON文件(使用锁机制防止并发冲突)
|
|
215
|
-
async addMessageToFile(messageInfo) {
|
|
216
|
-
this.fileOperationLock = this.fileOperationLock.then(async () => {
|
|
217
|
-
const data = this.readChatDataFromFile();
|
|
218
|
-
const channelKey = `${messageInfo.selfId}:${messageInfo.channelId}`;
|
|
219
|
-
if (!data.messages[channelKey]) {
|
|
220
|
-
data.messages[channelKey] = [];
|
|
221
|
-
}
|
|
222
|
-
const existingMessage = data.messages[channelKey].find((m) => m.id === messageInfo.id);
|
|
223
|
-
if (existingMessage) {
|
|
224
|
-
this.logInfo("消息已存在,跳过保存:", {
|
|
225
|
-
channelKey,
|
|
226
|
-
messageId: messageInfo.id,
|
|
227
|
-
existingType: existingMessage.type,
|
|
228
|
-
existingContent: existingMessage.content,
|
|
229
|
-
newType: messageInfo.type,
|
|
230
|
-
newContent: messageInfo.content
|
|
231
|
-
});
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (!messageInfo.timestamp) {
|
|
235
|
-
messageInfo.timestamp = Date.now();
|
|
236
|
-
}
|
|
237
|
-
const cleanedMessageInfo = this.utils.cleanBase64Content(messageInfo);
|
|
238
|
-
const beforeCount = data.messages[channelKey].length;
|
|
239
|
-
data.messages[channelKey].push(cleanedMessageInfo);
|
|
240
|
-
const afterCount = data.messages[channelKey].length;
|
|
241
|
-
if (data.messages[channelKey].length > this.config.maxMessagesPerChannel) {
|
|
242
|
-
data.messages[channelKey].sort((a, b) => a.timestamp - b.timestamp);
|
|
243
|
-
const removedCount = data.messages[channelKey].length - this.config.maxMessagesPerChannel;
|
|
244
|
-
data.messages[channelKey] = data.messages[channelKey].slice(-this.config.maxMessagesPerChannel);
|
|
245
|
-
this.logInfo(`频道 ${channelKey} 达到消息上限,清理了 ${removedCount} 条旧消息`);
|
|
246
|
-
}
|
|
247
|
-
this.writeChatDataToFile(data);
|
|
248
|
-
const isCommandMessage = messageInfo.content?.startsWith("++") || messageInfo.content?.startsWith(".");
|
|
249
|
-
this.logInfo("添加消息到文件:", {
|
|
250
|
-
channelKey,
|
|
251
|
-
messageId: messageInfo.id,
|
|
252
|
-
content: messageInfo.content,
|
|
253
|
-
type: messageInfo.type,
|
|
254
|
-
userId: messageInfo.userId,
|
|
255
|
-
username: messageInfo.username,
|
|
256
|
-
timestamp: messageInfo.timestamp,
|
|
257
|
-
isCommandMessage,
|
|
258
|
-
消息数变化: `${beforeCount} -> ${afterCount} -> ${data.messages[channelKey].length}`
|
|
259
|
-
});
|
|
260
|
-
}).catch((error) => {
|
|
261
|
-
this.logger.error("保存消息时发生错误:", error);
|
|
262
|
-
});
|
|
263
|
-
await this.fileOperationLock;
|
|
264
|
-
}
|
|
265
|
-
logInfo(...args) {
|
|
266
|
-
if (this.config.loggerinfo) {
|
|
267
|
-
this.logger.info(...args);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
|
|
272
127
|
// src/message-handler.ts
|
|
273
128
|
var MessageHandler = class {
|
|
274
129
|
constructor(ctx, config, fileManager) {
|
|
@@ -472,6 +327,149 @@ var MessageHandler = class {
|
|
|
472
327
|
}
|
|
473
328
|
};
|
|
474
329
|
|
|
330
|
+
// src/file-manager.ts
|
|
331
|
+
var import_node_path = __toESM(require("node:path"));
|
|
332
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
333
|
+
var FileManager = class {
|
|
334
|
+
constructor(ctx, config) {
|
|
335
|
+
this.ctx = ctx;
|
|
336
|
+
this.config = config;
|
|
337
|
+
this.dataFilePath = import_node_path.default.resolve(ctx.baseDir, "data", "chat-patch", "chat-data.json");
|
|
338
|
+
this.logger = ctx.logger("chat-patch");
|
|
339
|
+
this.utils = new Utils(config);
|
|
340
|
+
}
|
|
341
|
+
static {
|
|
342
|
+
__name(this, "FileManager");
|
|
343
|
+
}
|
|
344
|
+
dataFilePath;
|
|
345
|
+
fileOperationLock = Promise.resolve();
|
|
346
|
+
logger;
|
|
347
|
+
utils;
|
|
348
|
+
// 确保目录存在
|
|
349
|
+
ensureDataDir() {
|
|
350
|
+
const dir = import_node_path.default.dirname(this.dataFilePath);
|
|
351
|
+
if (!import_node_fs.default.existsSync(dir)) {
|
|
352
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// 从JSON文件读取数据
|
|
356
|
+
readChatDataFromFile() {
|
|
357
|
+
try {
|
|
358
|
+
if (import_node_fs.default.existsSync(this.dataFilePath)) {
|
|
359
|
+
const jsonData = import_node_fs.default.readFileSync(this.dataFilePath, "utf8");
|
|
360
|
+
const data = JSON.parse(jsonData);
|
|
361
|
+
return {
|
|
362
|
+
bots: data.bots || {},
|
|
363
|
+
channels: data.channels || {},
|
|
364
|
+
messages: data.messages || {},
|
|
365
|
+
pinnedBots: data.pinnedBots || [],
|
|
366
|
+
pinnedChannels: data.pinnedChannels || [],
|
|
367
|
+
lastSaveTime: data.lastSaveTime
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
} catch (error) {
|
|
371
|
+
this.logger.error("读取聊天数据失败:", error);
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
bots: {},
|
|
375
|
+
channels: {},
|
|
376
|
+
messages: {},
|
|
377
|
+
pinnedBots: [],
|
|
378
|
+
pinnedChannels: []
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
// 写入数据到JSON文件
|
|
382
|
+
writeChatDataToFile(data) {
|
|
383
|
+
try {
|
|
384
|
+
this.ensureDataDir();
|
|
385
|
+
data.lastSaveTime = Date.now();
|
|
386
|
+
const jsonData = JSON.stringify(data, null, 2);
|
|
387
|
+
import_node_fs.default.writeFileSync(this.dataFilePath, jsonData, "utf8");
|
|
388
|
+
} catch (error) {
|
|
389
|
+
this.logger.error("写入聊天数据失败:", error);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// 清理超量消息
|
|
393
|
+
cleanExcessMessages(data) {
|
|
394
|
+
let cleanedCount = 0;
|
|
395
|
+
const cleanedMessages = {};
|
|
396
|
+
for (const [channelKey, messages] of Object.entries(data.messages)) {
|
|
397
|
+
if (messages.length > this.config.maxMessagesPerChannel) {
|
|
398
|
+
const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp);
|
|
399
|
+
const keptMessages = sortedMessages.slice(-this.config.maxMessagesPerChannel);
|
|
400
|
+
cleanedCount += messages.length - keptMessages.length;
|
|
401
|
+
cleanedMessages[channelKey] = keptMessages;
|
|
402
|
+
this.logInfo(`频道 ${channelKey} 清理了 ${messages.length - keptMessages.length} 条旧消息,保留最新 ${keptMessages.length} 条`);
|
|
403
|
+
} else {
|
|
404
|
+
cleanedMessages[channelKey] = messages;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (cleanedCount > 0) {
|
|
408
|
+
this.logInfo("总共清理超量消息:", cleanedCount, "条");
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
...data,
|
|
412
|
+
messages: cleanedMessages
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// 添加消息到JSON文件(使用锁机制防止并发冲突)
|
|
416
|
+
async addMessageToFile(messageInfo) {
|
|
417
|
+
this.fileOperationLock = this.fileOperationLock.then(async () => {
|
|
418
|
+
const data = this.readChatDataFromFile();
|
|
419
|
+
const channelKey = `${messageInfo.selfId}:${messageInfo.channelId}`;
|
|
420
|
+
if (!data.messages[channelKey]) {
|
|
421
|
+
data.messages[channelKey] = [];
|
|
422
|
+
}
|
|
423
|
+
const existingMessage = data.messages[channelKey].find((m) => m.id === messageInfo.id);
|
|
424
|
+
if (existingMessage) {
|
|
425
|
+
this.logInfo("消息已存在,跳过保存:", {
|
|
426
|
+
channelKey,
|
|
427
|
+
messageId: messageInfo.id,
|
|
428
|
+
existingType: existingMessage.type,
|
|
429
|
+
existingContent: existingMessage.content,
|
|
430
|
+
newType: messageInfo.type,
|
|
431
|
+
newContent: messageInfo.content
|
|
432
|
+
});
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (!messageInfo.timestamp) {
|
|
436
|
+
messageInfo.timestamp = Date.now();
|
|
437
|
+
}
|
|
438
|
+
const cleanedMessageInfo = this.utils.cleanBase64Content(messageInfo);
|
|
439
|
+
const beforeCount = data.messages[channelKey].length;
|
|
440
|
+
data.messages[channelKey].push(cleanedMessageInfo);
|
|
441
|
+
const afterCount = data.messages[channelKey].length;
|
|
442
|
+
if (data.messages[channelKey].length > this.config.maxMessagesPerChannel) {
|
|
443
|
+
data.messages[channelKey].sort((a, b) => a.timestamp - b.timestamp);
|
|
444
|
+
const removedCount = data.messages[channelKey].length - this.config.maxMessagesPerChannel;
|
|
445
|
+
data.messages[channelKey] = data.messages[channelKey].slice(-this.config.maxMessagesPerChannel);
|
|
446
|
+
this.logInfo(`频道 ${channelKey} 达到消息上限,清理了 ${removedCount} 条旧消息`);
|
|
447
|
+
}
|
|
448
|
+
this.writeChatDataToFile(data);
|
|
449
|
+
const isCommandMessage = messageInfo.content?.startsWith("++") || messageInfo.content?.startsWith(".");
|
|
450
|
+
this.logInfo("添加消息到文件:", {
|
|
451
|
+
channelKey,
|
|
452
|
+
messageId: messageInfo.id,
|
|
453
|
+
content: messageInfo.content,
|
|
454
|
+
type: messageInfo.type,
|
|
455
|
+
userId: messageInfo.userId,
|
|
456
|
+
username: messageInfo.username,
|
|
457
|
+
timestamp: messageInfo.timestamp,
|
|
458
|
+
isCommandMessage,
|
|
459
|
+
消息数变化: `${beforeCount} -> ${afterCount} -> ${data.messages[channelKey].length}`
|
|
460
|
+
});
|
|
461
|
+
}).catch((error) => {
|
|
462
|
+
this.logger.error("保存消息时发生错误:", error);
|
|
463
|
+
});
|
|
464
|
+
await this.fileOperationLock;
|
|
465
|
+
}
|
|
466
|
+
logInfo(...args) {
|
|
467
|
+
if (this.config.loggerinfo) {
|
|
468
|
+
this.logger.info(...args);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
475
473
|
// src/api-handlers.ts
|
|
476
474
|
var import_koishi = require("koishi");
|
|
477
475
|
var import_node_url = require("node:url");
|
|
@@ -956,7 +954,7 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
956
954
|
// src/index.ts
|
|
957
955
|
var name = "chat-patch";
|
|
958
956
|
var reusable = false;
|
|
959
|
-
var filter =
|
|
957
|
+
var filter = true;
|
|
960
958
|
var inject = {
|
|
961
959
|
required: ["console"]
|
|
962
960
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
constructor(ctx: Context, config: Config, fileManager: FileManager);
|
|
11
|
+
updateBotInfoToFile(session: Session): Promise<void>;
|
|
12
|
+
updateChannelInfoToFile(session: Session): Promise<string>;
|
|
13
|
+
broadcastMessageEvent(session: Session): Promise<void>;
|
|
14
|
+
broadcastBotMessageEvent(session: Session): Promise<void>;
|
|
15
|
+
private logInfo;
|
|
16
|
+
}
|
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.11",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
package/src/api-handlers.ts
CHANGED
package/src/file-manager.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import fs from 'node:fs'
|
|
3
|
-
import { Context, Logger } from 'koishi'
|
|
4
1
|
import { ChatData, MessageInfo } from './types'
|
|
2
|
+
import { Context, Logger } from 'koishi'
|
|
5
3
|
import { Config } from './config'
|
|
6
4
|
import { Utils } from './utils'
|
|
7
5
|
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
import fs from 'node:fs'
|
|
8
|
+
|
|
8
9
|
export class FileManager {
|
|
9
10
|
private dataFilePath: string
|
|
10
11
|
private fileOperationLock = Promise.resolve()
|
package/src/index.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import { } from '@koishijs/plugin-console'
|
|
3
|
+
import { Context } from 'koishi'
|
|
3
4
|
import path from 'node:path'
|
|
4
|
-
import fs from 'node:fs'
|
|
5
5
|
|
|
6
|
-
import { Config } from './config'
|
|
7
|
-
import { FileManager } from './file-manager'
|
|
8
6
|
import { MessageHandler } from './message-handler'
|
|
7
|
+
import { FileManager } from './file-manager'
|
|
9
8
|
import { ApiHandlers } from './api-handlers'
|
|
9
|
+
import { Config } from './config'
|
|
10
10
|
import { Utils } from './utils'
|
|
11
11
|
|
|
12
12
|
export const name = 'chat-patch'
|
|
13
13
|
export const reusable = false
|
|
14
|
-
export const filter =
|
|
14
|
+
export const filter = true
|
|
15
15
|
export const inject = {
|
|
16
16
|
required: ['console']
|
|
17
17
|
}
|
package/src/message-handler.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { BotInfo, ChannelInfo, MessageInfo, QuoteInfo } from './types'
|
|
1
2
|
import { Context, Session, h, Logger } from 'koishi'
|
|
2
|
-
import { Config } from './config'
|
|
3
3
|
import { FileManager } from './file-manager'
|
|
4
|
+
import { Config } from './config'
|
|
4
5
|
import { Utils } from './utils'
|
|
5
|
-
import { BotInfo, ChannelInfo, MessageInfo, QuoteInfo } from './types'
|
|
6
6
|
|
|
7
7
|
export class MessageHandler {
|
|
8
8
|
private logger: Logger
|