koishi-plugin-chat-patch 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/vue/chat-logic.ts +80 -14
- package/client/vue/style.css +15 -1
- package/dist/index.js +7 -7
- package/dist/style.css +1 -1
- package/lib/index.js +45 -17
- package/package.json +1 -1
- package/src/api-handlers.ts +15 -6
- package/src/index.ts +1 -1
- package/src/message-handler.ts +48 -13
- package/src/types.ts +3 -1
package/client/vue/chat-logic.ts
CHANGED
|
@@ -23,8 +23,9 @@ export function useChatLogic() {
|
|
|
23
23
|
id: string
|
|
24
24
|
name: string
|
|
25
25
|
type: number | string
|
|
26
|
-
|
|
26
|
+
channelId?: string
|
|
27
27
|
guildName?: string
|
|
28
|
+
isDirect?: boolean
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
interface MessageElement {
|
|
@@ -306,6 +307,13 @@ export function useChatLogic() {
|
|
|
306
307
|
'width': 'auto',
|
|
307
308
|
'height': 'auto',
|
|
308
309
|
'object-fit': 'contain'
|
|
310
|
+
},
|
|
311
|
+
// 确保GIF动画能正常播放
|
|
312
|
+
onLoad: () => {
|
|
313
|
+
// 对于GIF图片,确保动画开始播放
|
|
314
|
+
if (imgRef.value && props.src.toLowerCase().includes('.gif')) {
|
|
315
|
+
imgRef.value.style.imageRendering = 'auto'
|
|
316
|
+
}
|
|
309
317
|
}
|
|
310
318
|
})
|
|
311
319
|
|
|
@@ -904,6 +912,9 @@ export function useChatLogic() {
|
|
|
904
912
|
selectedBot.value = botId
|
|
905
913
|
selectedChannel.value = ''
|
|
906
914
|
|
|
915
|
+
// 保存选择状态
|
|
916
|
+
saveSelectionState()
|
|
917
|
+
|
|
907
918
|
// 手机端:选择机器人后切换到频道视图
|
|
908
919
|
if (isMobile.value) {
|
|
909
920
|
mobileView.value = 'channels'
|
|
@@ -1094,6 +1105,9 @@ export function useChatLogic() {
|
|
|
1094
1105
|
selectedChannel.value = channelId
|
|
1095
1106
|
isUserScrolling.value = false
|
|
1096
1107
|
|
|
1108
|
+
// 保存选择状态
|
|
1109
|
+
saveSelectionState()
|
|
1110
|
+
|
|
1097
1111
|
// 手机端:选择频道后切换到消息视图
|
|
1098
1112
|
if (isMobile.value) {
|
|
1099
1113
|
mobileView.value = 'messages'
|
|
@@ -1207,7 +1221,19 @@ export function useChatLogic() {
|
|
|
1207
1221
|
event.preventDefault()
|
|
1208
1222
|
const file = item.getAsFile()
|
|
1209
1223
|
if (file) {
|
|
1210
|
-
|
|
1224
|
+
// 为粘贴的文件创建一个带有正确扩展名的新File对象
|
|
1225
|
+
const extension = item.type === 'image/gif' ? '.gif' :
|
|
1226
|
+
item.type === 'image/png' ? '.png' :
|
|
1227
|
+
item.type === 'image/jpeg' ? '.jpg' : '.jpg'
|
|
1228
|
+
const filename = `pasted-image-${Date.now()}${extension}`
|
|
1229
|
+
|
|
1230
|
+
// 创建新的File对象,确保有正确的文件名和类型
|
|
1231
|
+
const newFile = new File([file], filename, {
|
|
1232
|
+
type: item.type,
|
|
1233
|
+
lastModified: Date.now()
|
|
1234
|
+
})
|
|
1235
|
+
|
|
1236
|
+
await uploadImage(newFile)
|
|
1211
1237
|
}
|
|
1212
1238
|
}
|
|
1213
1239
|
}
|
|
@@ -1237,7 +1263,8 @@ export function useChatLogic() {
|
|
|
1237
1263
|
const result = await (send as any)('upload-image', {
|
|
1238
1264
|
file: base64,
|
|
1239
1265
|
filename: file.name,
|
|
1240
|
-
mimeType: file.type
|
|
1266
|
+
mimeType: file.type,
|
|
1267
|
+
isGif: file.type === 'image/gif' // 标记是否为GIF
|
|
1241
1268
|
})
|
|
1242
1269
|
|
|
1243
1270
|
if (result.success) {
|
|
@@ -2224,6 +2251,8 @@ export function useChatLogic() {
|
|
|
2224
2251
|
byteNumbers[i] = byteCharacters.charCodeAt(i)
|
|
2225
2252
|
}
|
|
2226
2253
|
const byteArray = new Uint8Array(byteNumbers)
|
|
2254
|
+
|
|
2255
|
+
// 保持原始MIME类型,特别是对于GIF
|
|
2227
2256
|
const blob = new Blob([byteArray], { type: contentType })
|
|
2228
2257
|
|
|
2229
2258
|
// 检查blob大小
|
|
@@ -2339,6 +2368,31 @@ export function useChatLogic() {
|
|
|
2339
2368
|
})
|
|
2340
2369
|
}
|
|
2341
2370
|
|
|
2371
|
+
// 保存和恢复选择状态
|
|
2372
|
+
function saveSelectionState() {
|
|
2373
|
+
if (selectedBot.value && selectedChannel.value) {
|
|
2374
|
+
localStorage.setItem('chat-selected-bot', selectedBot.value)
|
|
2375
|
+
localStorage.setItem('chat-selected-channel', selectedChannel.value)
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
function restoreSelectionState() {
|
|
2380
|
+
const savedBot = localStorage.getItem('chat-selected-bot')
|
|
2381
|
+
const savedChannel = localStorage.getItem('chat-selected-channel')
|
|
2382
|
+
|
|
2383
|
+
if (savedBot && savedChannel) {
|
|
2384
|
+
// 验证保存的状态是否仍然有效
|
|
2385
|
+
if (chatData.value.bots[savedBot] &&
|
|
2386
|
+
chatData.value.channels[savedBot] &&
|
|
2387
|
+
chatData.value.channels[savedBot][savedChannel]) {
|
|
2388
|
+
selectedBot.value = savedBot
|
|
2389
|
+
selectedChannel.value = savedChannel
|
|
2390
|
+
return true
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return false
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2342
2396
|
// 处理消息事件
|
|
2343
2397
|
function handleMessageEvent(messageEvent: any) {
|
|
2344
2398
|
// 更新机器人信息
|
|
@@ -2368,16 +2422,17 @@ export function useChatLogic() {
|
|
|
2368
2422
|
}
|
|
2369
2423
|
|
|
2370
2424
|
if (messageEvent.channelId && !chatData.value.channels[messageEvent.selfId][messageEvent.channelId]) {
|
|
2371
|
-
const channelName = messageEvent.
|
|
2372
|
-
?
|
|
2373
|
-
:
|
|
2425
|
+
const channelName = messageEvent.isDirect
|
|
2426
|
+
? `私信 ${messageEvent.channelId}`
|
|
2427
|
+
: `${messageEvent.guildName || messageEvent.channelId} (${messageEvent.channelId})`
|
|
2374
2428
|
|
|
2375
2429
|
chatData.value.channels[messageEvent.selfId][messageEvent.channelId] = {
|
|
2376
2430
|
id: messageEvent.channelId,
|
|
2377
2431
|
name: channelName,
|
|
2378
2432
|
type: messageEvent.channelType || 0,
|
|
2379
|
-
|
|
2380
|
-
guildName: messageEvent.guildName ||
|
|
2433
|
+
channelId: messageEvent.channelId,
|
|
2434
|
+
guildName: messageEvent.guildName || '群聊',
|
|
2435
|
+
isDirect: messageEvent.isDirect
|
|
2381
2436
|
}
|
|
2382
2437
|
}
|
|
2383
2438
|
|
|
@@ -2561,16 +2616,17 @@ export function useChatLogic() {
|
|
|
2561
2616
|
}
|
|
2562
2617
|
|
|
2563
2618
|
if (botMessageEvent.channelId && !chatData.value.channels[botMessageEvent.selfId][botMessageEvent.channelId]) {
|
|
2564
|
-
const channelName = botMessageEvent.
|
|
2565
|
-
?
|
|
2566
|
-
:
|
|
2619
|
+
const channelName = botMessageEvent.isDirect
|
|
2620
|
+
? `私信 ${botMessageEvent.channelId}`
|
|
2621
|
+
: `${botMessageEvent.guildName || botMessageEvent.channelId} (${botMessageEvent.channelId})`
|
|
2567
2622
|
|
|
2568
2623
|
chatData.value.channels[botMessageEvent.selfId][botMessageEvent.channelId] = {
|
|
2569
2624
|
id: botMessageEvent.channelId,
|
|
2570
2625
|
name: channelName,
|
|
2571
2626
|
type: botMessageEvent.channelType || 0,
|
|
2572
|
-
|
|
2573
|
-
guildName: botMessageEvent.guildName ||
|
|
2627
|
+
channelId: botMessageEvent.channelId,
|
|
2628
|
+
guildName: botMessageEvent.guildName || '群聊',
|
|
2629
|
+
isDirect: botMessageEvent.isDirect
|
|
2574
2630
|
}
|
|
2575
2631
|
}
|
|
2576
2632
|
|
|
@@ -2980,6 +3036,14 @@ export function useChatLogic() {
|
|
|
2980
3036
|
// 然后加载历史数据
|
|
2981
3037
|
await loadChatData()
|
|
2982
3038
|
|
|
3039
|
+
// 尝试恢复之前的选择状态
|
|
3040
|
+
nextTick(() => {
|
|
3041
|
+
if (!restoreSelectionState()) {
|
|
3042
|
+
// 如果没有保存的状态或状态无效,则使用默认逻辑
|
|
3043
|
+
// 不自动选择任何频道,让用户手动选择
|
|
3044
|
+
}
|
|
3045
|
+
})
|
|
3046
|
+
|
|
2983
3047
|
// 然后开始监听消息事件
|
|
2984
3048
|
const dispose1 = receive('chat-message-event', handleMessageEvent) as (() => void) | undefined
|
|
2985
3049
|
const dispose2 = receive('bot-message-sent-event', handleBotMessageSentEvent) as (() => void) | undefined
|
|
@@ -3151,6 +3215,8 @@ export function useChatLogic() {
|
|
|
3151
3215
|
// 其他工具函数
|
|
3152
3216
|
isFileUrl,
|
|
3153
3217
|
loadHistoryMessages,
|
|
3154
|
-
handleMessageEvent
|
|
3218
|
+
handleMessageEvent,
|
|
3219
|
+
saveSelectionState,
|
|
3220
|
+
restoreSelectionState
|
|
3155
3221
|
}
|
|
3156
3222
|
}
|
package/client/vue/style.css
CHANGED
|
@@ -624,13 +624,27 @@
|
|
|
624
624
|
max-width: min(400px, 66.67vw);
|
|
625
625
|
max-height: 200px;
|
|
626
626
|
width: auto;
|
|
627
|
-
height: auto
|
|
627
|
+
height: auto;
|
|
628
|
+
/* 确保GIF动画正常播放 */
|
|
629
|
+
image-rendering: auto;
|
|
630
|
+
-webkit-image-rendering: auto;
|
|
631
|
+
-moz-image-rendering: auto;
|
|
632
|
+
-o-image-rendering: auto;
|
|
628
633
|
}
|
|
629
634
|
|
|
630
635
|
.message-image:hover {
|
|
631
636
|
transform: scale(1.02)
|
|
632
637
|
}
|
|
633
638
|
|
|
639
|
+
/* 专门针对GIF图片的样式 */
|
|
640
|
+
.message-image[src*=".gif"],
|
|
641
|
+
.message-image[src*="image/gif"] {
|
|
642
|
+
/* 确保GIF动画不被优化掉 */
|
|
643
|
+
image-rendering: auto !important;
|
|
644
|
+
-webkit-image-rendering: auto !important;
|
|
645
|
+
animation-play-state: running !important;
|
|
646
|
+
}
|
|
647
|
+
|
|
634
648
|
.message-image-loading {
|
|
635
649
|
display: inline-block;
|
|
636
650
|
padding: 8px 12px;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{defineComponent as Ce,ref as v,onMounted as nt,h,computed as Q,watch as kt,nextTick as Ie,onUnmounted as ma,createElementBlock as x,openBlock as y,unref as r,normalizeStyle as st,normalizeClass as re,createElementVNode as f,createCommentVNode as xe,Fragment as E,renderList as De,createBlock as Ne,toDisplayString as _,withDirectives as bt,createTextVNode as ot,vShow as va,withModifiers as St,withKeys as ga,isRef as ya,vModelText as pa,resolveComponent as wa}from"vue";import{receive as rt,send as P,icons as Ia}from"@koishijs/client";function xa(){function ee(e){try{return new URL(e).protocol==="file:"}catch{return false}}const le=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=async()=>{try{t.value="loading";const i=await Ve(e.channelKey,e.src);if(i){a.value=i,t.value="loaded";return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const d=new Promise((k,w)=>{c.onload=()=>k(),c.onerror=()=>w(new Error("Direct load failed")),c.src=e.src}),p=new Promise((k,w)=>{setTimeout(()=>w(new Error("Timeout")),3e3)});try{await Promise.race([d,p]),a.value=e.src,t.value="loaded",we(e.channelKey,e.src).catch(k=>{console.warn("异步缓存头像失败:",k)})}catch{await s()}}catch(i){console.error("头像加载失败:",i),t.value="error",n.value="头像加载失败"}},s=async()=>{try{t.value="caching";const i=await we(e.channelKey,e.src);if(i)a.value=i,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(i){console.error("缓存系统加载头像失败:",i),t.value="error",n.value=(i==null?void 0:i.message)||"缓存加载失败"}};return nt(()=>{o()}),()=>{switch(t.value){case"loading":case"caching":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return h("img",{src:a.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),X=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=v(null),s=async()=>{try{t.value="loading";const c=await Ve(e.channelKey,e.src);if(c){a.value=c,t.value="loaded";return}if(ee(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await i();return}const d=new Image;d.crossOrigin="anonymous",d.referrerPolicy="no-referrer",d.draggable=false;const p=new Promise((w,R)=>{d.onload=()=>w(),d.onerror=()=>R(new Error("Direct load failed")),d.src=e.src}),k=new Promise((w,R)=>{setTimeout(()=>R(new Error("Timeout")),3e3)});try{await Promise.race([p,k]),a.value=e.src,t.value="loaded",we(e.channelKey,e.src).catch(w=>{console.warn("异步缓存图片失败:",w)})}catch{await i()}}catch(c){console.error("图片加载失败:",c),t.value="error",n.value="图片加载失败"}},i=async()=>{try{t.value="caching";const c=await we(e.channelKey,e.src);if(c)a.value=c,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(c){console.error("缓存系统加载图片失败:",c),t.value="error",n.value=(c==null?void 0:c.message)||"缓存加载失败"}};return nt(()=>{s()}),()=>{switch(t.value){case"loading":return h("div",{class:"message-image-loading"},"加载中...");case"caching":return h("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return h("img",{src:a.value,alt:e.alt,class:"message-image",loading:"lazy",ref:o,draggable:false,style:{"max-width":"min(400px, 66.67vw)","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return h("div",{class:"message-image-error"},["图片加载失败",h("br"),h("small",e.filename||e.alt||"未知图片"),h("br"),h("small",{style:"color: #ff9800;"},n.value)]);default:return h("div",{class:"message-image-error"},"未知状态")}}}}),ge=Ce({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const a=(()=>{try{const o=JSON.parse(e.data);if(o.meta&&o.meta.detail_1){const s=o.meta.detail_1;return{type:"share_card",title:s.title||o.prompt||"分享内容",desc:s.desc||"",preview:s.preview?s.preview.replace(/\\\//g,"/"):"",icon:s.icon?s.icon.replace(/\\\//g,"/"):"",url:s.qqdocurl?s.qqdocurl.replace(/\\\//g,"/"):s.url?s.url.replace(/\\\//g,"/"):"",appName:s.title||"应用"}}return{type:"raw",data:o}}catch(o){return console.error("解析JSON数据失败:",o),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{a.type==="share_card"&&a.url&&window.open(a.url,"_blank","noopener,noreferrer")};return()=>a.type==="share_card"&&a.preview?h("img",{src:a.preview,alt:a.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:a.url?"pointer":"default"},title:a.url?`点击打开: ${a.title||"链接"}`:a.title,onError:o=>{const i=o.target.parentElement;i&&(i.style.display="none")}}):a.type==="error"?h("div",{class:"message-json-error"},[h("span",{class:"json-error-text"},a.error),h("details",{class:"json-raw-data"},[h("summary","查看原始数据"),h("pre",{class:"json-raw-content"},e.data)])]):h("div",{class:"message-json-raw"},[h("div",{class:"json-label"},"[JSON数据]"),h("details",{class:"json-raw-data"},[h("summary","查看详情"),h("pre",{class:"json-raw-content"},JSON.stringify(a.data,null,2))])])}}),G=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=v(false),a=()=>{t.value=!t.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(d=>d.type==="message"),i=s.length;return{previews:s.slice(0,3).map(d=>{var w,R;const p=((w=d.attrs)==null?void 0:w.nickname)||"用户";let k="";if(d.children&&d.children.length>0){const z=d.children[0];z.type==="text"?(k=(((R=z.attrs)==null?void 0:R.content)||"").substring(0,20),k.length>15&&(k+="...")):z.type==="img"?k="[图片]":z.type==="video"?k="[视频]":k=`[${z.type}]`}return`${p}:${k}`}),messageCount:i}},o=(s,i)=>{var p,k,w;const c=((p=s.attrs)==null?void 0:p.nickname)||"用户",d=((k=s.attrs)==null?void 0:k.userId)||"unknown";return h("div",{key:i,class:"forwarded-message-item"},[h("div",{class:"forwarded-message-header"},[h("span",{class:"forwarded-message-nickname"},c),h("span",{class:"forwarded-message-userid"},`(${d})`)]),h("div",{class:"forwarded-message-content"},((w=s.children)==null?void 0:w.map((R,z)=>h(ke,{key:z,element:R,channelKey:e.channelKey})))||[])])};return()=>{var c;const{previews:s,messageCount:i}=n();return h("div",{class:"forward-message-container"},[h("div",{class:"forward-message-preview",onClick:a},[h("div",{class:"forward-message-title"},"聊天记录"),...s.map((d,p)=>h("div",{key:p,class:"forward-message-preview-item"},d)),h("div",{class:"forward-message-footer"},[h("span",{class:"forward-message-count"},`查看${i}条转发消息`),h("span",{class:"forward-message-toggle"},t.value?"▲":"▼")])]),t.value&&h("div",{class:"forward-message-expanded"},((c=e.element.children)==null?void 0:c.filter(d=>d.type==="message").map((d,p)=>o(d,p)))||[])])}}}),ke=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=a=>{var n,o,s,i,c,d;switch(a.type){case"text":return h("span",{class:"message-text-content"},a.attrs.content||"");case"forward":return h("span",{class:"message-text-content"},`[转发消息 ${a.attrs.id}]`||"[转发消息]");case"img":case"image":const p=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(X,{src:p,alt:a.attrs.summary||"图片",filename:a.attrs.filename||a.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const k=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(X,{src:k,alt:a.attrs.summary||"表情",filename:a.attrs.emojiId||a.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((o=(n=a.children[0])==null?void 0:n.attrs)!=null&&o.src){const w=((i=(s=a.children[0])==null?void 0:s.attrs)==null?void 0:i.src)||((d=(c=a.children[0])==null?void 0:c.attrs)==null?void 0:d.url);return h("div",{class:"message-image-container"},[h(X,{src:w,alt:a.attrs.name||a.attrs.id||"[表情]",filename:a.attrs.name||a.attrs.id||"[表情]",channelKey:e.channelKey})])}else return h("span",{class:"message-text-content"},`[${a.attrs.name||a.attrs.id}]`||"[表情]");case"at":return h("span",{class:"message-at",title:a.attrs.name},`${a.attrs.name||a.attrs.id}`);case"json":return h("div",{class:"message-image-container"},[h(ge,{data:a.attrs.data||"",channelKey:e.channelKey})]);case"p":if(a.children&&a.children.length>0){const w=a.children.map((R,z)=>h(ke,{key:z,element:R,channelKey:e.channelKey}));return h("div",{class:"message-paragraph"},w)}else return h("div",{class:"message-paragraph"},"");case"figure":return h(G,{element:a,channelKey:e.channelKey});default:return h("span",{class:"message-unknown",title:`未知消息类型: ${a.type}`},a.attrs.content||`[${a.type}]`)}};return()=>t(e.element)}}),u=v({bots:{},channels:{},messages:{}}),q=v({}),ce=v({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=v({}),be=100*1024*1024,ie=50;let ye=0,I=null;const Re="ChatImageCache",Oe=2,S="images",te=50*1024*1024,U=100,ue=500,Te=2*1024*1024,Fe=.8,We=60*1e3;let O=0,K=0,He=0;const g=v(""),$=v(""),Se=v(""),Y=v([]),de=v(false),Le=v(),L=v(false),V=v("bots"),F=v(null),ae=v(null),Be=v(false),fe=v({show:false,text:""}),B=v(),he=v(),$e=v(false),ne=v(false),me=v(false),se=v(""),M=v({x:0,y:0}),A=v({x:0,y:0}),_e=v({x:0,y:0}),pe=v({x:0,y:0}),H=80,qe=v(0),j=v(null),Z=v(false),C=v(null),N=v({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),W=v(new Set),oe=v(new Set),m=Q(()=>Object.values(u.value.bots).sort((t,a)=>{const n=W.value.has(t.selfId),o=W.value.has(a.selfId);return n&&!o?-1:!n&&o?1:0})),l=Q(()=>!g.value||!u.value.channels[g.value]?[]:Object.values(u.value.channels[g.value]).sort((t,a)=>{const n=oe.value.has(`${g.value}:${t.id}`),o=oe.value.has(`${g.value}:${a.id}`);return n&&!o?-1:!n&&o?1:0})),D=Q(()=>{if(!g.value||!$.value)return[];const e=`${g.value}:${$.value}`,t=u.value.messages[e]||[];return t.filter(a=>a.quote),t}),Ue=Q(()=>{var t;if(!g.value||!$.value)return"";const e=u.value.channels[g.value];return((t=e==null?void 0:e[$.value])==null?void 0:t.name)||""}),$t=Q(()=>!g.value||!$.value?"":`${g.value}:${$.value}`),lt=Q(()=>g.value&&$.value&&(Se.value.trim()||Y.value.length>0)&&!me.value),_t=Q(()=>g.value&&$.value&&!me.value),Dt=Q(()=>{if(!L.value)return"";switch(V.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),Tt=Q(()=>L.value?"输入消息...(屏幕左滑返回)":"输入消息..."),Lt=Q(()=>({}));function ct(e){return e.size||0}function Xe(e){ye+=e,ce.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(ye/1024/1024).toFixed(2)}MB`)}function it(e=10){const t=Object.entries(b.value);if(t.length<=e)return;const a=t.slice(0,t.length-e);let n=0;a.forEach(([o,s])=>{URL.revokeObjectURL(s),delete b.value[o],n+=500*1024,ce.value.loggerinfo&&console.log("清理旧blob URL:",o)}),Xe(-n)}function Je(){Object.keys(b.value).length>ie&&it(Math.floor(ie*.7)),ye>be&&it(Math.floor(ie*.5))}function qt(e){g.value=e,$.value="",L.value&&(V.value="channels")}function Ut(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="bot"&&N.value.targetId===t){J();return}Ge(e,"bot",t)}function Kt(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="channel"&&N.value.targetId===t){J();return}Ge(e,"channel",t)}function Ge(e,t,a){let s=e.clientX,i=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),i+80>window.innerHeight&&(i=window.innerHeight-80-10),N.value={show:true,x:s,y:i,type:t,targetId:a,isSecondClick:false},document.addEventListener("click",J,{once:true}),document.addEventListener("keydown",Ze)}function J(){N.value.show=false,document.removeEventListener("click",J),document.removeEventListener("keydown",Ze)}function Ze(e){e.key==="Escape"&&N.value.show&&J()}async function Mt(e){W.value.has(e)?W.value.delete(e):W.value.add(e),await P("set-pinned-bots",{pinnedBots:Array.from(W.value)}),J()}async function At(e){const t=`${g.value}:${e}`;oe.value.has(t)?oe.value.delete(t):oe.value.add(t),await P("set-pinned-channels",{pinnedChannels:Array.from(oe.value)}),J()}async function zt(e){try{const t=await P("delete-bot-data",{selfId:e});if(t.success){const a=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of a)delete u.value.messages[n],delete q.value[n],await je(n);delete u.value.bots[e],delete u.value.channels[e],g.value===e&&(g.value="",$.value=""),T(t.message||"已删除该机器人的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除机器人数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}J()}async function Pt(e){try{const t=await P("delete-channel-data",{selfId:g.value,channelId:e});if(t.success){const a=`${g.value}:${e}`;delete u.value.messages[a],delete q.value[a],u.value.channels[g.value]&&delete u.value.channels[g.value][e],await je(a),$.value===e&&($.value=""),T(t.message||"已删除该频道的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除频道数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}J()}async function jt(e){$.value=e,ne.value=false,L.value&&(V.value="messages"),g.value&&await It(g.value,e),Ie(()=>{ve(),!L.value&&he.value&&he.value.focus()})}async function Nt(){if(!lt.value)return;const e=Se.value.trim();if(!e&&Y.value.length===0)return;me.value=true;const t=[...Y.value];try{const a=await P("send-message",{selfId:g.value,channelId:$.value,content:e,images:t.map(n=>({tempId:n.tempId,filename:n.filename}))});if(a.success){if(Se.value="",t.forEach(n=>{URL.revokeObjectURL(n.preview)}),Y.value=[],de.value=false,a.tempImageIds&&a.tempImageIds.length>0)try{await P("cleanup-temp-images",{tempImageIds:a.tempImageIds}),console.log("临时图片清理完成:",a.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",a.error),T("发送失败: "+a.error,"error")}catch(a){console.error("发送消息时出错:",a),T("发送失败: "+((a==null?void 0:a.message)||String(a)),"error")}finally{me.value=false}}function Rt(){de.value=!de.value}function Ot(){Le.value&&Le.value.click(),de.value=false}async function Ft(e){const t=e.target,a=t.files;if(!(!a||a.length===0)){for(const n of Array.from(a))await Qe(n);t.value=""}}async function Ht(e){var a;const t=(a=e.clipboardData)==null?void 0:a.items;if(t){for(const n of Array.from(t))if(n.type.startsWith("image/")){e.preventDefault();const o=n.getAsFile();o&&await Qe(o)}}}async function Qe(e){try{if(e.size>10*1024*1024){T("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){T("请选择图片文件","error");return}const t=await ut(e),a=URL.createObjectURL(e),n=await P("upload-image",{file:t,filename:e.name,mimeType:e.type});n.success?Y.value.push({tempId:n.tempId,filename:e.name,preview:a,size:e.size}):(URL.revokeObjectURL(a),T("图片上传失败: "+n.error,"error"))}catch(t){console.error("上传图片失败:",t),T("图片上传失败: "+((t==null?void 0:t.message)||String(t)),"error")}}async function Xt(e){try{const t=Y.value.findIndex(a=>a.tempId===e);if(t!==-1){const a=Y.value[t];URL.revokeObjectURL(a.preview),Y.value.splice(t,1)}await P("delete-temp-image",{tempId:e})}catch(t){console.error("删除图片失败:",t)}}function ut(e){return new Promise((t,a)=>{const n=new FileReader;n.onload=()=>t(n.result),n.onerror=a,n.readAsDataURL(e)})}function Ee(e){const t=e.target;t.closest(".input-actions")||(de.value=false),t.closest(".context-menu")||J()}function Yt(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function Vt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function ve(){B.value&&(B.value.scrollTop=B.value.scrollHeight,$e.value=false,ne.value=false)}function Ke(){if(B.value){const{scrollTop:e,scrollHeight:t,clientHeight:a}=B.value,o=t-(e+a)<=50,s=!o;$e.value=s,o?ne.value=false:ne.value=true}}function Me(){if(!B.value)return true;const{scrollTop:e,scrollHeight:t,clientHeight:a}=B.value;return t-(e+a)<=200}function dt(e){var n;if(!g.value)return 0;const t=`${g.value}:${e}`,a=q.value[t];return a!==void 0?a:((n=u.value.messages[t])==null?void 0:n.length)||0}function Wt(e,t){e.preventDefault(),e.stopPropagation();const a="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;qe.value=Date.now(),M.value={x:a,y:n},A.value={x:a,y:n},Z.value=false;const s=e.target.getBoundingClientRect();_e.value={x:s.left,y:s.top},pe.value={x:a-s.left,y:n-s.top},j.value=window.setTimeout(()=>{if(qe.value>0){Z.value=true,se.value=t;const i=e.target,c=i.cloneNode(true);c.classList.add("dragging-clone"),c.style.position="fixed",c.style.zIndex="1000",c.style.pointerEvents="none";const d=i.getBoundingClientRect();c.style.left=`${d.left}px`,c.style.top=`${d.top}px`,c.style.width=`${d.width}px`,c.style.height=`${d.height}px`,document.body.appendChild(c),C.value=c,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),ht(M.value.x,M.value.y)}},60),document.addEventListener("mousemove",Ae),document.addEventListener("mouseup",ze),document.addEventListener("touchmove",Ae),document.addEventListener("touchend",ze)}function Ae(e){if(!Z.value||!C.value)return;e.preventDefault();const t="touches"in e?e.touches[0].clientX:e.clientX,a="touches"in e?e.touches[0].clientY:e.clientY;A.value={x:t,y:a};const n=A.value.x-M.value.x,o=A.value.y-M.value.y,s=Math.sqrt(n*n+o*o),i=Math.max(.3,1-s/(H*2)),c=Math.max(.8,1-s/(H*3)),d=s>H,p=A.value.x-pe.value.x,k=A.value.y-pe.value.y;C.value.style.left=`${p}px`,C.value.style.top=`${k}px`,C.value.style.transform=`scale(${c})`,C.value.style.opacity=`${i}`,C.value.style.backgroundColor=d?"#f44336":"#2196f3",C.value.style.boxShadow=d?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",d?C.value.classList.add("will-delete"):C.value.classList.remove("will-delete")}function ze(e){if(j.value&&(clearTimeout(j.value),j.value=null),j.value&&(clearTimeout(j.value),j.value=null),!Z.value||!se.value){Pe();return}const t=se.value;if(Math.sqrt(Math.pow(A.value.x-M.value.x,2)+Math.pow(A.value.y-M.value.y,2))>H)ft(t),Pe();else if(C.value){C.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${t}"] .channel-message-count`);if(n){const o=n.getBoundingClientRect();C.value.style.left=`${o.left}px`,C.value.style.top=`${o.top}px`,C.value.style.transform="scale(1)",C.value.style.opacity="1",C.value.style.backgroundColor="#2196f3",C.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{Pe()},300)}else Pe()}function Pe(){j.value&&(clearTimeout(j.value),j.value=null),se.value="",M.value={x:0,y:0},A.value={x:0,y:0},_e.value={x:0,y:0},qe.value=0,Z.value=false,document.removeEventListener("mousemove",Ae),document.removeEventListener("mouseup",ze),document.removeEventListener("touchmove",Ae),document.removeEventListener("touchend",ze),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),C.value&&C.value.parentNode&&(C.value.parentNode.removeChild(C.value),C.value=null),mt()}function Jt(e){return se.value===e&&Z.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function Gt(e){if(se.value!==e)return 0;const t=A.value.x-M.value.x,a=A.value.y-M.value.y;return Math.sqrt(t*t+a*a)}async function ft(e){if(g.value)try{const t=`${g.value}:${e}`,a=dt(e),n=ce.value.keepMessagesOnClear;if(n>0&&a<=n){T("当前消息还很少诶~ 无需清理","success");return}const o=await P("clear-channel-history",{selfId:g.value,channelId:e});if(o.success)if(o.clearedCount&&o.clearedCount>0){if(u.value.messages[t]){const i=[...u.value.messages[t]].sort((c,d)=>c.timestamp-d.timestamp);u.value.messages[t]=i.slice(-o.keptCount)}q.value[t]=o.keptCount,await je(t),T(`历史记录已清理,清理了 ${o.clearedCount} 条消息,保留最新 ${o.keptCount} 条`,"success")}else n===0?(u.value.messages[t]&&(u.value.messages[t]=[]),q.value[t]=0,await je(t),T("历史记录已清理,所有消息已删除","success")):T("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",o.error),T("清理失败: "+o.error,"error")}catch(t){console.error("清理历史记录时出错:",t),T("清理失败: "+((t==null?void 0:t.message)||String(t)),"error")}}function T(e,t="success"){const a=document.createElement("div");a.className=`notification ${t}`,a.textContent=e;let n="#4caf50";switch(t){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}a.style.cssText=`
|
|
1
|
+
import{defineComponent as Ce,ref as v,onMounted as st,h,computed as E,watch as St,nextTick as ye,onUnmounted as ga,createElementBlock as x,openBlock as y,unref as r,normalizeStyle as ot,normalizeClass as le,createCommentVNode as B,createElementVNode as f,Fragment as ee,renderList as _e,createBlock as Re,toDisplayString as _,withDirectives as Bt,createTextVNode as rt,vShow as ya,withModifiers as $t,withKeys as pa,isRef as wa,vModelText as Ia,resolveComponent as xa}from"vue";import{receive as lt,send as P,icons as Ca}from"@koishijs/client";function ka(){function te(e){try{return new URL(e).protocol==="file:"}catch{return false}}const ce=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=async()=>{try{t.value="loading";const i=await Ve(e.channelKey,e.src);if(i){a.value=i,t.value="loaded";return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const d=new Promise((k,w)=>{c.onload=()=>k(),c.onerror=()=>w(new Error("Direct load failed")),c.src=e.src}),p=new Promise((k,w)=>{setTimeout(()=>w(new Error("Timeout")),3e3)});try{await Promise.race([d,p]),a.value=e.src,t.value="loaded",xe(e.channelKey,e.src).catch(k=>{console.warn("异步缓存头像失败:",k)})}catch{await s()}}catch(i){console.error("头像加载失败:",i),t.value="error",n.value="头像加载失败"}},s=async()=>{try{t.value="caching";const i=await xe(e.channelKey,e.src);if(i)a.value=i,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(i){console.error("缓存系统加载头像失败:",i),t.value="error",n.value=(i==null?void 0:i.message)||"缓存加载失败"}};return st(()=>{o()}),()=>{switch(t.value){case"loading":case"caching":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return h("img",{src:a.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return h("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),Y=Ce({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const t=v("loading"),a=v(e.src),n=v(""),o=v(null),s=async()=>{try{t.value="loading";const c=await Ve(e.channelKey,e.src);if(c){a.value=c,t.value="loaded";return}if(te(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await i();return}const d=new Image;d.crossOrigin="anonymous",d.referrerPolicy="no-referrer",d.draggable=false;const p=new Promise((w,O)=>{d.onload=()=>w(),d.onerror=()=>O(new Error("Direct load failed")),d.src=e.src}),k=new Promise((w,O)=>{setTimeout(()=>O(new Error("Timeout")),3e3)});try{await Promise.race([p,k]),a.value=e.src,t.value="loaded",xe(e.channelKey,e.src).catch(w=>{console.warn("异步缓存图片失败:",w)})}catch{await i()}}catch(c){console.error("图片加载失败:",c),t.value="error",n.value="图片加载失败"}},i=async()=>{try{t.value="caching";const c=await xe(e.channelKey,e.src);if(c)a.value=c,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(c){console.error("缓存系统加载图片失败:",c),t.value="error",n.value=(c==null?void 0:c.message)||"缓存加载失败"}};return st(()=>{s()}),()=>{switch(t.value){case"loading":return h("div",{class:"message-image-loading"},"加载中...");case"caching":return h("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return h("img",{src:a.value,alt:e.alt,class:"message-image",loading:"lazy",ref:o,draggable:false,style:{"max-width":"min(400px, 66.67vw)","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"},onLoad:()=>{o.value&&e.src.toLowerCase().includes(".gif")&&(o.value.style.imageRendering="auto")}});case"error":return h("div",{class:"message-image-error"},["图片加载失败",h("br"),h("small",e.filename||e.alt||"未知图片"),h("br"),h("small",{style:"color: #ff9800;"},n.value)]);default:return h("div",{class:"message-image-error"},"未知状态")}}}}),pe=Ce({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const a=(()=>{try{const o=JSON.parse(e.data);if(o.meta&&o.meta.detail_1){const s=o.meta.detail_1;return{type:"share_card",title:s.title||o.prompt||"分享内容",desc:s.desc||"",preview:s.preview?s.preview.replace(/\\\//g,"/"):"",icon:s.icon?s.icon.replace(/\\\//g,"/"):"",url:s.qqdocurl?s.qqdocurl.replace(/\\\//g,"/"):s.url?s.url.replace(/\\\//g,"/"):"",appName:s.title||"应用"}}return{type:"raw",data:o}}catch(o){return console.error("解析JSON数据失败:",o),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{a.type==="share_card"&&a.url&&window.open(a.url,"_blank","noopener,noreferrer")};return()=>a.type==="share_card"&&a.preview?h("img",{src:a.preview,alt:a.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:a.url?"pointer":"default"},title:a.url?`点击打开: ${a.title||"链接"}`:a.title,onError:o=>{const i=o.target.parentElement;i&&(i.style.display="none")}}):a.type==="error"?h("div",{class:"message-json-error"},[h("span",{class:"json-error-text"},a.error),h("details",{class:"json-raw-data"},[h("summary","查看原始数据"),h("pre",{class:"json-raw-content"},e.data)])]):h("div",{class:"message-json-raw"},[h("div",{class:"json-label"},"[JSON数据]"),h("details",{class:"json-raw-data"},[h("summary","查看详情"),h("pre",{class:"json-raw-content"},JSON.stringify(a.data,null,2))])])}}),Z=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=v(false),a=()=>{t.value=!t.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(d=>d.type==="message"),i=s.length;return{previews:s.slice(0,3).map(d=>{var w,O;const p=((w=d.attrs)==null?void 0:w.nickname)||"用户";let k="";if(d.children&&d.children.length>0){const z=d.children[0];z.type==="text"?(k=(((O=z.attrs)==null?void 0:O.content)||"").substring(0,20),k.length>15&&(k+="...")):z.type==="img"?k="[图片]":z.type==="video"?k="[视频]":k=`[${z.type}]`}return`${p}:${k}`}),messageCount:i}},o=(s,i)=>{var p,k,w;const c=((p=s.attrs)==null?void 0:p.nickname)||"用户",d=((k=s.attrs)==null?void 0:k.userId)||"unknown";return h("div",{key:i,class:"forwarded-message-item"},[h("div",{class:"forwarded-message-header"},[h("span",{class:"forwarded-message-nickname"},c),h("span",{class:"forwarded-message-userid"},`(${d})`)]),h("div",{class:"forwarded-message-content"},((w=s.children)==null?void 0:w.map((O,z)=>h(ke,{key:z,element:O,channelKey:e.channelKey})))||[])])};return()=>{var c;const{previews:s,messageCount:i}=n();return h("div",{class:"forward-message-container"},[h("div",{class:"forward-message-preview",onClick:a},[h("div",{class:"forward-message-title"},"聊天记录"),...s.map((d,p)=>h("div",{key:p,class:"forward-message-preview-item"},d)),h("div",{class:"forward-message-footer"},[h("span",{class:"forward-message-count"},`查看${i}条转发消息`),h("span",{class:"forward-message-toggle"},t.value?"▲":"▼")])]),t.value&&h("div",{class:"forward-message-expanded"},((c=e.element.children)==null?void 0:c.filter(d=>d.type==="message").map((d,p)=>o(d,p)))||[])])}}}),ke=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=a=>{var n,o,s,i,c,d;switch(a.type){case"text":return h("span",{class:"message-text-content"},a.attrs.content||"");case"forward":return h("span",{class:"message-text-content"},`[转发消息 ${a.attrs.id}]`||"[转发消息]");case"img":case"image":const p=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(Y,{src:p,alt:a.attrs.summary||"图片",filename:a.attrs.filename||a.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const k=a.attrs.src||a.attrs.url||a.attrs.file;return h("div",{class:"message-image-container"},[h(Y,{src:k,alt:a.attrs.summary||"表情",filename:a.attrs.emojiId||a.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((o=(n=a.children[0])==null?void 0:n.attrs)!=null&&o.src){const w=((i=(s=a.children[0])==null?void 0:s.attrs)==null?void 0:i.src)||((d=(c=a.children[0])==null?void 0:c.attrs)==null?void 0:d.url);return h("div",{class:"message-image-container"},[h(Y,{src:w,alt:a.attrs.name||a.attrs.id||"[表情]",filename:a.attrs.name||a.attrs.id||"[表情]",channelKey:e.channelKey})])}else return h("span",{class:"message-text-content"},`[${a.attrs.name||a.attrs.id}]`||"[表情]");case"at":return h("span",{class:"message-at",title:a.attrs.name},`${a.attrs.name||a.attrs.id}`);case"json":return h("div",{class:"message-image-container"},[h(pe,{data:a.attrs.data||"",channelKey:e.channelKey})]);case"p":if(a.children&&a.children.length>0){const w=a.children.map((O,z)=>h(ke,{key:z,element:O,channelKey:e.channelKey}));return h("div",{class:"message-paragraph"},w)}else return h("div",{class:"message-paragraph"},"");case"figure":return h(Z,{element:a,channelKey:e.channelKey});default:return h("span",{class:"message-unknown",title:`未知消息类型: ${a.type}`},a.attrs.content||`[${a.type}]`)}};return()=>t(e.element)}}),u=v({bots:{},channels:{},messages:{}}),U=v({}),ie=v({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=v({}),be=100*1024*1024,ue=50;let we=0,I=null;const Ne="ChatImageCache",Oe=2,$="images",ae=50*1024*1024,M=100,de=500,Le=2*1024*1024,Fe=.8,We=60*1e3;let F=0,K=0,He=0;const g=v(""),S=v(""),Se=v(""),V=v([]),fe=v(false),Te=v(),q=v(false),W=v("bots"),H=v(null),ne=v(null),Be=v(false),he=v({show:false,text:""}),D=v(),me=v(),$e=v(false),se=v(false),ve=v(false),oe=v(""),j=v({x:0,y:0}),A=v({x:0,y:0}),De=v({x:0,y:0}),Ie=v({x:0,y:0}),X=80,qe=v(0),R=v(null),Q=v(false),C=v(null),N=v({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),J=v(new Set),re=v(new Set),m=E(()=>Object.values(u.value.bots).sort((t,a)=>{const n=J.value.has(t.selfId),o=J.value.has(a.selfId);return n&&!o?-1:!n&&o?1:0})),l=E(()=>!g.value||!u.value.channels[g.value]?[]:Object.values(u.value.channels[g.value]).sort((t,a)=>{const n=re.value.has(`${g.value}:${t.id}`),o=re.value.has(`${g.value}:${a.id}`);return n&&!o?-1:!n&&o?1:0})),L=E(()=>{if(!g.value||!S.value)return[];const e=`${g.value}:${S.value}`,t=u.value.messages[e]||[];return t.filter(a=>a.quote),t}),Ue=E(()=>{var t;if(!g.value||!S.value)return"";const e=u.value.channels[g.value];return((t=e==null?void 0:e[S.value])==null?void 0:t.name)||""}),_t=E(()=>!g.value||!S.value?"":`${g.value}:${S.value}`),ct=E(()=>g.value&&S.value&&(Se.value.trim()||V.value.length>0)&&!ve.value),Lt=E(()=>g.value&&S.value&&!ve.value),Tt=E(()=>{if(!q.value)return"";switch(W.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),qt=E(()=>q.value?"输入消息...(屏幕左滑返回)":"输入消息..."),Ut=E(()=>({}));function it(e){return e.size||0}function Xe(e){we+=e,ie.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(we/1024/1024).toFixed(2)}MB`)}function ut(e=10){const t=Object.entries(b.value);if(t.length<=e)return;const a=t.slice(0,t.length-e);let n=0;a.forEach(([o,s])=>{URL.revokeObjectURL(s),delete b.value[o],n+=500*1024,ie.value.loggerinfo&&console.log("清理旧blob URL:",o)}),Xe(-n)}function Je(){Object.keys(b.value).length>ue&&ut(Math.floor(ue*.7)),we>be&&ut(Math.floor(ue*.5))}function Mt(e){g.value=e,S.value="",at(),q.value&&(W.value="channels")}function Kt(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="bot"&&N.value.targetId===t){G();return}Ge(e,"bot",t)}function jt(e,t){if(e.preventDefault(),e.stopPropagation(),N.value.show&&N.value.type==="channel"&&N.value.targetId===t){G();return}Ge(e,"channel",t)}function Ge(e,t,a){let s=e.clientX,i=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),i+80>window.innerHeight&&(i=window.innerHeight-80-10),N.value={show:true,x:s,y:i,type:t,targetId:a,isSecondClick:false},document.addEventListener("click",G,{once:true}),document.addEventListener("keydown",Ze)}function G(){N.value.show=false,document.removeEventListener("click",G),document.removeEventListener("keydown",Ze)}function Ze(e){e.key==="Escape"&&N.value.show&&G()}async function At(e){J.value.has(e)?J.value.delete(e):J.value.add(e),await P("set-pinned-bots",{pinnedBots:Array.from(J.value)}),G()}async function zt(e){const t=`${g.value}:${e}`;re.value.has(t)?re.value.delete(t):re.value.add(t),await P("set-pinned-channels",{pinnedChannels:Array.from(re.value)}),G()}async function Pt(e){try{const t=await P("delete-bot-data",{selfId:e});if(t.success){const a=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of a)delete u.value.messages[n],delete U.value[n],await Pe(n);delete u.value.bots[e],delete u.value.channels[e],g.value===e&&(g.value="",S.value=""),T(t.message||"已删除该机器人的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除机器人数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}G()}async function Rt(e){try{const t=await P("delete-channel-data",{selfId:g.value,channelId:e});if(t.success){const a=`${g.value}:${e}`;delete u.value.messages[a],delete U.value[a],u.value.channels[g.value]&&delete u.value.channels[g.value][e],await Pe(a),S.value===e&&(S.value=""),T(t.message||"已删除该频道的所有数据","success")}else throw new Error(t.error||"删除失败")}catch(t){console.error("删除频道数据失败:",t),T("删除失败: "+((t==null?void 0:t.message)||String(t)),"error")}G()}async function Nt(e){S.value=e,se.value=false,at(),q.value&&(W.value="messages"),g.value&&await Ct(g.value,e),ye(()=>{ge(),!q.value&&me.value&&me.value.focus()})}async function Ot(){if(!ct.value)return;const e=Se.value.trim();if(!e&&V.value.length===0)return;ve.value=true;const t=[...V.value];try{const a=await P("send-message",{selfId:g.value,channelId:S.value,content:e,images:t.map(n=>({tempId:n.tempId,filename:n.filename}))});if(a.success){if(Se.value="",t.forEach(n=>{URL.revokeObjectURL(n.preview)}),V.value=[],fe.value=false,a.tempImageIds&&a.tempImageIds.length>0)try{await P("cleanup-temp-images",{tempImageIds:a.tempImageIds}),console.log("临时图片清理完成:",a.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",a.error),T("发送失败: "+a.error,"error")}catch(a){console.error("发送消息时出错:",a),T("发送失败: "+((a==null?void 0:a.message)||String(a)),"error")}finally{ve.value=false}}function Ft(){fe.value=!fe.value}function Ht(){Te.value&&Te.value.click(),fe.value=false}async function Xt(e){const t=e.target,a=t.files;if(!(!a||a.length===0)){for(const n of Array.from(a))await Qe(n);t.value=""}}async function Yt(e){var a;const t=(a=e.clipboardData)==null?void 0:a.items;if(t){for(const n of Array.from(t))if(n.type.startsWith("image/")){e.preventDefault();const o=n.getAsFile();if(o){const s=n.type==="image/gif"?".gif":n.type==="image/png"?".png":(n.type==="image/jpeg",".jpg"),i=`pasted-image-${Date.now()}${s}`,c=new File([o],i,{type:n.type,lastModified:Date.now()});await Qe(c)}}}}async function Qe(e){try{if(e.size>10*1024*1024){T("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){T("请选择图片文件","error");return}const t=await dt(e),a=URL.createObjectURL(e),n=await P("upload-image",{file:t,filename:e.name,mimeType:e.type,isGif:e.type==="image/gif"});n.success?V.value.push({tempId:n.tempId,filename:e.name,preview:a,size:e.size}):(URL.revokeObjectURL(a),T("图片上传失败: "+n.error,"error"))}catch(t){console.error("上传图片失败:",t),T("图片上传失败: "+((t==null?void 0:t.message)||String(t)),"error")}}async function Vt(e){try{const t=V.value.findIndex(a=>a.tempId===e);if(t!==-1){const a=V.value[t];URL.revokeObjectURL(a.preview),V.value.splice(t,1)}await P("delete-temp-image",{tempId:e})}catch(t){console.error("删除图片失败:",t)}}function dt(e){return new Promise((t,a)=>{const n=new FileReader;n.onload=()=>t(n.result),n.onerror=a,n.readAsDataURL(e)})}function Ee(e){const t=e.target;t.closest(".input-actions")||(fe.value=false),t.closest(".context-menu")||G()}function Wt(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function Jt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function ge(){D.value&&(D.value.scrollTop=D.value.scrollHeight,$e.value=false,se.value=false)}function Me(){if(D.value){const{scrollTop:e,scrollHeight:t,clientHeight:a}=D.value,o=t-(e+a)<=50,s=!o;$e.value=s,o?se.value=false:se.value=true}}function Ke(){if(!D.value)return true;const{scrollTop:e,scrollHeight:t,clientHeight:a}=D.value;return t-(e+a)<=200}function ft(e){var n;if(!g.value)return 0;const t=`${g.value}:${e}`,a=U.value[t];return a!==void 0?a:((n=u.value.messages[t])==null?void 0:n.length)||0}function Gt(e,t){e.preventDefault(),e.stopPropagation();const a="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;qe.value=Date.now(),j.value={x:a,y:n},A.value={x:a,y:n},Q.value=false;const s=e.target.getBoundingClientRect();De.value={x:s.left,y:s.top},Ie.value={x:a-s.left,y:n-s.top},R.value=window.setTimeout(()=>{if(qe.value>0){Q.value=true,oe.value=t;const i=e.target,c=i.cloneNode(true);c.classList.add("dragging-clone"),c.style.position="fixed",c.style.zIndex="1000",c.style.pointerEvents="none";const d=i.getBoundingClientRect();c.style.left=`${d.left}px`,c.style.top=`${d.top}px`,c.style.width=`${d.width}px`,c.style.height=`${d.height}px`,document.body.appendChild(c),C.value=c,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),mt(j.value.x,j.value.y)}},60),document.addEventListener("mousemove",je),document.addEventListener("mouseup",Ae),document.addEventListener("touchmove",je),document.addEventListener("touchend",Ae)}function je(e){if(!Q.value||!C.value)return;e.preventDefault();const t="touches"in e?e.touches[0].clientX:e.clientX,a="touches"in e?e.touches[0].clientY:e.clientY;A.value={x:t,y:a};const n=A.value.x-j.value.x,o=A.value.y-j.value.y,s=Math.sqrt(n*n+o*o),i=Math.max(.3,1-s/(X*2)),c=Math.max(.8,1-s/(X*3)),d=s>X,p=A.value.x-Ie.value.x,k=A.value.y-Ie.value.y;C.value.style.left=`${p}px`,C.value.style.top=`${k}px`,C.value.style.transform=`scale(${c})`,C.value.style.opacity=`${i}`,C.value.style.backgroundColor=d?"#f44336":"#2196f3",C.value.style.boxShadow=d?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",d?C.value.classList.add("will-delete"):C.value.classList.remove("will-delete")}function Ae(e){if(R.value&&(clearTimeout(R.value),R.value=null),R.value&&(clearTimeout(R.value),R.value=null),!Q.value||!oe.value){ze();return}const t=oe.value;if(Math.sqrt(Math.pow(A.value.x-j.value.x,2)+Math.pow(A.value.y-j.value.y,2))>X)ht(t),ze();else if(C.value){C.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${t}"] .channel-message-count`);if(n){const o=n.getBoundingClientRect();C.value.style.left=`${o.left}px`,C.value.style.top=`${o.top}px`,C.value.style.transform="scale(1)",C.value.style.opacity="1",C.value.style.backgroundColor="#2196f3",C.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{ze()},300)}else ze()}function ze(){R.value&&(clearTimeout(R.value),R.value=null),oe.value="",j.value={x:0,y:0},A.value={x:0,y:0},De.value={x:0,y:0},qe.value=0,Q.value=false,document.removeEventListener("mousemove",je),document.removeEventListener("mouseup",Ae),document.removeEventListener("touchmove",je),document.removeEventListener("touchend",Ae),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),C.value&&C.value.parentNode&&(C.value.parentNode.removeChild(C.value),C.value=null),vt()}function Zt(e){return oe.value===e&&Q.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function Qt(e){if(oe.value!==e)return 0;const t=A.value.x-j.value.x,a=A.value.y-j.value.y;return Math.sqrt(t*t+a*a)}async function ht(e){if(g.value)try{const t=`${g.value}:${e}`,a=ft(e),n=ie.value.keepMessagesOnClear;if(n>0&&a<=n){T("当前消息还很少诶~ 无需清理","success");return}const o=await P("clear-channel-history",{selfId:g.value,channelId:e});if(o.success)if(o.clearedCount&&o.clearedCount>0){if(u.value.messages[t]){const i=[...u.value.messages[t]].sort((c,d)=>c.timestamp-d.timestamp);u.value.messages[t]=i.slice(-o.keptCount)}U.value[t]=o.keptCount,await Pe(t),T(`历史记录已清理,清理了 ${o.clearedCount} 条消息,保留最新 ${o.keptCount} 条`,"success")}else n===0?(u.value.messages[t]&&(u.value.messages[t]=[]),U.value[t]=0,await Pe(t),T("历史记录已清理,所有消息已删除","success")):T("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",o.error),T("清理失败: "+o.error,"error")}catch(t){console.error("清理历史记录时出错:",t),T("清理失败: "+((t==null?void 0:t.message)||String(t)),"error")}}function T(e,t="success"){const a=document.createElement("div");a.className=`notification ${t}`,a.textContent=e;let n="#4caf50";switch(t){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}a.style.cssText=`
|
|
2
2
|
position: fixed;
|
|
3
3
|
top: 20px;
|
|
4
4
|
right: 20px;
|
|
@@ -19,9 +19,9 @@ import{defineComponent as Ce,ref as v,onMounted as nt,h,computed as Q,watch as k
|
|
|
19
19
|
from { transform: translateX(0); opacity: 1; }
|
|
20
20
|
to { transform: translateX(100%); opacity: 0; }
|
|
21
21
|
}
|
|
22
|
-
`,document.head.appendChild(o),document.body.appendChild(a),setTimeout(()=>{a.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{a.parentNode&&a.parentNode.removeChild(a),o.parentNode&&o.parentNode.removeChild(o)},300)},3e3)}function
|
|
23
|
-
left: ${e-
|
|
24
|
-
top: ${t-
|
|
25
|
-
width: ${
|
|
26
|
-
height: ${
|
|
27
|
-
`,document.body.appendChild(a),window.dragThresholdCircle=a}function mt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function et(){try{if(!I)return false;const e=Date.now();if(e-He<We)return true;He=e;const t=await vt();O=t.totalSize,K=t.totalImages,console.log("数据库健康检查:",{大小:`${(O/1024/1024).toFixed(2)}MB / ${(te/1024/1024).toFixed(2)}MB`,图片数量:`${K} / ${ue}`,使用率:`${(O/te*100).toFixed(1)}%`});const a=O/te,n=K/ue;return(a>Fe||n>Fe)&&(console.warn("数据库使用率过高,开始自动清理"),await Ye()),(a>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Zt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function vt(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{const o=n.result||[];let s=0;const i={};o.forEach(c=>{s+=c.size||0,i[c.channelKey]=(i[c.channelKey]||0)+1}),e({totalSize:s,totalImages:o.length,channelStats:i})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function Ye(){try{console.log("开始自动清理...");const e=await gt();if(e.length===0)return;const t={};e.forEach(o=>{t[o.channelKey]||(t[o.channelKey]=[]),t[o.channelKey].push(o)});let a=0,n=0;for(const[o,s]of Object.entries(t))if(s.length>U){s.sort((c,d)=>c.timestamp-d.timestamp);const i=s.slice(0,s.length-U);for(const c of i)await tt(c.url),a++,n+=c.size||0,b.value[c.url]&&(URL.revokeObjectURL(b.value[c.url]),delete b.value[c.url])}console.log(`自动清理完成: 清理了 ${a} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),K-=a,O-=n}catch(e){console.error("自动清理失败:",e)}}async function Zt(){try{console.log("开始紧急清理...");const e=await gt();if(e.length===0)return;e.sort((s,i)=>i.timestamp-s.timestamp);const t=Math.floor(ue*.3),a=e.slice(t);let n=0,o=0;for(const s of a)await tt(s.url),n++,o+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(o/1024/1024).toFixed(2)}MB`),K=t,O-=o}catch(e){console.error("紧急清理失败:",e)}}async function gt(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Qt(){return new Promise(e=>{try{I&&(I.close(),I=null);const t=indexedDB.deleteDatabase(Re);t.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),O=0,K=0,e(true)},t.onerror=()=>{console.error("清理IndexedDB数据库失败:",t.error),e(false)},t.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(t){console.error("清理数据库时出错:",t),e(false)}})}async function Et(){try{return await yt()?(setTimeout(async()=>{const t=await vt();console.log("数据库初始状态:",{大小:`${(t.totalSize/1024/1024).toFixed(2)}MB`,图片数量:t.totalImages,频道分布:t.channelStats}),(t.totalSize>te*.9||t.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await Ye())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Qt(),await yt())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function yt(){return new Promise(e=>{try{const t=indexedDB.open(Re,Oe);t.onerror=()=>{console.error("IndexedDB打开失败:",t.error),e(false)},t.onsuccess=()=>{I=t.result,I.onerror=a=>{console.error("IndexedDB运行时错误:",a)},I.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),I==null||I.close(),I=null},e(true)},t.onupgradeneeded=a=>{const n=a.target.result;if(!n.objectStoreNames.contains(S)){const o=n.createObjectStore(S,{keyPath:"url"});o.createIndex("channelKey","channelKey",{unique:false}),o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},t.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(t){console.error("打开数据库时出错:",t),e(false)}})}async function ea(e){return I?new Promise((t,a)=>{const s=I.transaction([S],"readonly").objectStore(S).get(e);s.onsuccess=()=>{t(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),t(null)}}):null}async function pt(e){if(!I)return false;try{return e.size>Te?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Te/1024/1024).toFixed(2)}MB`),false):(await et(),O+e.size>te&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await Ye(),O+e.size>te)?(console.warn("清理后仍会超过限制,跳过此图片"),false):K>=ue&&(console.warn("图片数量已达上限,执行清理"),await Ye(),K>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(t=>{const o=I.transaction([S],"readwrite").objectStore(S).put(e);o.onsuccess=()=>{O+=e.size,K+=1,t(true)},o.onerror=()=>{console.error("保存图片到IndexedDB失败:",o.error),t(false)}}))}catch(t){return console.error("保存图片时出错:",t),false}}async function tt(e){return I?new Promise(t=>{const o=I.transaction([S],"readwrite").objectStore(S).delete(e);o.onsuccess=()=>{t(true)},o.onerror=()=>{console.error("从IndexedDB删除图片失败:",o.error),t(false)}}):false}async function ta(e){return I?new Promise(t=>{const s=I.transaction([S],"readonly").objectStore(S).index("channelKey").getAll(e);s.onsuccess=()=>{t(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),t([])}}):[]}async function Ve(e,t){const a=b.value[t];if(a)return a;const n=await ea(t);if(!n)return null;Je();const o=URL.createObjectURL(n.blob);return b.value[t]=o,Xe(ct(n.blob)),n.timestamp=Date.now(),await pt(n),o}async function we(e,t){try{const a=await Ve(e,t);if(a)return a;const n=await P("fetch-image",{url:t});if(!n.success)return console.error("获取图片失败:",n.error),null;const o=n.base64,s=n.contentType||"image/jpeg",i=atob(o),c=new Array(i.length);for(let z=0;z<i.length;z++)c[z]=i.charCodeAt(z);const d=new Uint8Array(c),p=new Blob([d],{type:s});if(p.size>Te)return console.warn(`图片过大,跳过缓存: ${(p.size/1024/1024).toFixed(2)}MB`),null;const k={url:t,blob:p,timestamp:Date.now(),size:p.size,channelKey:e};if(!await pt(k))return console.error("保存图片到IndexedDB失败"),null;Je();const R=URL.createObjectURL(p);return b.value[t]=R,Xe(ct(p)),R}catch(a){return console.error("缓存图片失败:",a),null}}async function je(e){try{const t=await ta(e);let a=0;for(const n of t)await tt(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],a+=n.size||0);a>0&&Xe(-a)}catch(t){console.error("清理频道图片缓存失败:",t)}}function aa(){const e=Object.keys(b.value).length;return{blobCount:e,estimatedMemoryUsage:ye,maxMemoryLimit:be,maxBlobLimit:ie,memoryUsagePercent:(ye/be*100).toFixed(1),blobUsagePercent:(e/ie*100).toFixed(1)}}async function na(){return I?new Promise(e=>{const n=I.transaction([S],"readonly").objectStore(S).getAll();n.onsuccess=()=>{const o=n.result||[],s=new Set;let i=0;o.forEach(c=>{s.add(c.channelKey),i+=c.size}),e({totalImages:o.length,totalSize:i,channels:s.size})},n.onerror=()=>{console.error("获取缓存统计失败:",n.error),e({totalImages:0,totalSize:0,channels:0})}}):{totalImages:0,totalSize:0,channels:0}}function wt(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),q.value[s]=d.length;const k=Me();Ie(()=>{setTimeout(()=>{k&&ve()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&we(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}function sa(e){const t=`${e.selfId}:${e.channelId}`;if(u.value.messages[t]||(u.value.messages[t]=[]),!u.value.messages[t].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},o=u.value.messages[t];let s=o.length;for(let c=o.length-1;c>=0;c--){if(o[c].timestamp<=e.timestamp){s=c+1;break}c===0&&(s=0)}o.splice(s,0,n),o.length>100&&(u.value.messages[t]=o.slice(-100)),q.value[t]=o.length;const i=Me();Ie(()=>{setTimeout(()=>{i&&ve()},10)})}u.value={...u.value}}function oa(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),q.value[s]=d.length;const k=Me();Ie(()=>{setTimeout(()=>{k&&ve()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&we(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}async function ra(){try{const e=await P("get-chat-data");if(e.success&&e.data){const t={};W.value=new Set(e.data.pinnedBots||[]),oe.value=new Set(e.data.pinnedChannels||[]);for(const[a,n]of Object.entries(e.data.messages||{})){const o=n.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));o.sort((s,i)=>s.timestamp-i.timestamp),t[a]=o}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:t},await la(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function la(){try{const e=await P("get-all-channel-message-counts");if(e.success&&e.counts){const t={};for(const[a,n]of Object.entries(e.counts))t[a]=n;q.value=t}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ca(){try{const e=await P("get-plugin-config");e.success&&e.config?ce.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function It(e,t){try{const a=await P("get-history-messages",{selfId:e,channelId:t});if(a.success&&a.messages){const n=`${e}:${t}`,o=a.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return o.sort((s,i)=>s.timestamp-i.timestamp),u.value.messages[n]=o,q.value[n]=o.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",a.error),false}catch(a){return console.error("获取历史消息时出错:",a),false}}function ia(e){if(!L.value||e.touches.length!==1)return;const t=e.touches[0];F.value={x:t.clientX,y:t.clientY,time:Date.now()},ae.value={x:t.clientX,y:t.clientY},Be.value=false}function ua(e){if(!L.value||!F.value||e.touches.length!==1)return;const t=e.touches[0];ae.value={x:t.clientX,y:t.clientY};const a=t.clientX-F.value.x,n=t.clientY-F.value.y;if(Math.abs(a)>Math.abs(n)&&Math.abs(a)>30){const o=a>0,s=V.value==="messages"||V.value==="channels";if(o&&s){Be.value=true;const i=Math.min(a,200),c=150;i>c?fe.value={show:true,text:"松开返回"}:fe.value={show:true,text:`滑动返回 ${Math.round(i/c*100)}%`},e.preventDefault()}else fe.value={show:false,text:""}}else fe.value={show:false,text:""}}function da(e){if(!L.value||!F.value)return;const a=Date.now()-F.value.time;if(ae.value){const n=ae.value.x-F.value.x,o=ae.value.y-F.value.y,s=n>150,i=Math.abs(n)>Math.abs(o),c=a<300&&n>80;(s&&i||c)&&fa()}F.value=null,ae.value=null,Be.value=false,fe.value={show:false,text:""}}function fa(){switch(V.value){case"messages":V.value="channels";break;case"channels":V.value="bots",g.value="",$.value="";break}}function at(){L.value=window.innerWidth<=768}function xt(){return!ne.value||Me()}const Ct=()=>{L.value&&B.value&&Ie(()=>{xt()&&ve()})},ha=()=>{L.value&&setTimeout(()=>{B.value&&xt()&&ve()},300)};return kt(D,(e,t)=>{t.length===0&&e.length>0&&Ie(()=>{ve()})}),nt(async()=>{at(),window.addEventListener("resize",at),window.visualViewport&&window.visualViewport.addEventListener("resize",Ct),document.addEventListener("click",Ee),await Et()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await et()},2e3),setInterval(async()=>{await et()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ca(),await ra();const t=rt("chat-message-event",wt),a=rt("bot-message-sent-event",sa),n=rt("chat-bot-message-event",oa);kt($,o=>{o&&Ie(()=>{B.value&&(B.value.removeEventListener("scroll",Ke),B.value.addEventListener("scroll",Ke),Ke()),!L.value&&he.value&&he.value.focus()})},{immediate:true}),setInterval(()=>{Je()},2*60*1e3),ma(()=>{window.removeEventListener("resize",at),window.visualViewport&&window.visualViewport.removeEventListener("resize",Ct),document.removeEventListener("click",Ee),t&&typeof t=="function"&&t(),a&&typeof a=="function"&&a(),n&&typeof n=="function"&&n(),B.value&&B.value.removeEventListener("scroll",Ke),Object.values(b.value).forEach(o=>{URL.revokeObjectURL(o)}),b.value={},I&&(I.close(),I=null)})}),{AvatarComponent:le,ImageComponent:X,JsonCardComponent:ge,ForwardMessageComponent:G,MessageElement:ke,chatData:u,channelMessageCounts:q,pluginConfig:ce,selectedBot:g,selectedChannel:$,inputMessage:Se,imageBlobUrls:b,pinnedBots:W,pinnedChannels:oe,uploadedImages:Y,showActionMenu:de,isMobile:L,mobileView:V,touchStart:F,touchCurrent:ae,isSwipeActive:Be,swipeIndicator:fe,messageHistory:B,messageInput:he,showScrollButton:$e,isUserScrolling:ne,isSending:me,draggingChannel:se,dragStartPos:M,dragCurrentPos:A,dragElementInitialPos:_e,dragOffset:pe,dragThreshold:H,isDragReady:Z,draggedBubbleElement:C,contextMenu:N,fileInput:Le,bots:m,currentChannels:l,currentMessages:D,currentChannelName:Ue,currentChannelKey:$t,canSendMessage:lt,canInputMessage:_t,mobileViewClass:Dt,inputPlaceholder:Tt,chatContainerStyle:Lt,selectBot:qt,selectChannel:jt,handleBotRightClick:Ut,handleChannelRightClick:Kt,showContextMenu:Ge,hideContextMenu:J,handleKeyDown:Ze,toggleBotPin:Mt,toggleChannelPin:At,deleteBotMessages:zt,deleteChannelMessages:Pt,sendMessage:Nt,toggleActionMenu:Rt,triggerImageUpload:Ot,handleFileSelect:Ft,handlePaste:Ht,uploadImage:Qe,removeImage:Xt,fileToBase64:ut,handleClickOutside:Ee,formatTime:Yt,getChannelTypeText:Vt,scrollToBottom:ve,checkScrollPosition:Ke,isNearBottom:Me,getChannelMessageCount:dt,startDrag:Wt,handleDragMove:Ae,handleDragEnd:ze,resetDragState:Pe,getDragStyle:Jt,getDragDistance:Gt,clearChannelHistory:ft,showNotification:T,createThresholdCircle:ht,removeThresholdCircle:mt,handleTouchStart:ia,handleTouchMove:ua,handleTouchEnd:da,handleInputFocus:ha,getCachedImageUrl:Ve,cacheImage:we,clearChannelImageCache:je,getMemoryStats:aa,getCacheStats:na,isFileUrl:ee,loadHistoryMessages:It,handleMessageEvent:wt}}const Ca={class:"bot-list"},ka={class:"bot-items"},ba=["onClick","onContextmenu"],Sa={class:"bot-avatar"},Ba={key:1,class:"avatar-placeholder"},$a={class:"bot-info"},_a={class:"bot-name"},Da={class:"bot-platform"},Ta={class:"channel-list"},La={key:0,class:"empty-state"},qa={key:1,class:"channel-items"},Ua=["data-channel-id","onClick","onContextmenu"],Ka={class:"channel-info"},Ma={class:"channel-name"},Aa={class:"channel-type"},za=["onMousedown","onTouchstart","title"],Pa={class:"message-area"},ja={class:"panel-header"},Na={key:0,class:"empty-state"},Ra={key:1,class:"message-content"},Oa={class:"message-avatar"},Fa={key:1,class:"avatar-placeholder"},Ha={class:"message-content-wrapper"},Xa={class:"message-header"},Ya={class:"message-username"},Va={class:"message-time"},Wa={key:0,class:"message-quote"},Ja={class:"quote-header"},Ga={class:"quote-avatar"},Za={key:1,class:"avatar-placeholder"},Qa={class:"quote-username"},Ea={class:"quote-time"},en={class:"quote-content"},tn={class:"message-text"},an={class:"message-input"},nn={key:0,class:"image-preview-container"},sn=["src","alt"],on=["onClick"],rn={class:"input-row"},ln={class:"input-actions"},cn=["placeholder","disabled"],un=["disabled"],dn=Ce({__name:"index",setup(ee){const le=xa(),{AvatarComponent:X,MessageElement:ge,selectedBot:G,selectedChannel:ke,inputMessage:u,pinnedBots:q,pinnedChannels:ce,uploadedImages:b,showActionMenu:be,swipeIndicator:ie,messageHistory:ye,messageInput:I,showScrollButton:Re,isSending:Oe,draggingChannel:S,dragThreshold:te,contextMenu:U,fileInput:ue,bots:Te,currentChannels:Fe,currentMessages:We,currentChannelName:O,currentChannelKey:K,canSendMessage:He,canInputMessage:g,mobileViewClass:$,inputPlaceholder:Se,chatContainerStyle:Y,selectBot:de,selectChannel:Le,handleBotRightClick:L,handleChannelRightClick:V,toggleBotPin:F,toggleChannelPin:ae,deleteBotMessages:Be,deleteChannelMessages:fe,sendMessage:B,toggleActionMenu:he,triggerImageUpload:$e,handleFileSelect:ne,handlePaste:me,removeImage:se,formatTime:M,getChannelTypeText:A,scrollToBottom:_e,getChannelMessageCount:pe,startDrag:H,getDragStyle:qe,getDragDistance:j,handleTouchStart:Z,handleTouchMove:C,handleTouchEnd:N,handleInputFocus:W}=le;return(oe,m)=>(y(),x("div",{class:re(["chat-container",r($)]),style:st(r(Y)),onTouchstart:m[15]||(m[15]=(...l)=>r(Z)&&r(Z)(...l)),onTouchmove:m[16]||(m[16]=(...l)=>r(C)&&r(C)(...l)),onTouchend:m[17]||(m[17]=(...l)=>r(N)&&r(N)(...l))},[f("div",Ca,[m[18]||(m[18]=f("div",{class:"panel-header"},[f("h3",null,"机器人")],-1)),f("div",ka,[(y(true),x(E,null,De(r(Te),l=>(y(),x("div",{key:l.selfId,class:re(["bot-item",{active:r(G)===l.selfId,pinned:r(q).has(l.selfId)}]),onClick:D=>r(de)(l.selfId),onContextmenu:D=>r(L)(D,l.selfId)},[f("div",Sa,[l.avatar?(y(),Ne(r(X),{key:0,src:l.avatar,alt:l.username,"channel-key":"bot-list"},null,8,["src","alt"])):(y(),x("div",Ba,_(l.username.charAt(0).toUpperCase()),1))]),f("div",$a,[f("div",_a,_(l.username),1),f("div",Da,_(l.platform),1)]),f("div",{class:re(["bot-status",l.status])},null,2)],42,ba))),128))])]),f("div",Ta,[m[19]||(m[19]=f("div",{class:"panel-header"},[f("h3",null,"频道")],-1)),r(G)?(y(),x("div",qa,[(y(true),x(E,null,De(r(Fe),l=>(y(),x("div",{key:l.id,class:re(["channel-item",{active:r(ke)===l.id,pinned:r(ce).has(`${r(G)}:${l.id}`)}]),"data-channel-id":l.id,onClick:D=>r(Le)(l.id),onContextmenu:D=>r(V)(D,l.id)},[f("div",Ka,[f("div",Ma,_(l.name),1),f("div",Aa,_(r(A)(l.type)),1)]),r(pe)(l.id)>0?(y(),x("div",{key:0,class:re(["channel-message-count draggable-bubble",{dragging:r(S)===l.id,"will-delete":r(S)===l.id&&r(j)(l.id)>r(te)}]),onMousedown:D=>r(H)(D,l.id),onTouchstart:D=>r(H)(D,l.id),style:st(r(qe)(l.id)),title:r(S)===l.id?r(j)(l.id)>r(te)?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},_(r(pe)(l.id)),47,za)):xe("",true)],42,Ua))),128))])):(y(),x("div",La," 请选择一个机器人 "))]),f("div",Pa,[f("div",ja,[f("h3",null,_(r(O)||"选择频道"),1)]),!r(G)||!r(ke)?(y(),x("div",Na," 请选择机器人和频道 ")):(y(),x("div",Ra,[f("div",{class:"message-history",ref_key:"messageHistory",ref:ye},[(y(true),x(E,null,De(r(We),l=>(y(),x("div",{key:l.id,class:re(["message-item",{"bot-message":l.isBot}])},[f("div",Oa,[l.avatar?(y(),Ne(r(X),{key:0,src:l.avatar,alt:l.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Fa,_(l.username.charAt(0).toUpperCase()),1))]),f("div",Ha,[f("div",Xa,[f("span",Ya,_(l.username),1),f("span",Va,_(r(M)(l.timestamp)),1)]),l.quote?(y(),x("div",Wa,[f("div",Ja,[f("div",Ga,[l.quote.user.avatar?(y(),Ne(r(X),{key:0,src:l.quote.user.avatar,alt:l.quote.user.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Za,_(l.quote.user.username.charAt(0).toUpperCase()),1))]),f("span",Qa,_(l.quote.user.username),1),f("span",Ea,_(r(M)(l.quote.timestamp)),1)]),f("div",en,[l.quote.elements&&l.quote.elements.length>0?(y(true),x(E,{key:0},De(l.quote.elements,(D,Ue)=>(y(),Ne(r(ge),{key:`quote-${Ue}`,element:D,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(E,{key:1},[ot(_(l.quote.content),1)],64))])])):xe("",true),f("div",tn,[l.elements&&l.elements.length>0?(y(true),x(E,{key:0},De(l.elements,(D,Ue)=>(y(),Ne(r(ge),{key:Ue,element:D,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(E,{key:1},[ot(_(l.content),1)],64))])])],2))),128))],512),bt(f("div",{class:"floating-scroll-button",onClick:m[0]||(m[0]=(...l)=>r(_e)&&r(_e)(...l))},m[20]||(m[20]=[f("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[va,r(Re)]]),f("div",an,[r(b).length>0?(y(),x("div",nn,[(y(true),x(E,null,De(r(b),l=>(y(),x("div",{key:l.tempId,class:"image-preview-item"},[f("img",{src:l.preview,alt:l.filename,class:"preview-image"},null,8,sn),f("button",{class:"remove-image-btn",onClick:D=>r(se)(l.tempId),title:"删除图片"},m[21]||(m[21]=[f("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})],-1)]),8,on)]))),128))])):xe("",true),f("div",rn,[f("div",ln,[f("button",{class:re(["add-button",{active:r(be)}]),onClick:m[1]||(m[1]=(...l)=>r(he)&&r(he)(...l)),title:"更多操作"},m[22]||(m[22]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[f("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),f("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),r(be)?(y(),x("div",{key:0,class:"action-menu",onClick:m[3]||(m[3]=St(()=>{},["stop"]))},[f("button",{class:"action-menu-item",onClick:m[2]||(m[2]=(...l)=>r($e)&&r($e)(...l))},m[23]||(m[23]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[f("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),f("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),f("polyline",{points:"21,15 16,10 5,21"})],-1),ot(" 上传图片 ",-1)]))])):xe("",true)]),bt(f("input",{"onUpdate:modelValue":m[4]||(m[4]=l=>ya(u)?u.value=l:null),type:"text",placeholder:r(Se),onKeyup:m[5]||(m[5]=ga((...l)=>r(B)&&r(B)(...l),["enter"])),disabled:!r(g),ref_key:"messageInput",ref:I,onPaste:m[6]||(m[6]=(...l)=>r(me)&&r(me)(...l)),onFocus:m[7]||(m[7]=(...l)=>r(W)&&r(W)(...l))},null,40,cn),[[pa,r(u)]]),f("button",{onClick:m[8]||(m[8]=(...l)=>r(B)&&r(B)(...l)),disabled:!r(He),class:re({"is-sending":r(Oe)})},_(r(Oe)?"发送中...":"发送"),11,un)]),f("input",{type:"file",ref_key:"fileInput",ref:ue,onChange:m[9]||(m[9]=(...l)=>r(ne)&&r(ne)(...l)),accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),r(U).show?(y(),x("div",{key:0,class:"context-menu",style:st({left:r(U).x+"px",top:r(U).y+"px"}),onClick:m[14]||(m[14]=St(()=>{},["stop"]))},[r(U).type==="bot"?(y(),x(E,{key:0},[f("div",{class:"context-menu-item",onClick:m[10]||(m[10]=l=>r(F)(r(U).targetId))},_(r(q).has(r(U).targetId)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[11]||(m[11]=l=>r(Be)(r(U).targetId))}," 彻底删除此机器人所有数据 ")],64)):xe("",true),r(U).type==="channel"?(y(),x(E,{key:1},[f("div",{class:"context-menu-item",onClick:m[12]||(m[12]=l=>r(ae)(r(U).targetId))},_(r(ce).has(`${r(G)}:${r(U).targetId}`)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[13]||(m[13]=l=>r(fe)(r(U).targetId))}," 彻底删除此频道所有数据 ")],64)):xe("",true)],4)):xe("",true),f("div",{class:re(["swipe-indicator",{show:r(ie).show}])},_(r(ie).text),3)],38))}}),Bt=(ee,le)=>{const X=ee.__vccOpts||ee;for(const[ge,G]of le)X[ge]=G;return X},fn=Bt(dn,[["__scopeId","data-v-de93bb69"]]),hn={},mn={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function vn(ee,le){return y(),x("svg",mn,le[0]||(le[0]=[f("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M17 3.33782C15.5291 2.48697 13.8214 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22C17.5228 22 22 17.5228 22 12C22 10.1786 21.513 8.47087 20.6622 7",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)]))}const gn=Bt(hn,[["render",vn]]);Ia.register("activity:chat",gn);const wn=ee=>{ee.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Ce({setup(){return()=>h(wa("k-layout"),{},{default:()=>h(fn)})}})})};export{wn as default};
|
|
22
|
+
`,document.head.appendChild(o),document.body.appendChild(a),setTimeout(()=>{a.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{a.parentNode&&a.parentNode.removeChild(a),o.parentNode&&o.parentNode.removeChild(o)},300)},3e3)}function mt(e,t){const a=document.createElement("div");a.className="drag-threshold-circle",a.style.cssText=`
|
|
23
|
+
left: ${e-X}px;
|
|
24
|
+
top: ${t-X}px;
|
|
25
|
+
width: ${X*2}px;
|
|
26
|
+
height: ${X*2}px;
|
|
27
|
+
`,document.body.appendChild(a),window.dragThresholdCircle=a}function vt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function et(){try{if(!I)return false;const e=Date.now();if(e-He<We)return true;He=e;const t=await gt();F=t.totalSize,K=t.totalImages,console.log("数据库健康检查:",{大小:`${(F/1024/1024).toFixed(2)}MB / ${(ae/1024/1024).toFixed(2)}MB`,图片数量:`${K} / ${de}`,使用率:`${(F/ae*100).toFixed(1)}%`});const a=F/ae,n=K/de;return(a>Fe||n>Fe)&&(console.warn("数据库使用率过高,开始自动清理"),await Ye()),(a>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Et()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function gt(){return I?new Promise(e=>{const n=I.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{const o=n.result||[];let s=0;const i={};o.forEach(c=>{s+=c.size||0,i[c.channelKey]=(i[c.channelKey]||0)+1}),e({totalSize:s,totalImages:o.length,channelStats:i})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function Ye(){try{console.log("开始自动清理...");const e=await yt();if(e.length===0)return;const t={};e.forEach(o=>{t[o.channelKey]||(t[o.channelKey]=[]),t[o.channelKey].push(o)});let a=0,n=0;for(const[o,s]of Object.entries(t))if(s.length>M){s.sort((c,d)=>c.timestamp-d.timestamp);const i=s.slice(0,s.length-M);for(const c of i)await tt(c.url),a++,n+=c.size||0,b.value[c.url]&&(URL.revokeObjectURL(b.value[c.url]),delete b.value[c.url])}console.log(`自动清理完成: 清理了 ${a} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),K-=a,F-=n}catch(e){console.error("自动清理失败:",e)}}async function Et(){try{console.log("开始紧急清理...");const e=await yt();if(e.length===0)return;e.sort((s,i)=>i.timestamp-s.timestamp);const t=Math.floor(de*.3),a=e.slice(t);let n=0,o=0;for(const s of a)await tt(s.url),n++,o+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(o/1024/1024).toFixed(2)}MB`),K=t,F-=o}catch(e){console.error("紧急清理失败:",e)}}async function yt(){return I?new Promise(e=>{const n=I.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function ea(){return new Promise(e=>{try{I&&(I.close(),I=null);const t=indexedDB.deleteDatabase(Ne);t.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),F=0,K=0,e(true)},t.onerror=()=>{console.error("清理IndexedDB数据库失败:",t.error),e(false)},t.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(t){console.error("清理数据库时出错:",t),e(false)}})}async function ta(){try{return await pt()?(setTimeout(async()=>{const t=await gt();console.log("数据库初始状态:",{大小:`${(t.totalSize/1024/1024).toFixed(2)}MB`,图片数量:t.totalImages,频道分布:t.channelStats}),(t.totalSize>ae*.9||t.totalImages>de*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await Ye())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await ea(),await pt())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function pt(){return new Promise(e=>{try{const t=indexedDB.open(Ne,Oe);t.onerror=()=>{console.error("IndexedDB打开失败:",t.error),e(false)},t.onsuccess=()=>{I=t.result,I.onerror=a=>{console.error("IndexedDB运行时错误:",a)},I.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),I==null||I.close(),I=null},e(true)},t.onupgradeneeded=a=>{const n=a.target.result;if(!n.objectStoreNames.contains($)){const o=n.createObjectStore($,{keyPath:"url"});o.createIndex("channelKey","channelKey",{unique:false}),o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},t.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(t){console.error("打开数据库时出错:",t),e(false)}})}async function aa(e){return I?new Promise((t,a)=>{const s=I.transaction([$],"readonly").objectStore($).get(e);s.onsuccess=()=>{t(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),t(null)}}):null}async function wt(e){if(!I)return false;try{return e.size>Le?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Le/1024/1024).toFixed(2)}MB`),false):(await et(),F+e.size>ae&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await Ye(),F+e.size>ae)?(console.warn("清理后仍会超过限制,跳过此图片"),false):K>=de&&(console.warn("图片数量已达上限,执行清理"),await Ye(),K>=de)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(t=>{const o=I.transaction([$],"readwrite").objectStore($).put(e);o.onsuccess=()=>{F+=e.size,K+=1,t(true)},o.onerror=()=>{console.error("保存图片到IndexedDB失败:",o.error),t(false)}}))}catch(t){return console.error("保存图片时出错:",t),false}}async function tt(e){return I?new Promise(t=>{const o=I.transaction([$],"readwrite").objectStore($).delete(e);o.onsuccess=()=>{t(true)},o.onerror=()=>{console.error("从IndexedDB删除图片失败:",o.error),t(false)}}):false}async function na(e){return I?new Promise(t=>{const s=I.transaction([$],"readonly").objectStore($).index("channelKey").getAll(e);s.onsuccess=()=>{t(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),t([])}}):[]}async function Ve(e,t){const a=b.value[t];if(a)return a;const n=await aa(t);if(!n)return null;Je();const o=URL.createObjectURL(n.blob);return b.value[t]=o,Xe(it(n.blob)),n.timestamp=Date.now(),await wt(n),o}async function xe(e,t){try{const a=await Ve(e,t);if(a)return a;const n=await P("fetch-image",{url:t});if(!n.success)return console.error("获取图片失败:",n.error),null;const o=n.base64,s=n.contentType||"image/jpeg",i=atob(o),c=new Array(i.length);for(let z=0;z<i.length;z++)c[z]=i.charCodeAt(z);const d=new Uint8Array(c),p=new Blob([d],{type:s});if(p.size>Le)return console.warn(`图片过大,跳过缓存: ${(p.size/1024/1024).toFixed(2)}MB`),null;const k={url:t,blob:p,timestamp:Date.now(),size:p.size,channelKey:e};if(!await wt(k))return console.error("保存图片到IndexedDB失败"),null;Je();const O=URL.createObjectURL(p);return b.value[t]=O,Xe(it(p)),O}catch(a){return console.error("缓存图片失败:",a),null}}async function Pe(e){try{const t=await na(e);let a=0;for(const n of t)await tt(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],a+=n.size||0);a>0&&Xe(-a)}catch(t){console.error("清理频道图片缓存失败:",t)}}function sa(){const e=Object.keys(b.value).length;return{blobCount:e,estimatedMemoryUsage:we,maxMemoryLimit:be,maxBlobLimit:ue,memoryUsagePercent:(we/be*100).toFixed(1),blobUsagePercent:(e/ue*100).toFixed(1)}}async function oa(){return I?new Promise(e=>{const n=I.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{const o=n.result||[],s=new Set;let i=0;o.forEach(c=>{s.add(c.channelKey),i+=c.size}),e({totalImages:o.length,totalSize:i,channels:s.size})},n.onerror=()=>{console.error("获取缓存统计失败:",n.error),e({totalImages:0,totalSize:0,channels:0})}}):{totalImages:0,totalSize:0,channels:0}}function at(){g.value&&S.value&&(localStorage.setItem("chat-selected-bot",g.value),localStorage.setItem("chat-selected-channel",S.value))}function It(){const e=localStorage.getItem("chat-selected-bot"),t=localStorage.getItem("chat-selected-channel");return e&&t&&u.value.bots[e]&&u.value.channels[e]&&u.value.channels[e][t]?(g.value=e,S.value=t,true):false}function xt(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.isDirect?`私信 ${e.channelId}`:`${e.guildName||e.channelId} (${e.channelId})`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,channelId:e.channelId,guildName:e.guildName||"群聊",isDirect:e.isDirect}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const k=Ke();ye(()=>{setTimeout(()=>{k&&ge()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&xe(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}function ra(e){const t=`${e.selfId}:${e.channelId}`;if(u.value.messages[t]||(u.value.messages[t]=[]),!u.value.messages[t].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},o=u.value.messages[t];let s=o.length;for(let c=o.length-1;c>=0;c--){if(o[c].timestamp<=e.timestamp){s=c+1;break}c===0&&(s=0)}o.splice(s,0,n),o.length>100&&(u.value.messages[t]=o.slice(-100)),U.value[t]=o.length;const i=Ke();ye(()=>{setTimeout(()=>{i&&ge()},10)})}u.value={...u.value}}function la(e){var t,a,n,o;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((t=e.bot)==null?void 0:t.name)||`Bot-${e.selfId}`,avatar:(a=e.bot)==null?void 0:a.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(o=e.bot)!=null&&o.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.isDirect?`私信 ${e.channelId}`:`${e.guildName||e.channelId} (${e.channelId})`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,channelId:e.channelId,guildName:e.guildName||"群聊",isDirect:e.isDirect}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(c=>c.id===e.messageId)){const c={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},d=u.value.messages[s];let p=d.length;for(let w=d.length-1;w>=0;w--){if(d[w].timestamp<=e.timestamp){p=w+1;break}w===0&&(p=0)}d.splice(p,0,c),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const k=Ke();ye(()=>{setTimeout(()=>{k&&ge()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(i=>{if((i.type==="img"||i.type==="image"||i.type==="mface")&&i.attrs){const c=i.attrs.src||i.attrs.url||i.attrs.file;c&&xe(s,c).catch(d=>{console.warn("预缓存图片失败:",c,d)})}})}u.value={...u.value}}async function ca(){try{const e=await P("get-chat-data");if(e.success&&e.data){const t={};J.value=new Set(e.data.pinnedBots||[]),re.value=new Set(e.data.pinnedChannels||[]);for(const[a,n]of Object.entries(e.data.messages||{})){const o=n.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));o.sort((s,i)=>s.timestamp-i.timestamp),t[a]=o}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:t},await ia(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function ia(){try{const e=await P("get-all-channel-message-counts");if(e.success&&e.counts){const t={};for(const[a,n]of Object.entries(e.counts))t[a]=n;U.value=t}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ua(){try{const e=await P("get-plugin-config");e.success&&e.config?ie.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function Ct(e,t){try{const a=await P("get-history-messages",{selfId:e,channelId:t});if(a.success&&a.messages){const n=`${e}:${t}`,o=a.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return o.sort((s,i)=>s.timestamp-i.timestamp),u.value.messages[n]=o,U.value[n]=o.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",a.error),false}catch(a){return console.error("获取历史消息时出错:",a),false}}function da(e){if(!q.value||e.touches.length!==1)return;const t=e.touches[0];H.value={x:t.clientX,y:t.clientY,time:Date.now()},ne.value={x:t.clientX,y:t.clientY},Be.value=false}function fa(e){if(!q.value||!H.value||e.touches.length!==1)return;const t=e.touches[0];ne.value={x:t.clientX,y:t.clientY};const a=t.clientX-H.value.x,n=t.clientY-H.value.y;if(Math.abs(a)>Math.abs(n)&&Math.abs(a)>30){const o=a>0,s=W.value==="messages"||W.value==="channels";if(o&&s){Be.value=true;const i=Math.min(a,200),c=150;i>c?he.value={show:true,text:"松开返回"}:he.value={show:true,text:`滑动返回 ${Math.round(i/c*100)}%`},e.preventDefault()}else he.value={show:false,text:""}}else he.value={show:false,text:""}}function ha(e){if(!q.value||!H.value)return;const a=Date.now()-H.value.time;if(ne.value){const n=ne.value.x-H.value.x,o=ne.value.y-H.value.y,s=n>150,i=Math.abs(n)>Math.abs(o),c=a<300&&n>80;(s&&i||c)&&ma()}H.value=null,ne.value=null,Be.value=false,he.value={show:false,text:""}}function ma(){switch(W.value){case"messages":W.value="channels";break;case"channels":W.value="bots",g.value="",S.value="";break}}function nt(){q.value=window.innerWidth<=768}function kt(){return!se.value||Ke()}const bt=()=>{q.value&&D.value&&ye(()=>{kt()&&ge()})},va=()=>{q.value&&setTimeout(()=>{D.value&&kt()&&ge()},300)};return St(L,(e,t)=>{t.length===0&&e.length>0&&ye(()=>{ge()})}),st(async()=>{nt(),window.addEventListener("resize",nt),window.visualViewport&&window.visualViewport.addEventListener("resize",bt),document.addEventListener("click",Ee),await ta()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await et()},2e3),setInterval(async()=>{await et()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ua(),await ca(),ye(()=>{It()});const t=lt("chat-message-event",xt),a=lt("bot-message-sent-event",ra),n=lt("chat-bot-message-event",la);St(S,o=>{o&&ye(()=>{D.value&&(D.value.removeEventListener("scroll",Me),D.value.addEventListener("scroll",Me),Me()),!q.value&&me.value&&me.value.focus()})},{immediate:true}),setInterval(()=>{Je()},2*60*1e3),ga(()=>{window.removeEventListener("resize",nt),window.visualViewport&&window.visualViewport.removeEventListener("resize",bt),document.removeEventListener("click",Ee),t&&typeof t=="function"&&t(),a&&typeof a=="function"&&a(),n&&typeof n=="function"&&n(),D.value&&D.value.removeEventListener("scroll",Me),Object.values(b.value).forEach(o=>{URL.revokeObjectURL(o)}),b.value={},I&&(I.close(),I=null)})}),{AvatarComponent:ce,ImageComponent:Y,JsonCardComponent:pe,ForwardMessageComponent:Z,MessageElement:ke,chatData:u,channelMessageCounts:U,pluginConfig:ie,selectedBot:g,selectedChannel:S,inputMessage:Se,imageBlobUrls:b,pinnedBots:J,pinnedChannels:re,uploadedImages:V,showActionMenu:fe,isMobile:q,mobileView:W,touchStart:H,touchCurrent:ne,isSwipeActive:Be,swipeIndicator:he,messageHistory:D,messageInput:me,showScrollButton:$e,isUserScrolling:se,isSending:ve,draggingChannel:oe,dragStartPos:j,dragCurrentPos:A,dragElementInitialPos:De,dragOffset:Ie,dragThreshold:X,isDragReady:Q,draggedBubbleElement:C,contextMenu:N,fileInput:Te,bots:m,currentChannels:l,currentMessages:L,currentChannelName:Ue,currentChannelKey:_t,canSendMessage:ct,canInputMessage:Lt,mobileViewClass:Tt,inputPlaceholder:qt,chatContainerStyle:Ut,selectBot:Mt,selectChannel:Nt,handleBotRightClick:Kt,handleChannelRightClick:jt,showContextMenu:Ge,hideContextMenu:G,handleKeyDown:Ze,toggleBotPin:At,toggleChannelPin:zt,deleteBotMessages:Pt,deleteChannelMessages:Rt,sendMessage:Ot,toggleActionMenu:Ft,triggerImageUpload:Ht,handleFileSelect:Xt,handlePaste:Yt,uploadImage:Qe,removeImage:Vt,fileToBase64:dt,handleClickOutside:Ee,formatTime:Wt,getChannelTypeText:Jt,scrollToBottom:ge,checkScrollPosition:Me,isNearBottom:Ke,getChannelMessageCount:ft,startDrag:Gt,handleDragMove:je,handleDragEnd:Ae,resetDragState:ze,getDragStyle:Zt,getDragDistance:Qt,clearChannelHistory:ht,showNotification:T,createThresholdCircle:mt,removeThresholdCircle:vt,handleTouchStart:da,handleTouchMove:fa,handleTouchEnd:ha,handleInputFocus:va,getCachedImageUrl:Ve,cacheImage:xe,clearChannelImageCache:Pe,getMemoryStats:sa,getCacheStats:oa,isFileUrl:te,loadHistoryMessages:Ct,handleMessageEvent:xt,saveSelectionState:at,restoreSelectionState:It}}const ba={class:"bot-list"},Sa={class:"bot-items"},Ba=["onClick","onContextmenu"],$a={class:"bot-avatar"},Da={key:1,class:"avatar-placeholder"},_a={class:"bot-info"},La={class:"bot-name"},Ta={class:"bot-platform"},qa={class:"channel-list"},Ua={key:0,class:"empty-state"},Ma={key:1,class:"channel-items"},Ka=["data-channel-id","onClick","onContextmenu"],ja={class:"channel-info"},Aa={class:"channel-name"},za={class:"channel-type"},Pa=["onMousedown","onTouchstart","title"],Ra={class:"message-area"},Na={class:"panel-header"},Oa={key:0,class:"empty-state"},Fa={key:1,class:"message-content"},Ha={class:"message-avatar"},Xa={key:1,class:"avatar-placeholder"},Ya={class:"message-content-wrapper"},Va={class:"message-header"},Wa={class:"message-username"},Ja={class:"message-time"},Ga={key:0,class:"message-quote"},Za={class:"quote-header"},Qa={class:"quote-avatar"},Ea={key:1,class:"avatar-placeholder"},en={class:"quote-username"},tn={class:"quote-time"},an={class:"quote-content"},nn={class:"message-text"},sn={class:"message-input"},on={key:0,class:"image-preview-container"},rn=["src","alt"],ln=["onClick"],cn={class:"input-row"},un={class:"input-actions"},dn=["placeholder","disabled"],fn=["disabled"],hn=Ce({__name:"index",setup(te){const ce=ka(),{AvatarComponent:Y,MessageElement:pe,selectedBot:Z,selectedChannel:ke,inputMessage:u,pinnedBots:U,pinnedChannels:ie,uploadedImages:b,showActionMenu:be,swipeIndicator:ue,messageHistory:we,messageInput:I,showScrollButton:Ne,isSending:Oe,draggingChannel:$,dragThreshold:ae,contextMenu:M,fileInput:de,bots:Le,currentChannels:Fe,currentMessages:We,currentChannelName:F,currentChannelKey:K,canSendMessage:He,canInputMessage:g,mobileViewClass:S,inputPlaceholder:Se,chatContainerStyle:V,selectBot:fe,selectChannel:Te,handleBotRightClick:q,handleChannelRightClick:W,toggleBotPin:H,toggleChannelPin:ne,deleteBotMessages:Be,deleteChannelMessages:he,sendMessage:D,toggleActionMenu:me,triggerImageUpload:$e,handleFileSelect:se,handlePaste:ve,removeImage:oe,formatTime:j,getChannelTypeText:A,scrollToBottom:De,getChannelMessageCount:Ie,startDrag:X,getDragStyle:qe,getDragDistance:R,handleTouchStart:Q,handleTouchMove:C,handleTouchEnd:N,handleInputFocus:J}=ce;return(re,m)=>(y(),x("div",{class:le(["chat-container",r(S)]),style:ot(r(V)),onTouchstart:m[15]||(m[15]=(...l)=>r(Q)&&r(Q)(...l)),onTouchmove:m[16]||(m[16]=(...l)=>r(C)&&r(C)(...l)),onTouchend:m[17]||(m[17]=(...l)=>r(N)&&r(N)(...l))},[B(" 左侧机器人列表 "),f("div",ba,[m[18]||(m[18]=f("div",{class:"panel-header"},[f("h3",null,"机器人")],-1)),f("div",Sa,[(y(true),x(ee,null,_e(r(Le),l=>(y(),x("div",{key:l.selfId,class:le(["bot-item",{active:r(Z)===l.selfId,pinned:r(U).has(l.selfId)}]),onClick:L=>r(fe)(l.selfId),onContextmenu:L=>r(q)(L,l.selfId)},[f("div",$a,[l.avatar?(y(),Re(r(Y),{key:0,src:l.avatar,alt:l.username,"channel-key":"bot-list"},null,8,["src","alt"])):(y(),x("div",Da,_(l.username.charAt(0).toUpperCase()),1))]),f("div",_a,[f("div",La,_(l.username),1),f("div",Ta,_(l.platform),1)]),f("div",{class:le(["bot-status",l.status])},null,2)],42,Ba))),128))])]),B(" 中间频道列表 "),f("div",qa,[m[19]||(m[19]=f("div",{class:"panel-header"},[f("h3",null,"频道")],-1)),r(Z)?(y(),x("div",Ma,[(y(true),x(ee,null,_e(r(Fe),l=>(y(),x("div",{key:l.id,class:le(["channel-item",{active:r(ke)===l.id,pinned:r(ie).has(`${r(Z)}:${l.id}`)}]),"data-channel-id":l.id,onClick:L=>r(Te)(l.id),onContextmenu:L=>r(W)(L,l.id)},[f("div",ja,[f("div",Aa,_(l.name),1),f("div",za,_(r(A)(l.type)),1)]),r(Ie)(l.id)>0?(y(),x("div",{key:0,class:le(["channel-message-count draggable-bubble",{dragging:r($)===l.id,"will-delete":r($)===l.id&&r(R)(l.id)>r(ae)}]),onMousedown:L=>r(X)(L,l.id),onTouchstart:L=>r(X)(L,l.id),style:ot(r(qe)(l.id)),title:r($)===l.id?r(R)(l.id)>r(ae)?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},_(r(Ie)(l.id)),47,Pa)):B("v-if",true)],42,Ka))),128))])):(y(),x("div",Ua," 请选择一个机器人 "))]),B(" 右侧消息区域 "),f("div",Ra,[f("div",Na,[f("h3",null,_(r(F)||"选择频道"),1)]),!r(Z)||!r(ke)?(y(),x("div",Oa," 请选择机器人和频道 ")):(y(),x("div",Fa,[B(" 消息历史 "),f("div",{class:"message-history",ref_key:"messageHistory",ref:we},[(y(true),x(ee,null,_e(r(We),l=>(y(),x("div",{key:l.id,class:le(["message-item",{"bot-message":l.isBot}])},[f("div",Ha,[l.avatar?(y(),Re(r(Y),{key:0,src:l.avatar,alt:l.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Xa,_(l.username.charAt(0).toUpperCase()),1))]),f("div",Ya,[f("div",Va,[f("span",Wa,_(l.username),1),f("span",Ja,_(r(j)(l.timestamp)),1)]),B(" 引用消息显示 "),l.quote?(y(),x("div",Ga,[f("div",Za,[f("div",Qa,[l.quote.user.avatar?(y(),Re(r(Y),{key:0,src:l.quote.user.avatar,alt:l.quote.user.username,"channel-key":r(K)},null,8,["src","alt","channel-key"])):(y(),x("div",Ea,_(l.quote.user.username.charAt(0).toUpperCase()),1))]),f("span",en,_(l.quote.user.username),1),f("span",tn,_(r(j)(l.quote.timestamp)),1)]),f("div",an,[l.quote.elements&&l.quote.elements.length>0?(y(true),x(ee,{key:0},_e(l.quote.elements,(L,Ue)=>(y(),Re(r(pe),{key:`quote-${Ue}`,element:L,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(ee,{key:1},[rt(_(l.quote.content),1)],64))])])):B("v-if",true),f("div",nn,[l.elements&&l.elements.length>0?(y(true),x(ee,{key:0},_e(l.elements,(L,Ue)=>(y(),Re(r(pe),{key:Ue,element:L,"channel-key":r(K)},null,8,["element","channel-key"]))),128)):(y(),x(ee,{key:1},[rt(_(l.content),1)],64))])])],2))),128))],512),B(" 悬浮的滚动到底部按钮 "),Bt(f("div",{class:"floating-scroll-button",onClick:m[0]||(m[0]=(...l)=>r(De)&&r(De)(...l))},m[20]||(m[20]=[f("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[ya,r(Ne)]]),B(" 输入框 "),f("div",sn,[B(" 图片预览区域 "),r(b).length>0?(y(),x("div",on,[(y(true),x(ee,null,_e(r(b),l=>(y(),x("div",{key:l.tempId,class:"image-preview-item"},[f("img",{src:l.preview,alt:l.filename,class:"preview-image"},null,8,rn),f("button",{class:"remove-image-btn",onClick:L=>r(oe)(l.tempId),title:"删除图片"},m[21]||(m[21]=[f("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})],-1)]),8,ln)]))),128))])):B("v-if",true),f("div",cn,[B(" 加号按钮 "),f("div",un,[f("button",{class:le(["add-button",{active:r(be)}]),onClick:m[1]||(m[1]=(...l)=>r(me)&&r(me)(...l)),title:"更多操作"},m[22]||(m[22]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[f("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),f("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),B(" 操作菜单 "),r(be)?(y(),x("div",{key:0,class:"action-menu",onClick:m[3]||(m[3]=$t(()=>{},["stop"]))},[f("button",{class:"action-menu-item",onClick:m[2]||(m[2]=(...l)=>r($e)&&r($e)(...l))},m[23]||(m[23]=[f("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[f("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),f("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),f("polyline",{points:"21,15 16,10 5,21"})],-1),rt(" 上传图片 ",-1)]))])):B("v-if",true)]),Bt(f("input",{"onUpdate:modelValue":m[4]||(m[4]=l=>wa(u)?u.value=l:null),type:"text",placeholder:r(Se),onKeyup:m[5]||(m[5]=pa((...l)=>r(D)&&r(D)(...l),["enter"])),disabled:!r(g),ref_key:"messageInput",ref:I,onPaste:m[6]||(m[6]=(...l)=>r(ve)&&r(ve)(...l)),onFocus:m[7]||(m[7]=(...l)=>r(J)&&r(J)(...l))},null,40,dn),[[Ia,r(u)]]),f("button",{onClick:m[8]||(m[8]=(...l)=>r(D)&&r(D)(...l)),disabled:!r(He),class:le({"is-sending":r(Oe)})},_(r(Oe)?"发送中...":"发送"),11,fn)]),B(" 隐藏的文件输入 "),f("input",{type:"file",ref_key:"fileInput",ref:de,onChange:m[9]||(m[9]=(...l)=>r(se)&&r(se)(...l)),accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),B(" 右键菜单 "),r(M).show?(y(),x("div",{key:0,class:"context-menu",style:ot({left:r(M).x+"px",top:r(M).y+"px"}),onClick:m[14]||(m[14]=$t(()=>{},["stop"]))},[B(" 机器人右键菜单 "),r(M).type==="bot"?(y(),x(ee,{key:0},[f("div",{class:"context-menu-item",onClick:m[10]||(m[10]=l=>r(H)(r(M).targetId))},_(r(U).has(r(M).targetId)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[11]||(m[11]=l=>r(Be)(r(M).targetId))}," 彻底删除此机器人所有数据 ")],64)):B("v-if",true),B(" 频道右键菜单 "),r(M).type==="channel"?(y(),x(ee,{key:1},[f("div",{class:"context-menu-item",onClick:m[12]||(m[12]=l=>r(ne)(r(M).targetId))},_(r(ie).has(`${r(Z)}:${r(M).targetId}`)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:m[13]||(m[13]=l=>r(he)(r(M).targetId))}," 彻底删除此频道所有数据 ")],64)):B("v-if",true)],4)):B("v-if",true),B(" 滑动指示器 "),f("div",{class:le(["swipe-indicator",{show:r(ue).show}])},_(r(ue).text),3)],38))}}),Dt=(te,ce)=>{const Y=te.__vccOpts||te;for(const[pe,Z]of ce)Y[pe]=Z;return Y},mn=Dt(hn,[["__scopeId","data-v-de93bb69"]]),vn={},gn={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function yn(te,ce){return y(),x("svg",gn,ce[0]||(ce[0]=[f("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),f("path",{d:"M17 3.33782C15.5291 2.48697 13.8214 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22C17.5228 22 22 17.5228 22 12C22 10.1786 21.513 8.47087 20.6622 7",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)]))}const pn=Dt(vn,[["render",yn]]);Ca.register("activity:chat",pn);const xn=te=>{te.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Ce({setup(){return()=>h(xa("k-layout"),{},{default:()=>h(mn)})}})})};export{xn as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.message-quote[data-v-de93bb69]{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-de93bb69]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-de93bb69]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-de93bb69]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-de93bb69]{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-de93bb69]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-de93bb69]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-de93bb69]{color:#7276b7;line-height:1.3;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.quote-content .message-image[data-v-de93bb69]{max-width:min(200px,50vw);max-height:100px}.quote-content .message-image-container[data-v-de93bb69]{margin:2px 0}@media (prefers-color-scheme:dark){.message-quote[data-v-de93bb69]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-de93bb69]{color:#adb5bd}.quote-username[data-v-de93bb69]{color:#0d6efd}}.chat-container[data-v-de93bb69]{display:flex;height:100vh;background:0 0;margin-left:0;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-de93bb69],.channel-list[data-v-de93bb69],.message-area[data-v-de93bb69]{display:flex;flex-direction:column;background:0 0;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-de93bb69]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-de93bb69]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-de93bb69]{flex:1;border-right:none}.panel-header[data-v-de93bb69]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:0 0;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-de93bb69]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-de93bb69]{display:none;background:0 0;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-de93bb69]:hover{background:#8080801a}.bot-items[data-v-de93bb69],.channel-items[data-v-de93bb69]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-de93bb69],.channel-item[data-v-de93bb69]{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-de93bb69]:hover,.channel-item[data-v-de93bb69]:hover{background:#8080801a}.bot-item.active[data-v-de93bb69],.channel-item.active[data-v-de93bb69]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-de93bb69]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-de93bb69]{flex:1}.bot-name[data-v-de93bb69]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-de93bb69]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-de93bb69]{background:#4caf50}.bot-status.offline[data-v-de93bb69]{background:#f44336}.channel-info[data-v-de93bb69]{flex:1}.channel-name[data-v-de93bb69]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-de93bb69]{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-de93bb69]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-de93bb69]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble.dragging[data-v-de93bb69],.channel-message-count.draggable-bubble[data-v-de93bb69]:active{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-de93bb69]{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-de93bb69]{background:#f44336!important;animation:shake-de93bb69 .3s ease-in-out infinite}@keyframes pulseThreshold-de93bb69{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-de93bb69{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-de93bb69]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-de93bb69]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-de93bb69]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-de93bb69]:hover{background-color:#8080801a}.message-item.new-message[data-v-de93bb69]{background-color:#4caf5033;animation:highlight-de93bb69 2s ease-out}.message-item.bot-message[data-v-de93bb69]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-de93bb69]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-de93bb69]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-de93bb69]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-de93bb69]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-de93bb69]{order:1}.message-item.bot-message .message-text[data-v-de93bb69]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}@keyframes highlight-de93bb69{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-de93bb69]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-de93bb69]{flex:1}.message-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-de93bb69]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-de93bb69]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-all;white-space:pre-wrap;max-width:100%;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.message-item:not(.bot-message) .message-text[data-v-de93bb69]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.message-input[data-v-de93bb69]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:0 0;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-de93bb69]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-de93bb69]{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-de93bb69]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-de93bb69]:active{transform:scale(.95)}.input-row button[data-v-de93bb69]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-de93bb69]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-de93bb69]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease;max-width:min(400px,66.67vw);max-height:200px;width:auto;height:auto}.message-image-loading[data-v-de93bb69]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-de93bb69]{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-de93bb69]{display:block;margin-bottom:4px}.message-paragraph[data-v-de93bb69]:last-child{margin-bottom:0}.forward-message-container[data-v-de93bb69]{border:1px solid #fff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-de93bb69]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-de93bb69]:hover{background:#f0f0f0}.forward-message-title[data-v-de93bb69]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-de93bb69]{color:#666;font-size:13px;margin:2px 0;line-height:1.4;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.forward-message-footer[data-v-de93bb69]{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-de93bb69]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-de93bb69]{color:#666;font-size:12px}.forward-message-expanded[data-v-de93bb69]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-de93bb69]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-de93bb69]:last-child{border-bottom:none}.forwarded-message-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-de93bb69]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-de93bb69]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-de93bb69]{color:#555;font-size:13px;line-height:1.4;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.message-at[data-v-de93bb69]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-de93bb69]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-de93bb69]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:0;background:0 0;color:currentColor}.input-row input[data-v-de93bb69]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-de93bb69]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-de93bb69]{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-de93bb69]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-de93bb69]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-de93bb69]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-de93bb69]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-de93bb69]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-de93bb69]{display:inline;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.message-image-container[data-v-de93bb69]{display:block;margin:4px 0}.message-image[data-v-de93bb69]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-de93bb69]:hover{transform:scale(1.02)}.message-image-loading[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{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-de93bb69]:hover{background:#2196f333}.message-unknown[data-v-de93bb69]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-de93bb69{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-de93bb69]{background:#f44336!important;animation:shake-de93bb69 .3s ease-in-out infinite}@keyframes shake-de93bb69{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-de93bb69]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-de93bb69]{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-de93bb69 1.5s ease-in-out infinite}.context-menu[data-v-de93bb69]{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-de93bb69]{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-de93bb69]:last-child{border-bottom:none}.context-menu-item[data-v-de93bb69]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-de93bb69]{color:#d32f2f}.context-menu-item.danger[data-v-de93bb69]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-de93bb69]:before,.channel-item.pinned[data-v-de93bb69]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{position:relative;padding-left:24px}@media (prefers-color-scheme:dark){.context-menu[data-v-de93bb69]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-de93bb69]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-de93bb69]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-de93bb69]{color:#ff8a80}.context-menu-item.danger[data-v-de93bb69]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{background:#ffc10726}}.message-share-card[data-v-de93bb69]{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-de93bb69]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{transform:scale(1.05)}.share-card-content[data-v-de93bb69]{padding:8px}.share-card-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-de93bb69]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-de93bb69]{flex:1;min-width:0}.share-card-app-name[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-de93bb69]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-de93bb69]:after{transform:translate(2px)}.message-json-error[data-v-de93bb69],.message-json-raw[data-v-de93bb69]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-de93bb69]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-de93bb69]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-de93bb69]{margin-top:8px}.json-raw-data summary[data-v-de93bb69]{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-de93bb69]:hover{background:#2196f333}.json-raw-content[data-v-de93bb69]{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;word-break:break-all;overflow-wrap:anywhere;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme:dark){.message-share-card[data-v-de93bb69]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-de93bb69]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-de93bb69]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width:768px){.chat-container[data-v-de93bb69]{position:relative;height:100vh;height:100dvh}.bot-list[data-v-de93bb69],.channel-list[data-v-de93bb69],.message-area[data-v-de93bb69]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-de93bb69]{transform:translate(0);z-index:3}.channel-list[data-v-de93bb69]{transform:translate(100%);z-index:2}.message-area[data-v-de93bb69]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-de93bb69]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-de93bb69]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-de93bb69]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-de93bb69]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-de93bb69]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-de93bb69]{transform:translate(0);z-index:3}.back-button[data-v-de93bb69]{display:none!important}.panel-header[data-v-de93bb69]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-de93bb69]{text-align:right}.floating-scroll-button[data-v-de93bb69]{right:16px;bottom:calc(90px + env(safe-area-inset-bottom,0px));width:40px;height:40px;transition:bottom .3s ease}.message-input[data-v-de93bb69]{padding:8px 12px calc(12px + env(safe-area-inset-bottom,0px)) 12px;position:fixed;bottom:20px;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10;min-height:calc(60px + env(safe-area-inset-bottom,0px));transition:transform .3s ease;transform:translateZ(0)}.input-row input[data-v-de93bb69]{font-size:16px;padding:10px 12px}.input-row button[data-v-de93bb69]{padding:10px 16px;font-size:16px}.message-history[data-v-de93bb69]{padding:12px;max-height:calc(100vh - 140px - env(safe-area-inset-bottom,0px));max-height:calc(100dvh - 140px - env(safe-area-inset-bottom,0px));padding-bottom:calc(80px + env(safe-area-inset-bottom,0px));overflow-y:auto;-webkit-overflow-scrolling:touch;transition:max-height .3s ease}.message-item[data-v-de93bb69]{margin-bottom:12px;padding:6px}.message-text[data-v-de93bb69]{max-width:90%!important}.message-avatar[data-v-de93bb69]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-de93bb69]{margin-left:8px}.message-image[data-v-de93bb69]{max-width:min(280px,66.67vw);max-height:160px}.quote-content .message-image[data-v-de93bb69]{max-width:min(150px,50vw);max-height:80px}.context-menu[data-v-de93bb69]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-de93bb69]{padding:14px 16px;font-size:16px}.bot-item[data-v-de93bb69],.channel-item[data-v-de93bb69]{padding:14px 16px}.bot-avatar[data-v-de93bb69]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-de93bb69],.channel-name[data-v-de93bb69]{font-size:15px}.bot-platform[data-v-de93bb69],.channel-type[data-v-de93bb69]{font-size:13px}}@media (min-width:769px) and (max-width:1024px){.bot-list[data-v-de93bb69]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-de93bb69]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-de93bb69]{max-width:min(350px,66.67vw);max-height:180px}}.chat-container.swiping[data-v-de93bb69]{overflow:hidden}.bot-list.swiping[data-v-de93bb69],.channel-list.swiping[data-v-de93bb69],.message-area.swiping[data-v-de93bb69]{transition:none!important}.swipe-indicator[data-v-de93bb69]{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-de93bb69]{opacity:1}.message-area .message-content[data-v-de93bb69]{padding-bottom:80px}.image-preview-container[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-de93bb69]{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-de93bb69]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-de93bb69]{position:relative;margin-right:8px}.add-button[data-v-de93bb69]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea 0,#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-de93bb69]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3 0,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-de93bb69]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-de93bb69]:hover:before{opacity:1}.add-button.active[data-v-de93bb69]{background:linear-gradient(135deg,#f093fb 0,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-de93bb69]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-de93bb69]{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-de93bb69 .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-de93bb69]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:0 0;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-de93bb69]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea 0,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-de93bb69]:hover{background:linear-gradient(90deg,#667eea14 0,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-de93bb69]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-de93bb69]{flex-shrink:0}@media (prefers-color-scheme:dark){.action-menu[data-v-de93bb69]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-de93bb69]{color:#fff}.action-menu-item[data-v-de93bb69]:before{background:linear-gradient(135deg,#4facfe 0,#00f2fe)}.action-menu-item[data-v-de93bb69]:hover{background:linear-gradient(90deg,#4facfe1f 0,#00f2fe1f);color:#4facfe}.add-button[data-v-de93bb69]{background:linear-gradient(135deg,#4facfe 0,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-de93bb69]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-de93bb69]{background:linear-gradient(135deg,#fa709a 0,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-de93bb69]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width:768px){.image-preview-container[data-v-de93bb69]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-de93bb69]{width:50px;height:50px}.add-button[data-v-de93bb69]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-de93bb69]{min-width:100px}.action-menu-item[data-v-de93bb69]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-de93bb69]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-de93bb69]::-webkit-scrollbar{width:6px}.message-history[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-de93bb69]::-webkit-scrollbar{width:6px}.bot-items[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-de93bb69]::-webkit-scrollbar{width:6px}.channel-items[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme:dark){.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb,.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb,.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#fff3}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
|
|
1
|
+
.message-quote[data-v-de93bb69]{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-de93bb69]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-de93bb69]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-de93bb69]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-de93bb69]{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-de93bb69]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-de93bb69]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-de93bb69]{color:#7276b7;line-height:1.3;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.quote-content .message-image[data-v-de93bb69]{max-width:min(200px,50vw);max-height:100px}.quote-content .message-image-container[data-v-de93bb69]{margin:2px 0}@media (prefers-color-scheme:dark){.message-quote[data-v-de93bb69]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-de93bb69]{color:#adb5bd}.quote-username[data-v-de93bb69]{color:#0d6efd}}.chat-container[data-v-de93bb69]{display:flex;height:100vh;background:0 0;margin-left:0;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-de93bb69],.channel-list[data-v-de93bb69],.message-area[data-v-de93bb69]{display:flex;flex-direction:column;background:0 0;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-de93bb69]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-de93bb69]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-de93bb69]{flex:1;border-right:none}.panel-header[data-v-de93bb69]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:0 0;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-de93bb69]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-de93bb69]{display:none;background:0 0;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-de93bb69]:hover{background:#8080801a}.bot-items[data-v-de93bb69],.channel-items[data-v-de93bb69]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-de93bb69],.channel-item[data-v-de93bb69]{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-de93bb69]:hover,.channel-item[data-v-de93bb69]:hover{background:#8080801a}.bot-item.active[data-v-de93bb69],.channel-item.active[data-v-de93bb69]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-de93bb69]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-de93bb69]{flex:1}.bot-name[data-v-de93bb69]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-de93bb69]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-de93bb69]{background:#4caf50}.bot-status.offline[data-v-de93bb69]{background:#f44336}.channel-info[data-v-de93bb69]{flex:1}.channel-name[data-v-de93bb69]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-de93bb69]{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-de93bb69]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-de93bb69]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble.dragging[data-v-de93bb69],.channel-message-count.draggable-bubble[data-v-de93bb69]:active{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-de93bb69]{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-de93bb69]{background:#f44336!important;animation:shake-de93bb69 .3s ease-in-out infinite}@keyframes pulseThreshold-de93bb69{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-de93bb69{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-de93bb69]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-de93bb69]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-de93bb69]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-de93bb69]:hover{background-color:#8080801a}.message-item.new-message[data-v-de93bb69]{background-color:#4caf5033;animation:highlight-de93bb69 2s ease-out}.message-item.bot-message[data-v-de93bb69]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-de93bb69]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-de93bb69]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-de93bb69]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-de93bb69]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-de93bb69]{order:1}.message-item.bot-message .message-text[data-v-de93bb69]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}@keyframes highlight-de93bb69{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-de93bb69]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-de93bb69]{flex:1}.message-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-de93bb69]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-de93bb69]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-all;white-space:pre-wrap;max-width:100%;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.message-item:not(.bot-message) .message-text[data-v-de93bb69]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.message-input[data-v-de93bb69]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:0 0;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-de93bb69]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-de93bb69]{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-de93bb69]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-de93bb69]:active{transform:scale(.95)}.input-row button[data-v-de93bb69]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-de93bb69]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-de93bb69]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease;max-width:min(400px,66.67vw);max-height:200px;width:auto;height:auto;image-rendering:auto;-webkit-image-rendering:auto;-moz-image-rendering:auto;-o-image-rendering:auto}.message-image[src*=".gif"][data-v-de93bb69],.message-image[src*="image/gif"][data-v-de93bb69]{image-rendering:auto!important;-webkit-image-rendering:auto!important;animation-play-state:running!important}.message-image-loading[data-v-de93bb69]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-de93bb69]{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-de93bb69]{display:block;margin-bottom:4px}.message-paragraph[data-v-de93bb69]:last-child{margin-bottom:0}.forward-message-container[data-v-de93bb69]{border:1px solid #fff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-de93bb69]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-de93bb69]:hover{background:#f0f0f0}.forward-message-title[data-v-de93bb69]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-de93bb69]{color:#666;font-size:13px;margin:2px 0;line-height:1.4;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.forward-message-footer[data-v-de93bb69]{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-de93bb69]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-de93bb69]{color:#666;font-size:12px}.forward-message-expanded[data-v-de93bb69]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-de93bb69]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-de93bb69]:last-child{border-bottom:none}.forwarded-message-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-de93bb69]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-de93bb69]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-de93bb69]{color:#555;font-size:13px;line-height:1.4;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.message-at[data-v-de93bb69]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-de93bb69]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-de93bb69]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:0;background:0 0;color:currentColor}.input-row input[data-v-de93bb69]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-de93bb69]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-de93bb69]{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-de93bb69]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-de93bb69]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-de93bb69]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-de93bb69]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-de93bb69]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-de93bb69]{display:inline;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.message-image-container[data-v-de93bb69]{display:block;margin:4px 0}.message-image[data-v-de93bb69]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-de93bb69]:hover{transform:scale(1.02)}.message-image-loading[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{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-de93bb69]:hover{background:#2196f333}.message-unknown[data-v-de93bb69]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-de93bb69{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-de93bb69]{background:#f44336!important;animation:shake-de93bb69 .3s ease-in-out infinite}@keyframes shake-de93bb69{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-de93bb69]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-de93bb69]{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-de93bb69 1.5s ease-in-out infinite}.context-menu[data-v-de93bb69]{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-de93bb69]{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-de93bb69]:last-child{border-bottom:none}.context-menu-item[data-v-de93bb69]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-de93bb69]{color:#d32f2f}.context-menu-item.danger[data-v-de93bb69]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-de93bb69]:before,.channel-item.pinned[data-v-de93bb69]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{position:relative;padding-left:24px}@media (prefers-color-scheme:dark){.context-menu[data-v-de93bb69]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-de93bb69]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-de93bb69]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-de93bb69]{color:#ff8a80}.context-menu-item.danger[data-v-de93bb69]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-de93bb69],.channel-item.pinned[data-v-de93bb69]{background:#ffc10726}}.message-share-card[data-v-de93bb69]{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-de93bb69]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{transform:scale(1.05)}.share-card-content[data-v-de93bb69]{padding:8px}.share-card-header[data-v-de93bb69]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-de93bb69]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-de93bb69]{flex:1;min-width:0}.share-card-app-name[data-v-de93bb69]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-de93bb69]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-de93bb69]:after{transform:translate(2px)}.message-json-error[data-v-de93bb69],.message-json-raw[data-v-de93bb69]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-de93bb69]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-de93bb69]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-de93bb69]{margin-top:8px}.json-raw-data summary[data-v-de93bb69]{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-de93bb69]:hover{background:#2196f333}.json-raw-content[data-v-de93bb69]{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;word-break:break-all;overflow-wrap:anywhere;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme:dark){.message-share-card[data-v-de93bb69]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-de93bb69]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-de93bb69]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width:768px){.chat-container[data-v-de93bb69]{position:relative;height:100vh;height:100dvh}.bot-list[data-v-de93bb69],.channel-list[data-v-de93bb69],.message-area[data-v-de93bb69]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-de93bb69]{transform:translate(0);z-index:3}.channel-list[data-v-de93bb69]{transform:translate(100%);z-index:2}.message-area[data-v-de93bb69]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-de93bb69]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-de93bb69]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-de93bb69]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-de93bb69]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-de93bb69]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-de93bb69]{transform:translate(0);z-index:3}.back-button[data-v-de93bb69]{display:none!important}.panel-header[data-v-de93bb69]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-de93bb69]{text-align:right}.floating-scroll-button[data-v-de93bb69]{right:16px;bottom:calc(90px + env(safe-area-inset-bottom,0px));width:40px;height:40px;transition:bottom .3s ease}.message-input[data-v-de93bb69]{padding:8px 12px calc(12px + env(safe-area-inset-bottom,0px)) 12px;position:fixed;bottom:20px;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10;min-height:calc(60px + env(safe-area-inset-bottom,0px));transition:transform .3s ease;transform:translateZ(0)}.input-row input[data-v-de93bb69]{font-size:16px;padding:10px 12px}.input-row button[data-v-de93bb69]{padding:10px 16px;font-size:16px}.message-history[data-v-de93bb69]{padding:12px;max-height:calc(100vh - 140px - env(safe-area-inset-bottom,0px));max-height:calc(100dvh - 140px - env(safe-area-inset-bottom,0px));padding-bottom:calc(80px + env(safe-area-inset-bottom,0px));overflow-y:auto;-webkit-overflow-scrolling:touch;transition:max-height .3s ease}.message-item[data-v-de93bb69]{margin-bottom:12px;padding:6px}.message-text[data-v-de93bb69]{max-width:90%!important}.message-avatar[data-v-de93bb69]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-de93bb69]{margin-left:8px}.message-image[data-v-de93bb69]{max-width:min(280px,66.67vw);max-height:160px}.quote-content .message-image[data-v-de93bb69]{max-width:min(150px,50vw);max-height:80px}.context-menu[data-v-de93bb69]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-de93bb69]{padding:14px 16px;font-size:16px}.bot-item[data-v-de93bb69],.channel-item[data-v-de93bb69]{padding:14px 16px}.bot-avatar[data-v-de93bb69]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-de93bb69],.channel-name[data-v-de93bb69]{font-size:15px}.bot-platform[data-v-de93bb69],.channel-type[data-v-de93bb69]{font-size:13px}}@media (min-width:769px) and (max-width:1024px){.bot-list[data-v-de93bb69]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-de93bb69]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-de93bb69]{max-width:min(350px,66.67vw);max-height:180px}}.chat-container.swiping[data-v-de93bb69]{overflow:hidden}.bot-list.swiping[data-v-de93bb69],.channel-list.swiping[data-v-de93bb69],.message-area.swiping[data-v-de93bb69]{transition:none!important}.swipe-indicator[data-v-de93bb69]{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-de93bb69]{opacity:1}.message-area .message-content[data-v-de93bb69]{padding-bottom:80px}.image-preview-container[data-v-de93bb69]{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-de93bb69]{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-de93bb69]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-de93bb69]{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-de93bb69]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-de93bb69]{position:relative;margin-right:8px}.add-button[data-v-de93bb69]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea 0,#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-de93bb69]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3 0,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-de93bb69]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-de93bb69]:hover:before{opacity:1}.add-button.active[data-v-de93bb69]{background:linear-gradient(135deg,#f093fb 0,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-de93bb69]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-de93bb69]{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-de93bb69 .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-de93bb69]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:0 0;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-de93bb69]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea 0,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-de93bb69]:hover{background:linear-gradient(90deg,#667eea14 0,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-de93bb69]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-de93bb69]{flex-shrink:0}@media (prefers-color-scheme:dark){.action-menu[data-v-de93bb69]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-de93bb69]{color:#fff}.action-menu-item[data-v-de93bb69]:before{background:linear-gradient(135deg,#4facfe 0,#00f2fe)}.action-menu-item[data-v-de93bb69]:hover{background:linear-gradient(90deg,#4facfe1f 0,#00f2fe1f);color:#4facfe}.add-button[data-v-de93bb69]{background:linear-gradient(135deg,#4facfe 0,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-de93bb69]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-de93bb69]{background:linear-gradient(135deg,#fa709a 0,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-de93bb69]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width:768px){.image-preview-container[data-v-de93bb69]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-de93bb69]{width:50px;height:50px}.add-button[data-v-de93bb69]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-de93bb69]{min-width:100px}.action-menu-item[data-v-de93bb69]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-de93bb69]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-de93bb69]::-webkit-scrollbar{width:6px}.message-history[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-de93bb69]::-webkit-scrollbar{width:6px}.bot-items[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-de93bb69]::-webkit-scrollbar{width:6px}.channel-items[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-track{background:0 0}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme:dark){.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb,.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb,.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#fff3}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.message-history[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
|
package/lib/index.js
CHANGED
|
@@ -138,6 +138,17 @@ var MessageHandler = class {
|
|
|
138
138
|
}
|
|
139
139
|
logger;
|
|
140
140
|
utils;
|
|
141
|
+
// 存储正确的 channelId 映射,key 是 selfId,value 是正确的 channelId
|
|
142
|
+
correctChannelIds = /* @__PURE__ */ new Map();
|
|
143
|
+
// 设置正确的 channelId
|
|
144
|
+
setCorrectChannelId(selfId, channelId) {
|
|
145
|
+
this.correctChannelIds.set(selfId, channelId);
|
|
146
|
+
this.logInfo("设置正确的 channelId:", { selfId, channelId });
|
|
147
|
+
}
|
|
148
|
+
// 获取正确的 channelId
|
|
149
|
+
getCorrectChannelId(selfId) {
|
|
150
|
+
return this.correctChannelIds.get(selfId);
|
|
151
|
+
}
|
|
141
152
|
// 更新机器人信息到JSON文件
|
|
142
153
|
async updateBotInfoToFile(session) {
|
|
143
154
|
const data = this.fileManager.readChatDataFromFile();
|
|
@@ -170,10 +181,11 @@ var MessageHandler = class {
|
|
|
170
181
|
}
|
|
171
182
|
const channelInfo = {
|
|
172
183
|
id: session.channelId,
|
|
173
|
-
name: session.
|
|
184
|
+
name: session.isDirect ? `私信 ${session.channelId}` : `${guildName} (${session.channelId})`,
|
|
174
185
|
type: session.type || 0,
|
|
175
|
-
|
|
176
|
-
guildName
|
|
186
|
+
channelId: session.channelId,
|
|
187
|
+
guildName,
|
|
188
|
+
isDirect: session.isDirect
|
|
177
189
|
};
|
|
178
190
|
data.channels[session.selfId][session.channelId] = channelInfo;
|
|
179
191
|
this.fileManager.writeChatDataToFile(data);
|
|
@@ -226,10 +238,10 @@ var MessageHandler = class {
|
|
|
226
238
|
selfId: session.selfId,
|
|
227
239
|
elements: this.utils.cleanBase64Content(elements),
|
|
228
240
|
type: "user",
|
|
229
|
-
guildId: session.guildId,
|
|
230
241
|
guildName,
|
|
231
242
|
platform: session.platform || "unknown",
|
|
232
|
-
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0
|
|
243
|
+
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0,
|
|
244
|
+
isDirect: session.isDirect
|
|
233
245
|
};
|
|
234
246
|
await this.fileManager.addMessageToFile(messageInfo);
|
|
235
247
|
const messageEvent = {
|
|
@@ -243,11 +255,11 @@ var MessageHandler = class {
|
|
|
243
255
|
username: session.username || session.event?.user?.name || session.userId || "unknown",
|
|
244
256
|
avatar: session.event?.user?.avatar,
|
|
245
257
|
timestamp,
|
|
246
|
-
guildId: session.guildId,
|
|
247
258
|
guildName,
|
|
248
259
|
channelType: session.type || 0,
|
|
249
260
|
elements: this.utils.cleanBase64Content(elements),
|
|
250
261
|
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : void 0,
|
|
262
|
+
isDirect: session.isDirect,
|
|
251
263
|
bot: {
|
|
252
264
|
avatar: session.bot.user?.avatar,
|
|
253
265
|
name: session.bot.user?.name
|
|
@@ -261,6 +273,16 @@ var MessageHandler = class {
|
|
|
261
273
|
// 处理机器人发送的消息
|
|
262
274
|
async broadcastBotMessageEvent(session) {
|
|
263
275
|
try {
|
|
276
|
+
const correctChannelId = this.getCorrectChannelId(session.selfId);
|
|
277
|
+
this.logInfo("机器人发送消息调试信息:", {
|
|
278
|
+
"session.channelId": session.channelId,
|
|
279
|
+
"session.event?.channel?.id": session.event?.channel?.id,
|
|
280
|
+
"correctChannelId": correctChannelId,
|
|
281
|
+
"session.guildId": session.guildId,
|
|
282
|
+
"session.isDirect": session.isDirect,
|
|
283
|
+
"session.platform": session.platform
|
|
284
|
+
});
|
|
285
|
+
const finalChannelId = correctChannelId || session.channelId;
|
|
264
286
|
await this.updateBotInfoToFile(session);
|
|
265
287
|
const guildName = await this.updateChannelInfoToFile(session);
|
|
266
288
|
const timestamp = Date.now();
|
|
@@ -275,30 +297,30 @@ var MessageHandler = class {
|
|
|
275
297
|
username: session.bot.user?.name || `Bot-${session.selfId}`,
|
|
276
298
|
avatar: session.bot.user?.avatar,
|
|
277
299
|
timestamp,
|
|
278
|
-
channelId:
|
|
300
|
+
channelId: finalChannelId,
|
|
279
301
|
selfId: session.selfId,
|
|
280
302
|
elements: this.utils.cleanBase64Content(session.event?.message?.elements),
|
|
281
303
|
type: "bot",
|
|
282
|
-
guildId: session.event?.guild?.id || session.guildId,
|
|
283
304
|
guildName,
|
|
284
|
-
platform: session.platform || "unknown"
|
|
305
|
+
platform: session.platform || "unknown",
|
|
306
|
+
isDirect: session.isDirect
|
|
285
307
|
};
|
|
286
308
|
await this.fileManager.addMessageToFile(messageInfo);
|
|
287
309
|
const messageEvent = {
|
|
288
310
|
type: "bot-message",
|
|
289
311
|
selfId: session.selfId,
|
|
290
312
|
platform: session.platform || "unknown",
|
|
291
|
-
channelId:
|
|
313
|
+
channelId: finalChannelId,
|
|
292
314
|
messageId: `bot-msg-${timestamp}`,
|
|
293
315
|
content,
|
|
294
316
|
userId: session.selfId,
|
|
295
317
|
username: session.bot.user?.name || `Bot-${session.selfId}`,
|
|
296
318
|
avatar: session.bot.user?.avatar,
|
|
297
319
|
timestamp,
|
|
298
|
-
guildId: session.event?.guild?.id || session.guildId,
|
|
299
320
|
guildName,
|
|
300
321
|
channelType: session.event?.channel?.type || session.type || 0,
|
|
301
322
|
elements: this.utils.cleanBase64Content(session.event?.message?.elements),
|
|
323
|
+
isDirect: session.isDirect,
|
|
302
324
|
bot: {
|
|
303
325
|
avatar: session.bot.user?.avatar,
|
|
304
326
|
name: session.bot.user?.name
|
|
@@ -310,11 +332,14 @@ var MessageHandler = class {
|
|
|
310
332
|
this.logInfo("机器人发送消息 (before-send):", {
|
|
311
333
|
selfId: session.selfId,
|
|
312
334
|
channelId: messageEvent.channelId,
|
|
335
|
+
originalChannelId: session.channelId,
|
|
336
|
+
correctedChannelId: finalChannelId,
|
|
313
337
|
content,
|
|
314
338
|
platform: session.platform,
|
|
315
339
|
imageCount: imageElements.length,
|
|
316
340
|
imageUrls: imageElements.map((el) => el.attrs?.src || el.attrs?.url || el.attrs?.file)
|
|
317
341
|
});
|
|
342
|
+
this.correctChannelIds.delete(session.selfId);
|
|
318
343
|
this.ctx.console.broadcast("chat-bot-message-event", messageEvent);
|
|
319
344
|
} catch (error) {
|
|
320
345
|
this.logger.error("广播机器人消息事件失败:", error);
|
|
@@ -474,10 +499,11 @@ var FileManager = class {
|
|
|
474
499
|
var import_koishi = require("koishi");
|
|
475
500
|
var import_node_url = require("node:url");
|
|
476
501
|
var ApiHandlers = class {
|
|
477
|
-
constructor(ctx, config, fileManager) {
|
|
502
|
+
constructor(ctx, config, fileManager, messageHandler) {
|
|
478
503
|
this.ctx = ctx;
|
|
479
504
|
this.config = config;
|
|
480
505
|
this.fileManager = fileManager;
|
|
506
|
+
this.messageHandler = messageHandler;
|
|
481
507
|
this.logger = ctx.logger("chat-patch");
|
|
482
508
|
}
|
|
483
509
|
static {
|
|
@@ -630,6 +656,7 @@ var ApiHandlers = class {
|
|
|
630
656
|
}
|
|
631
657
|
}
|
|
632
658
|
}
|
|
659
|
+
this.messageHandler.setCorrectChannelId(data.selfId, data.channelId);
|
|
633
660
|
const result = await bot.sendMessage(data.channelId, messageContent);
|
|
634
661
|
this.logInfo("消息发送成功:", result);
|
|
635
662
|
return {
|
|
@@ -737,11 +764,11 @@ var ApiHandlers = class {
|
|
|
737
764
|
});
|
|
738
765
|
this.ctx.console.addListener("upload-image", async (data) => {
|
|
739
766
|
try {
|
|
740
|
-
this.logInfo("收到图片上传请求:", { filename: data.filename, mimeType: data.mimeType });
|
|
767
|
+
this.logInfo("收到图片上传请求:", { filename: data.filename, mimeType: data.mimeType, isGif: data.isGif });
|
|
741
768
|
const base64Data = data.file.replace(/^data:image\/\w+;base64,/, "");
|
|
742
769
|
const buffer = Buffer.from(base64Data, "base64");
|
|
743
770
|
const tempId = Date.now() + "_" + Math.random().toString(36).substring(2, 11);
|
|
744
|
-
const extension = data.filename.split(".").pop() || "jpg";
|
|
771
|
+
const extension = data.filename.split(".").pop()?.toLowerCase() || (data.isGif ? "gif" : "jpg");
|
|
745
772
|
const tempFilename = `temp_${tempId}.${extension}`;
|
|
746
773
|
const tempDir = this.ctx.baseDir + "/data/chat-patch/temp";
|
|
747
774
|
if (!require("fs").existsSync(tempDir)) {
|
|
@@ -749,13 +776,14 @@ var ApiHandlers = class {
|
|
|
749
776
|
}
|
|
750
777
|
const tempPath = `${tempDir}/${tempFilename}`;
|
|
751
778
|
require("fs").writeFileSync(tempPath, buffer);
|
|
752
|
-
this.logInfo("图片上传成功:", { tempPath, size: buffer.length });
|
|
779
|
+
this.logInfo("图片上传成功:", { tempPath, size: buffer.length, isGif: data.isGif });
|
|
753
780
|
return {
|
|
754
781
|
success: true,
|
|
755
782
|
tempId,
|
|
756
783
|
tempPath,
|
|
757
784
|
filename: data.filename,
|
|
758
|
-
size: buffer.length
|
|
785
|
+
size: buffer.length,
|
|
786
|
+
isGif: data.isGif
|
|
759
787
|
};
|
|
760
788
|
} catch (error) {
|
|
761
789
|
this.logger.error("图片上传失败:", error);
|
|
@@ -972,7 +1000,7 @@ async function apply(ctx, config) {
|
|
|
972
1000
|
const logger = ctx.logger("chat-patch");
|
|
973
1001
|
const fileManager = new FileManager(ctx, config);
|
|
974
1002
|
const messageHandler = new MessageHandler(ctx, config, fileManager);
|
|
975
|
-
const apiHandlers = new ApiHandlers(ctx, config, fileManager);
|
|
1003
|
+
const apiHandlers = new ApiHandlers(ctx, config, fileManager, messageHandler);
|
|
976
1004
|
const utils = new Utils(config);
|
|
977
1005
|
const initialData = fileManager.readChatDataFromFile();
|
|
978
1006
|
const cleanedData = fileManager.cleanExcessMessages(initialData);
|
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.16",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
package/src/api-handlers.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FileManager } from './file-manager'
|
|
2
|
+
import { MessageHandler } from './message-handler'
|
|
2
3
|
import { Context, h, Logger } from 'koishi'
|
|
3
4
|
import { Config } from './config'
|
|
4
5
|
|
|
@@ -10,7 +11,8 @@ export class ApiHandlers {
|
|
|
10
11
|
constructor(
|
|
11
12
|
private ctx: Context,
|
|
12
13
|
private config: Config,
|
|
13
|
-
private fileManager: FileManager
|
|
14
|
+
private fileManager: FileManager,
|
|
15
|
+
private messageHandler: MessageHandler
|
|
14
16
|
) {
|
|
15
17
|
this.logger = ctx.logger('chat-patch')
|
|
16
18
|
}
|
|
@@ -218,6 +220,9 @@ export class ApiHandlers {
|
|
|
218
220
|
}
|
|
219
221
|
}
|
|
220
222
|
|
|
223
|
+
// 在发送消息前,通知 MessageHandler 正确的 channelId
|
|
224
|
+
this.messageHandler.setCorrectChannelId(data.selfId, data.channelId)
|
|
225
|
+
|
|
221
226
|
const result = await bot.sendMessage(data.channelId, messageContent)
|
|
222
227
|
this.logInfo('消息发送成功:', result)
|
|
223
228
|
|
|
@@ -366,17 +371,18 @@ export class ApiHandlers {
|
|
|
366
371
|
file: string // base64 encoded image
|
|
367
372
|
filename: string
|
|
368
373
|
mimeType: string
|
|
374
|
+
isGif?: boolean // 是否为GIF图片
|
|
369
375
|
}) => {
|
|
370
376
|
try {
|
|
371
|
-
this.logInfo('收到图片上传请求:', { filename: data.filename, mimeType: data.mimeType })
|
|
377
|
+
this.logInfo('收到图片上传请求:', { filename: data.filename, mimeType: data.mimeType, isGif: data.isGif })
|
|
372
378
|
|
|
373
379
|
// 将base64转换为Buffer
|
|
374
380
|
const base64Data = data.file.replace(/^data:image\/\w+;base64,/, '')
|
|
375
381
|
const buffer = Buffer.from(base64Data, 'base64')
|
|
376
382
|
|
|
377
|
-
//
|
|
383
|
+
// 生成临时文件路径,保持原始扩展名以保持GIF格式
|
|
378
384
|
const tempId = Date.now() + '_' + Math.random().toString(36).substring(2, 11)
|
|
379
|
-
const extension = data.filename.split('.').pop() || 'jpg'
|
|
385
|
+
const extension = data.filename.split('.').pop()?.toLowerCase() || (data.isGif ? 'gif' : 'jpg')
|
|
380
386
|
const tempFilename = `temp_${tempId}.${extension}`
|
|
381
387
|
|
|
382
388
|
// 保存到临时目录
|
|
@@ -386,16 +392,19 @@ export class ApiHandlers {
|
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
const tempPath = `${tempDir}/${tempFilename}`
|
|
395
|
+
|
|
396
|
+
// 对于GIF文件,直接保存原始数据以保持动画
|
|
389
397
|
require('fs').writeFileSync(tempPath, buffer)
|
|
390
398
|
|
|
391
|
-
this.logInfo('图片上传成功:', { tempPath, size: buffer.length })
|
|
399
|
+
this.logInfo('图片上传成功:', { tempPath, size: buffer.length, isGif: data.isGif })
|
|
392
400
|
|
|
393
401
|
return {
|
|
394
402
|
success: true,
|
|
395
403
|
tempId: tempId,
|
|
396
404
|
tempPath: tempPath,
|
|
397
405
|
filename: data.filename,
|
|
398
|
-
size: buffer.length
|
|
406
|
+
size: buffer.length,
|
|
407
|
+
isGif: data.isGif
|
|
399
408
|
}
|
|
400
409
|
} catch (error: any) {
|
|
401
410
|
this.logger.error('图片上传失败:', error)
|
package/src/index.ts
CHANGED
|
@@ -35,7 +35,7 @@ export async function apply(ctx: Context, config: Config) {
|
|
|
35
35
|
// 初始化各个模块
|
|
36
36
|
const fileManager = new FileManager(ctx, config)
|
|
37
37
|
const messageHandler = new MessageHandler(ctx, config, fileManager)
|
|
38
|
-
const apiHandlers = new ApiHandlers(ctx, config, fileManager)
|
|
38
|
+
const apiHandlers = new ApiHandlers(ctx, config, fileManager, messageHandler)
|
|
39
39
|
const utils = new Utils(config)
|
|
40
40
|
|
|
41
41
|
// 初始化数据
|
package/src/message-handler.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { Utils } from './utils'
|
|
|
7
7
|
export class MessageHandler {
|
|
8
8
|
private logger: Logger
|
|
9
9
|
private utils: Utils
|
|
10
|
+
// 存储正确的 channelId 映射,key 是 selfId,value 是正确的 channelId
|
|
11
|
+
private correctChannelIds: Map<string, string> = new Map()
|
|
10
12
|
|
|
11
13
|
constructor(
|
|
12
14
|
private ctx: Context,
|
|
@@ -17,6 +19,17 @@ export class MessageHandler {
|
|
|
17
19
|
this.utils = new Utils(config)
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
// 设置正确的 channelId
|
|
23
|
+
setCorrectChannelId(selfId: string, channelId: string) {
|
|
24
|
+
this.correctChannelIds.set(selfId, channelId)
|
|
25
|
+
this.logInfo('设置正确的 channelId:', { selfId, channelId })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 获取正确的 channelId
|
|
29
|
+
getCorrectChannelId(selfId: string): string | undefined {
|
|
30
|
+
return this.correctChannelIds.get(selfId)
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
// 更新机器人信息到JSON文件
|
|
21
34
|
async updateBotInfoToFile(session: Session) {
|
|
22
35
|
const data = this.fileManager.readChatDataFromFile()
|
|
@@ -56,12 +69,13 @@ export class MessageHandler {
|
|
|
56
69
|
|
|
57
70
|
const channelInfo: ChannelInfo = {
|
|
58
71
|
id: session.channelId,
|
|
59
|
-
name: session.
|
|
60
|
-
?
|
|
61
|
-
:
|
|
72
|
+
name: session.isDirect
|
|
73
|
+
? `私信 ${session.channelId}`
|
|
74
|
+
: `${guildName} (${session.channelId})`,
|
|
62
75
|
type: session.type || 0,
|
|
63
|
-
|
|
64
|
-
guildName: guildName
|
|
76
|
+
channelId: session.channelId,
|
|
77
|
+
guildName: guildName,
|
|
78
|
+
isDirect: session.isDirect
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
data.channels[session.selfId][session.channelId] = channelInfo
|
|
@@ -129,10 +143,10 @@ export class MessageHandler {
|
|
|
129
143
|
selfId: session.selfId,
|
|
130
144
|
elements: this.utils.cleanBase64Content(elements),
|
|
131
145
|
type: 'user',
|
|
132
|
-
guildId: session.guildId,
|
|
133
146
|
guildName: guildName,
|
|
134
147
|
platform: session.platform || 'unknown',
|
|
135
|
-
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined
|
|
148
|
+
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined,
|
|
149
|
+
isDirect: session.isDirect
|
|
136
150
|
}
|
|
137
151
|
|
|
138
152
|
await this.fileManager.addMessageToFile(messageInfo)
|
|
@@ -148,11 +162,11 @@ export class MessageHandler {
|
|
|
148
162
|
username: session.username || session.event?.user?.name || session.userId || 'unknown',
|
|
149
163
|
avatar: session.event?.user?.avatar,
|
|
150
164
|
timestamp: timestamp,
|
|
151
|
-
guildId: session.guildId,
|
|
152
165
|
guildName: guildName,
|
|
153
166
|
channelType: session.type || 0,
|
|
154
167
|
elements: this.utils.cleanBase64Content(elements),
|
|
155
168
|
quote: quoteInfo ? this.utils.cleanBase64Content(quoteInfo) : undefined,
|
|
169
|
+
isDirect: session.isDirect,
|
|
156
170
|
bot: {
|
|
157
171
|
avatar: session.bot.user?.avatar,
|
|
158
172
|
name: session.bot.user?.name,
|
|
@@ -168,6 +182,22 @@ export class MessageHandler {
|
|
|
168
182
|
// 处理机器人发送的消息
|
|
169
183
|
async broadcastBotMessageEvent(session: Session) {
|
|
170
184
|
try {
|
|
185
|
+
// 获取正确的 channelId
|
|
186
|
+
const correctChannelId = this.getCorrectChannelId(session.selfId)
|
|
187
|
+
|
|
188
|
+
// 调试日志:检查 channelId 的来源
|
|
189
|
+
this.logInfo('机器人发送消息调试信息:', {
|
|
190
|
+
'session.channelId': session.channelId,
|
|
191
|
+
'session.event?.channel?.id': session.event?.channel?.id,
|
|
192
|
+
'correctChannelId': correctChannelId,
|
|
193
|
+
'session.guildId': session.guildId,
|
|
194
|
+
'session.isDirect': session.isDirect,
|
|
195
|
+
'session.platform': session.platform
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// 使用正确的 channelId,如果没有则使用 session.channelId
|
|
199
|
+
const finalChannelId = correctChannelId || session.channelId
|
|
200
|
+
|
|
171
201
|
await this.updateBotInfoToFile(session)
|
|
172
202
|
const guildName = await this.updateChannelInfoToFile(session)
|
|
173
203
|
|
|
@@ -187,13 +217,13 @@ export class MessageHandler {
|
|
|
187
217
|
username: session.bot.user?.name || `Bot-${session.selfId}`,
|
|
188
218
|
avatar: session.bot.user?.avatar,
|
|
189
219
|
timestamp: timestamp,
|
|
190
|
-
channelId:
|
|
220
|
+
channelId: finalChannelId,
|
|
191
221
|
selfId: session.selfId,
|
|
192
222
|
elements: this.utils.cleanBase64Content(session.event?.message?.elements),
|
|
193
223
|
type: 'bot',
|
|
194
|
-
guildId: session.event?.guild?.id || session.guildId,
|
|
195
224
|
guildName: guildName,
|
|
196
|
-
platform: session.platform || 'unknown'
|
|
225
|
+
platform: session.platform || 'unknown',
|
|
226
|
+
isDirect: session.isDirect
|
|
197
227
|
}
|
|
198
228
|
|
|
199
229
|
await this.fileManager.addMessageToFile(messageInfo)
|
|
@@ -202,17 +232,17 @@ export class MessageHandler {
|
|
|
202
232
|
type: 'bot-message',
|
|
203
233
|
selfId: session.selfId,
|
|
204
234
|
platform: session.platform || 'unknown',
|
|
205
|
-
channelId:
|
|
235
|
+
channelId: finalChannelId,
|
|
206
236
|
messageId: `bot-msg-${timestamp}`,
|
|
207
237
|
content: content,
|
|
208
238
|
userId: session.selfId,
|
|
209
239
|
username: session.bot.user?.name || `Bot-${session.selfId}`,
|
|
210
240
|
avatar: session.bot.user?.avatar,
|
|
211
241
|
timestamp: timestamp,
|
|
212
|
-
guildId: session.event?.guild?.id || session.guildId,
|
|
213
242
|
guildName: guildName,
|
|
214
243
|
channelType: session.event?.channel?.type || session.type || 0,
|
|
215
244
|
elements: this.utils.cleanBase64Content(session.event?.message?.elements),
|
|
245
|
+
isDirect: session.isDirect,
|
|
216
246
|
bot: {
|
|
217
247
|
avatar: session.bot.user?.avatar,
|
|
218
248
|
name: session.bot.user?.name,
|
|
@@ -227,12 +257,17 @@ export class MessageHandler {
|
|
|
227
257
|
this.logInfo('机器人发送消息 (before-send):', {
|
|
228
258
|
selfId: session.selfId,
|
|
229
259
|
channelId: messageEvent.channelId,
|
|
260
|
+
originalChannelId: session.channelId,
|
|
261
|
+
correctedChannelId: finalChannelId,
|
|
230
262
|
content: content,
|
|
231
263
|
platform: session.platform,
|
|
232
264
|
imageCount: imageElements.length,
|
|
233
265
|
imageUrls: imageElements.map((el: any) => el.attrs?.src || el.attrs?.url || el.attrs?.file)
|
|
234
266
|
})
|
|
235
267
|
|
|
268
|
+
// 清理已使用的 channelId 映射
|
|
269
|
+
this.correctChannelIds.delete(session.selfId)
|
|
270
|
+
|
|
236
271
|
this.ctx.console.broadcast('chat-bot-message-event', messageEvent)
|
|
237
272
|
} catch (error) {
|
|
238
273
|
this.logger.error('广播机器人消息事件失败:', error)
|
package/src/types.ts
CHANGED
|
@@ -12,8 +12,9 @@ export interface ChannelInfo {
|
|
|
12
12
|
id: string
|
|
13
13
|
name: string
|
|
14
14
|
type: number | string
|
|
15
|
-
|
|
15
|
+
channelId?: string
|
|
16
16
|
guildName?: string
|
|
17
|
+
isDirect?: boolean
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export interface QuoteInfo {
|
|
@@ -46,6 +47,7 @@ export interface MessageInfo {
|
|
|
46
47
|
guildName?: string
|
|
47
48
|
platform: string
|
|
48
49
|
quote?: QuoteInfo
|
|
50
|
+
isDirect?: boolean
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export interface ChatData {
|