koishi-plugin-chat-patch 1.0.18 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -449,7 +449,7 @@ export function useChatLogic() {
449
449
  isExpanded.value = !isExpanded.value
450
450
  }
451
451
 
452
- const getPreviewText = () => {
452
+ const getPreviewText = (): { previews: string[]; messageCount: number } => {
453
453
  if (!props.element.children || props.element.children.length === 0) {
454
454
  return {
455
455
  previews: [],
@@ -488,7 +488,7 @@ export function useChatLogic() {
488
488
  }
489
489
  }
490
490
 
491
- const renderForwardedMessage = (message: any, index: number) => {
491
+ const renderForwardedMessage = (message: any, index: number): any => {
492
492
  const nickname = message.attrs?.nickname || '用户'
493
493
  const userId = message.attrs?.userId || 'unknown'
494
494
 
@@ -551,7 +551,7 @@ export function useChatLogic() {
551
551
  }
552
552
  },
553
553
  setup(props) {
554
- const renderElement = (element: MessageElement) => {
554
+ const renderElement = (element: MessageElement): any => {
555
555
  switch (element.type) {
556
556
  case 'text':
557
557
  return h('span', { class: 'message-text-content' }, element.attrs.content || '')
@@ -614,7 +614,7 @@ export function useChatLogic() {
614
614
  case 'p':
615
615
  // 处理段落元素,递归渲染子元素
616
616
  if (element.children && element.children.length > 0) {
617
- const childElements = element.children.map((child, index) =>
617
+ const childElements: any[] = element.children.map((child, index) =>
618
618
  h(MessageElement, {
619
619
  key: index,
620
620
  element: child,
@@ -654,6 +654,13 @@ export function useChatLogic() {
654
654
  // 存储每个频道的真实消息数量
655
655
  const channelMessageCounts = ref<Record<string, number>>({})
656
656
 
657
+ // 存储每个频道的分页状态
658
+ const channelPagination = ref<Record<string, {
659
+ offset: number
660
+ hasMore: boolean
661
+ loading: boolean
662
+ }>>({})
663
+
657
664
  const pluginConfig = ref<{
658
665
  maxMessagesPerChannel: number
659
666
  keepMessagesOnClear: number
@@ -682,6 +689,8 @@ export function useChatLogic() {
682
689
 
683
690
  // 内存中的URL缓存
684
691
  const imageBlobUrls = ref<Record<string, string>>({})
692
+ // 正在加载的图片URL锁,防止并发请求
693
+ const loadingImages = new Map<string, Promise<string | null>>()
685
694
 
686
695
  // 内存管理配置
687
696
  const MAX_MEMORY_USAGE = 100 * 1024 * 1024 // 100MB 最大内存使用量
@@ -736,6 +745,7 @@ export function useChatLogic() {
736
745
  const showScrollButton = ref<boolean>(false)
737
746
  const isUserScrolling = ref<boolean>(false)
738
747
  const isSending = ref<boolean>(false)
748
+ const isLoadingMore = ref<boolean>(false)
739
749
 
740
750
  // 拖拽相关状态
741
751
  const draggingChannel = ref<string>('')
@@ -1113,9 +1123,13 @@ export function useChatLogic() {
1113
1123
  mobileView.value = 'messages'
1114
1124
  }
1115
1125
 
1116
- // 先获取历史消息,然后再滚动到底部
1126
+ // 清除该频道的分页状态
1127
+ const channelKey = `${selectedBot.value}:${channelId}`
1128
+ delete channelPagination.value[channelKey]
1129
+
1130
+ // 先获取历史消息(只加载最新的50条)
1117
1131
  if (selectedBot.value) {
1118
- await loadHistoryMessages(selectedBot.value, channelId)
1132
+ await loadHistoryMessages(selectedBot.value, channelId, 50, 0)
1119
1133
  }
1120
1134
 
1121
1135
  nextTick(() => {
@@ -1366,6 +1380,59 @@ export function useChatLogic() {
1366
1380
  // 滚动到底部时,重置滚动状态
1367
1381
  isUserScrolling.value = false
1368
1382
  }
1383
+
1384
+ // 检查是否滚动到顶部,如果是则加载更多消息
1385
+ if (scrollTop <= 10 && selectedBot.value && selectedChannel.value) {
1386
+ loadMoreMessages()
1387
+ }
1388
+ }
1389
+ }
1390
+
1391
+ // 加载更多消息的函数
1392
+ async function loadMoreMessages() {
1393
+ if (!selectedBot.value || !selectedChannel.value) return
1394
+
1395
+ const channelKey = `${selectedBot.value}:${selectedChannel.value}`
1396
+
1397
+ // 检查是否正在加载或没有更多消息
1398
+ const pagination = channelPagination.value[channelKey]
1399
+ if (isLoadingMore.value || (pagination && !pagination.hasMore)) return
1400
+
1401
+ // 更新加载状态
1402
+ if (!channelPagination.value[channelKey]) {
1403
+ channelPagination.value[channelKey] = {
1404
+ offset: 0,
1405
+ hasMore: true,
1406
+ loading: false
1407
+ }
1408
+ }
1409
+
1410
+ // 设置为加载中状态
1411
+ isLoadingMore.value = true
1412
+ channelPagination.value[channelKey].loading = true
1413
+
1414
+ try {
1415
+ // 获取当前offset
1416
+ const currentOffset = pagination?.offset || 0
1417
+
1418
+ // 加载下一批消息(50条)
1419
+ const result = await loadHistoryMessages(selectedBot.value, selectedChannel.value, 50, currentOffset)
1420
+
1421
+ if (result) {
1422
+ // 更新分页状态已在loadHistoryMessages中处理
1423
+ } else {
1424
+ // 加载失败,重置加载状态
1425
+ channelPagination.value[channelKey].loading = false
1426
+ }
1427
+ } catch (error) {
1428
+ console.error('加载更多消息失败:', error)
1429
+ // 加载失败,重置加载状态
1430
+ if (channelPagination.value[channelKey]) {
1431
+ channelPagination.value[channelKey].loading = false
1432
+ }
1433
+ } finally {
1434
+ // 重置加载状态
1435
+ isLoadingMore.value = false
1369
1436
  }
1370
1437
  }
1371
1438
 
@@ -2197,102 +2264,177 @@ export function useChatLogic() {
2197
2264
 
2198
2265
  // 图片缓存管理函数
2199
2266
  async function getCachedImageUrl(channelKey: string, originalUrl: string): Promise<string | null> {
2267
+ // 检查是否正在加载中,如果是则等待加载完成
2268
+ if (loadingImages.has(originalUrl)) {
2269
+ return loadingImages.get(originalUrl) || null
2270
+ }
2271
+
2200
2272
  // 首先检查内存中的blob URL
2201
2273
  const existingBlobUrl = imageBlobUrls.value[originalUrl]
2202
2274
  if (existingBlobUrl) {
2203
2275
  return existingBlobUrl
2204
2276
  }
2205
2277
 
2206
- // 从IndexedDB获取
2207
- const cacheItem = await getImageFromDB(originalUrl)
2208
- if (!cacheItem) return null
2278
+ // 使用立即执行的异步函数来处理加载过程
2279
+ const loadingPromise = (async () => {
2280
+ try {
2281
+ // 再次检查内存中的blob URL(防止在创建Promise期间其他地方已经缓存了)
2282
+ const cachedBlobUrl = imageBlobUrls.value[originalUrl]
2283
+ if (cachedBlobUrl) {
2284
+ return cachedBlobUrl
2285
+ }
2286
+
2287
+ // 从IndexedDB获取
2288
+ const cacheItem = await getImageFromDB(originalUrl)
2289
+ if (!cacheItem) {
2290
+ return null
2291
+ }
2292
+
2293
+ // 检查内存使用情况
2294
+ checkAndCleanupMemory()
2295
+
2296
+ // 创建blob URL并缓存到内存
2297
+ const blobUrl = URL.createObjectURL(cacheItem.blob)
2298
+ imageBlobUrls.value[originalUrl] = blobUrl
2209
2299
 
2210
- // 检查内存使用情况
2211
- checkAndCleanupMemory()
2300
+ // 更新内存使用量
2301
+ updateMemoryUsage(estimateBlobSize(cacheItem.blob))
2212
2302
 
2213
- // 创建blob URL并缓存到内存
2214
- const blobUrl = URL.createObjectURL(cacheItem.blob)
2215
- imageBlobUrls.value[originalUrl] = blobUrl
2303
+ // 更新访问时间
2304
+ cacheItem.timestamp = Date.now()
2305
+ await saveImageToDB(cacheItem)
2216
2306
 
2217
- // 更新内存使用量
2218
- updateMemoryUsage(estimateBlobSize(cacheItem.blob))
2307
+ return blobUrl
2308
+ } catch (error) {
2309
+ console.error('获取缓存图片失败:', error)
2310
+ return null
2311
+ } finally {
2312
+ // 加载完成后从loadingImages中移除
2313
+ loadingImages.delete(originalUrl)
2314
+ }
2315
+ })()
2219
2316
 
2220
- // 更新访问时间
2221
- cacheItem.timestamp = Date.now()
2222
- await saveImageToDB(cacheItem)
2317
+ // 立即添加到loadingImages中,防止并发请求
2318
+ loadingImages.set(originalUrl, loadingPromise)
2223
2319
 
2224
- return blobUrl
2320
+ // 等待加载完成并返回结果
2321
+ return loadingPromise
2225
2322
  }
2226
2323
 
2227
2324
  async function cacheImage(channelKey: string, originalUrl: string): Promise<string | null> {
2228
- try {
2229
- // 检查是否已经缓存
2230
- const cached = await getCachedImageUrl(channelKey, originalUrl)
2231
- if (cached) {
2232
- return cached
2233
- }
2325
+ // 检查是否正在加载中,如果是则等待加载完成
2326
+ if (loadingImages.has(originalUrl)) {
2327
+ return loadingImages.get(originalUrl) || null
2328
+ }
2234
2329
 
2235
- // 获取图片数据
2236
- const result = await (send as any)('fetch-image', { url: originalUrl })
2330
+ // 首先检查内存中的blob URL
2331
+ const existingBlobUrl = imageBlobUrls.value[originalUrl]
2332
+ if (existingBlobUrl) {
2333
+ return existingBlobUrl
2334
+ }
2237
2335
 
2238
- if (!result.success) {
2239
- console.error('获取图片失败:', result.error)
2240
- return null
2241
- }
2336
+ // 使用立即执行的异步函数来处理加载过程
2337
+ const loadingPromise = (async () => {
2338
+ try {
2339
+ // 再次检查内存中的blob URL(防止在创建Promise期间其他地方已经缓存了)
2340
+ const cachedBlobUrl = imageBlobUrls.value[originalUrl]
2341
+ if (cachedBlobUrl) {
2342
+ return cachedBlobUrl
2343
+ }
2242
2344
 
2243
- // 将base64转换为blob
2244
- const base64Data = result.base64
2245
- const contentType = result.contentType || 'image/jpeg'
2345
+ // 从IndexedDB获取
2346
+ const cachedItem = await getImageFromDB(originalUrl)
2347
+ if (cachedItem) {
2348
+ // 检查内存使用情况
2349
+ checkAndCleanupMemory()
2246
2350
 
2247
- // 解码base64
2248
- const byteCharacters = atob(base64Data)
2249
- const byteNumbers = new Array(byteCharacters.length)
2250
- for (let i = 0; i < byteCharacters.length; i++) {
2251
- byteNumbers[i] = byteCharacters.charCodeAt(i)
2252
- }
2253
- const byteArray = new Uint8Array(byteNumbers)
2351
+ // 创建blob URL并缓存到内存
2352
+ const blobUrl = URL.createObjectURL(cachedItem.blob)
2353
+ imageBlobUrls.value[originalUrl] = blobUrl
2254
2354
 
2255
- // 保持原始MIME类型,特别是对于GIF
2256
- const blob = new Blob([byteArray], { type: contentType })
2355
+ // 更新内存使用量
2356
+ updateMemoryUsage(estimateBlobSize(cachedItem.blob))
2257
2357
 
2258
- // 检查blob大小
2259
- if (blob.size > MAX_IMAGE_SIZE) {
2260
- console.warn(`图片过大,跳过缓存: ${(blob.size / 1024 / 1024).toFixed(2)}MB`)
2261
- return null
2262
- }
2358
+ // 更新访问时间
2359
+ cachedItem.timestamp = Date.now()
2360
+ await saveImageToDB(cachedItem)
2263
2361
 
2264
- // 创建缓存项
2265
- const cacheItem: ImageCacheItem = {
2266
- url: originalUrl,
2267
- blob: blob,
2268
- timestamp: Date.now(),
2269
- size: blob.size,
2270
- channelKey: channelKey
2271
- }
2362
+ return blobUrl
2363
+ }
2272
2364
 
2273
- // 保存到IndexedDB
2274
- const saved = await saveImageToDB(cacheItem)
2275
- if (!saved) {
2276
- console.error('保存图片到IndexedDB失败')
2277
- return null
2278
- }
2365
+ // 获取图片数据
2366
+ const result = await (send as any)('fetch-image', { url: originalUrl })
2279
2367
 
2280
- // 检查内存使用情况
2281
- checkAndCleanupMemory()
2368
+ if (!result.success) {
2369
+ return null
2370
+ }
2282
2371
 
2283
- // 创建blob URL并缓存到内存
2284
- const blobUrl = URL.createObjectURL(blob)
2285
- imageBlobUrls.value[originalUrl] = blobUrl
2372
+ // 将base64转换为blob
2373
+ const base64Data = result.base64
2374
+ const contentType = result.contentType || 'image/jpeg'
2286
2375
 
2287
- // 更新内存使用量
2288
- updateMemoryUsage(estimateBlobSize(blob))
2376
+ // 解码base64
2377
+ const byteCharacters = atob(base64Data)
2378
+ const byteNumbers = new Array(byteCharacters.length)
2379
+ for (let i = 0; i < byteCharacters.length; i++) {
2380
+ byteNumbers[i] = byteCharacters.charCodeAt(i)
2381
+ }
2382
+ const byteArray = new Uint8Array(byteNumbers)
2289
2383
 
2290
- return blobUrl
2384
+ // 保持原始MIME类型,特别是对于GIF
2385
+ const blob = new Blob([byteArray], { type: contentType })
2291
2386
 
2292
- } catch (error) {
2293
- console.error('缓存图片失败:', error)
2294
- return null
2295
- }
2387
+ // 检查blob大小
2388
+ if (blob.size > MAX_IMAGE_SIZE) {
2389
+ return null
2390
+ }
2391
+
2392
+ // 再次检查内存中是否已经存在(防止并发请求)
2393
+ const concurrentBlobUrl = imageBlobUrls.value[originalUrl]
2394
+ if (concurrentBlobUrl) {
2395
+ return concurrentBlobUrl
2396
+ }
2397
+
2398
+ // 创建缓存项
2399
+ const cacheItem: ImageCacheItem = {
2400
+ url: originalUrl,
2401
+ blob: blob,
2402
+ timestamp: Date.now(),
2403
+ size: blob.size,
2404
+ channelKey: channelKey
2405
+ }
2406
+
2407
+ // 保存到IndexedDB
2408
+ const saved = await saveImageToDB(cacheItem)
2409
+ if (!saved) {
2410
+ return null
2411
+ }
2412
+
2413
+ // 检查内存使用情况
2414
+ checkAndCleanupMemory()
2415
+
2416
+ // 创建blob URL并缓存到内存
2417
+ const blobUrl = URL.createObjectURL(blob)
2418
+ imageBlobUrls.value[originalUrl] = blobUrl
2419
+
2420
+ // 更新内存使用量
2421
+ updateMemoryUsage(estimateBlobSize(blob))
2422
+
2423
+ return blobUrl
2424
+ } catch (error) {
2425
+ console.error('缓存图片失败:', error)
2426
+ return null
2427
+ } finally {
2428
+ // 加载完成后从loadingImages中移除
2429
+ loadingImages.delete(originalUrl)
2430
+ }
2431
+ })()
2432
+
2433
+ // 立即添加到loadingImages中,防止并发请求
2434
+ loadingImages.set(originalUrl, loadingPromise)
2435
+
2436
+ // 等待加载完成并返回结果
2437
+ return loadingPromise
2296
2438
  }
2297
2439
 
2298
2440
  // 清理频道的所有图片缓存
@@ -2808,13 +2950,21 @@ export function useChatLogic() {
2808
2950
  }
2809
2951
 
2810
2952
  // 获取历史消息
2811
- async function loadHistoryMessages(botId: string, channelId: string) {
2953
+ async function loadHistoryMessages(botId: string, channelId: string, limit?: number, offset?: number) {
2812
2954
  try {
2813
2955
 
2814
- const result = await (send as any)('get-history-messages', {
2956
+ const requestData: any = {
2815
2957
  selfId: botId,
2816
2958
  channelId: channelId
2817
- })
2959
+ }
2960
+
2961
+ // 如果提供了分页参数,则添加到请求中
2962
+ if (limit !== undefined) {
2963
+ requestData.limit = limit
2964
+ requestData.offset = offset || 0
2965
+ }
2966
+
2967
+ const result = await (send as any)('get-history-messages', requestData)
2818
2968
 
2819
2969
  if (result.success && result.messages) {
2820
2970
  const channelKey = `${botId}:${channelId}`
@@ -2834,14 +2984,51 @@ export function useChatLogic() {
2834
2984
  quote: msg.quote
2835
2985
  }))
2836
2986
 
2837
- // 按时间戳排序
2838
- messages.sort((a, b) => a.timestamp - b.timestamp)
2987
+ // 确保offset有默认值
2988
+ const actualOffset = offset || 0
2839
2989
 
2840
- // 设置历史消息
2841
- chatData.value.messages[channelKey] = messages
2990
+ // 如果是分页加载,需要合并到现有消息中
2991
+ if (limit !== undefined) {
2992
+ // 按时间戳排序
2993
+ messages.sort((a, b) => a.timestamp - b.timestamp)
2994
+
2995
+ // 如果是第一页(offset为0),则替换现有消息
2996
+ if (offset === 0) {
2997
+ chatData.value.messages[channelKey] = messages
2998
+ // 初始化分页状态
2999
+ channelPagination.value[channelKey] = {
3000
+ offset: messages.length,
3001
+ hasMore: messages.length >= limit && result.total > messages.length,
3002
+ loading: false
3003
+ }
3004
+ } else {
3005
+ // 否则是加载更多,需要合并到现有消息的开头(因为是历史消息)
3006
+ const existingMessages = chatData.value.messages[channelKey] || []
3007
+ chatData.value.messages[channelKey] = [...messages, ...existingMessages]
3008
+ // 更新分页状态
3009
+ const actualOffset = offset || 0
3010
+ channelPagination.value[channelKey] = {
3011
+ offset: actualOffset + messages.length,
3012
+ hasMore: messages.length >= limit && result.total > (actualOffset + messages.length),
3013
+ loading: false
3014
+ }
3015
+ }
3016
+ } else {
3017
+ // 按时间戳排序
3018
+ messages.sort((a, b) => a.timestamp - b.timestamp)
3019
+
3020
+ // 设置历史消息
3021
+ chatData.value.messages[channelKey] = messages
3022
+ // 初始化分页状态
3023
+ channelPagination.value[channelKey] = {
3024
+ offset: messages.length,
3025
+ hasMore: false, // 不分页时没有更多消息
3026
+ loading: false
3027
+ }
3028
+ }
2842
3029
 
2843
3030
  // 更新频道消息数量缓存
2844
- channelMessageCounts.value[channelKey] = messages.length
3031
+ channelMessageCounts.value[channelKey] = result.total || messages.length
2845
3032
 
2846
3033
  // 触发响应式更新
2847
3034
  chatData.value = { ...chatData.value }
@@ -3120,6 +3307,7 @@ export function useChatLogic() {
3120
3307
  // 响应式数据
3121
3308
  chatData,
3122
3309
  channelMessageCounts,
3310
+ channelPagination,
3123
3311
  pluginConfig,
3124
3312
  selectedBot,
3125
3313
  selectedChannel,
@@ -3140,6 +3328,7 @@ export function useChatLogic() {
3140
3328
  showScrollButton,
3141
3329
  isUserScrolling,
3142
3330
  isSending,
3331
+ isLoadingMore,
3143
3332
  draggingChannel,
3144
3333
  dragStartPos,
3145
3334
  dragCurrentPos,
@@ -3204,6 +3393,7 @@ export function useChatLogic() {
3204
3393
  handleTouchMove,
3205
3394
  handleTouchEnd,
3206
3395
  handleInputFocus,
3396
+ loadMoreMessages,
3207
3397
 
3208
3398
  // 图片缓存相关
3209
3399
  getCachedImageUrl,
@@ -66,6 +66,12 @@
66
66
  <div v-else class="message-content">
67
67
  <!-- 消息历史 -->
68
68
  <div class="message-history" ref="messageHistory">
69
+ <!-- 加载更多指示器 -->
70
+ <div v-if="isLoadingMore" class="loading-more-indicator">
71
+ <div class="loading-spinner"></div>
72
+ <span>加载更多消息中...</span>
73
+ </div>
74
+
69
75
  <div v-for="message in currentMessages" :key="message.id"
70
76
  :class="['message-item', { 'bot-message': message.isBot }]">
71
77
  <div class="message-avatar">
@@ -245,6 +251,7 @@ const {
245
251
  showScrollButton,
246
252
  isUserScrolling,
247
253
  isSending,
254
+ isLoadingMore,
248
255
  draggingChannel,
249
256
  dragStartPos,
250
257
  dragCurrentPos,
@@ -1918,3 +1918,27 @@ body.dragging-bubble-global {
1918
1918
  background-color: rgba(255, 255, 255, .7)
1919
1919
  }
1920
1920
  }
1921
+
1922
+ .loading-more-indicator {
1923
+ display: flex;
1924
+ align-items: center;
1925
+ justify-content: center;
1926
+ padding: 12px;
1927
+ color: #6c757d;
1928
+ font-size: 14px;
1929
+ }
1930
+
1931
+ .loading-spinner {
1932
+ width: 20px;
1933
+ height: 20px;
1934
+ border: 2px solid #f3f3f3;
1935
+ border-top: 2px solid #2196f3;
1936
+ border-radius: 50%;
1937
+ animation: spin 1s linear infinite;
1938
+ margin-right: 8px;
1939
+ }
1940
+
1941
+ @keyframes spin {
1942
+ 0% { transform: rotate(0deg); }
1943
+ 100% { transform: rotate(360deg); }
1944
+ }
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
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=12*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=`
1
+ import{defineComponent as Ce,ref as g,onMounted as it,h as m,computed as te,watch as Tt,nextTick as me,onUnmounted as ba,createElementBlock as C,openBlock as w,unref as c,normalizeStyle as ut,normalizeClass as re,createCommentVNode as B,createElementVNode as f,Fragment as ae,renderList as Le,createBlock as Fe,toDisplayString as D,withDirectives as Mt,createTextVNode as dt,vShow as ka,withModifiers as qt,withKeys as Sa,isRef as Ba,vModelText as $a,resolveComponent as Da}from"vue";import{receive as ft,send as z,icons as _a}from"@koishijs/client";function La(){function ne(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=g("loading"),a=g(e.src),n=g(""),o=async()=>{try{t.value="loading";const i=await ot(e.channelKey,e.src);if(i){a.value=i,t.value="loaded";return}const l=new Image;l.crossOrigin="anonymous",l.referrerPolicy="no-referrer",l.draggable=false;const d=new Promise((p,I)=>{l.onload=()=>p(),l.onerror=()=>I(new Error("Direct load failed")),l.src=e.src}),v=new Promise((p,I)=>{setTimeout(()=>I(new Error("Timeout")),3e3)});try{await Promise.race([d,v]),a.value=e.src,t.value="loaded",Ie(e.channelKey,e.src).catch(p=>{console.warn("异步缓存头像失败:",p)})}catch{await s()}}catch(i){console.error("头像加载失败:",i),t.value="error",n.value="头像加载失败"}},s=async()=>{try{t.value="caching";const i=await Ie(e.channelKey,e.src);if(i)a.value=i,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(i){console.error("缓存系统加载头像失败:",i),t.value="error",n.value=(i==null?void 0:i.message)||"缓存加载失败"}};return it(()=>{o()}),()=>{switch(t.value){case"loading":case"caching":return m("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return m("img",{src:a.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return m("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return m("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=g("loading"),a=g(e.src),n=g(""),o=g(null),s=async()=>{try{t.value="loading";const l=await ot(e.channelKey,e.src);if(l){a.value=l,t.value="loaded";return}if(ne(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 v=new Promise((I,q)=>{d.onload=()=>I(),d.onerror=()=>q(new Error("Direct load failed")),d.src=e.src}),p=new Promise((I,q)=>{setTimeout(()=>q(new Error("Timeout")),3e3)});try{await Promise.race([v,p]),a.value=e.src,t.value="loaded",Ie(e.channelKey,e.src).catch(I=>{console.warn("异步缓存图片失败:",I)})}catch{await i()}}catch(l){console.error("图片加载失败:",l),t.value="error",n.value="图片加载失败"}},i=async()=>{try{t.value="caching";const l=await Ie(e.channelKey,e.src);if(l)a.value=l,t.value="loaded";else throw new Error("缓存系统加载失败")}catch(l){console.error("缓存系统加载图片失败:",l),t.value="error",n.value=(l==null?void 0:l.message)||"缓存加载失败"}};return it(()=>{s()}),()=>{switch(t.value){case"loading":return m("div",{class:"message-image-loading"},"加载中...");case"caching":return m("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return m("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 m("div",{class:"message-image-error"},["图片加载失败",m("br"),m("small",e.filename||e.alt||"未知图片"),m("br"),m("small",{style:"color: #ff9800;"},n.value)]);default:return m("div",{class:"message-image-error"},"未知状态")}}}}),ve=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?m("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"?m("div",{class:"message-json-error"},[m("span",{class:"json-error-text"},a.error),m("details",{class:"json-raw-data"},[m("summary","查看原始数据"),m("pre",{class:"json-raw-content"},e.data)])]):m("div",{class:"message-json-raw"},[m("div",{class:"json-label"},"[JSON数据]"),m("details",{class:"json-raw-data"},[m("summary","查看详情"),m("pre",{class:"json-raw-content"},JSON.stringify(a.data,null,2))])])}}),E=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=g(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 I,q;const v=((I=d.attrs)==null?void 0:I.nickname)||"用户";let p="";if(d.children&&d.children.length>0){const H=d.children[0];H.type==="text"?(p=(((q=H.attrs)==null?void 0:q.content)||"").substring(0,20),p.length>15&&(p+="...")):H.type==="img"?p="[图片]":H.type==="video"?p="[视频]":p=`[${H.type}]`}return`${v}:${p}`}),messageCount:i}},o=(s,i)=>{var v,p,I;const l=((v=s.attrs)==null?void 0:v.nickname)||"用户",d=((p=s.attrs)==null?void 0:p.userId)||"unknown";return m("div",{key:i,class:"forwarded-message-item"},[m("div",{class:"forwarded-message-header"},[m("span",{class:"forwarded-message-nickname"},l),m("span",{class:"forwarded-message-userid"},`(${d})`)]),m("div",{class:"forwarded-message-content"},((I=s.children)==null?void 0:I.map((q,H)=>m(be,{key:H,element:q,channelKey:e.channelKey})))||[])])};return()=>{var l;const{previews:s,messageCount:i}=n();return m("div",{class:"forward-message-container"},[m("div",{class:"forward-message-preview",onClick:a},[m("div",{class:"forward-message-title"},"聊天记录"),...s.map((d,v)=>m("div",{key:v,class:"forward-message-preview-item"},d)),m("div",{class:"forward-message-footer"},[m("span",{class:"forward-message-count"},`查看${i}条转发消息`),m("span",{class:"forward-message-toggle"},t.value?"▲":"▼")])]),t.value&&m("div",{class:"forward-message-expanded"},((l=e.element.children)==null?void 0:l.filter(d=>d.type==="message").map((d,v)=>o(d,v)))||[])])}}}),be=Ce({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const t=a=>{var n,o,s,i,l,d;switch(a.type){case"text":return m("span",{class:"message-text-content"},a.attrs.content||"");case"forward":return m("span",{class:"message-text-content"},`[转发消息 ${a.attrs.id}]`||"[转发消息]");case"img":case"image":const v=a.attrs.src||a.attrs.url||a.attrs.file;return m("div",{class:"message-image-container"},[m(X,{src:v,alt:a.attrs.summary||"图片",filename:a.attrs.filename||a.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const p=a.attrs.src||a.attrs.url||a.attrs.file;return m("div",{class:"message-image-container"},[m(X,{src:p,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 I=((i=(s=a.children[0])==null?void 0:s.attrs)==null?void 0:i.src)||((d=(l=a.children[0])==null?void 0:l.attrs)==null?void 0:d.url);return m("div",{class:"message-image-container"},[m(X,{src:I,alt:a.attrs.name||a.attrs.id||"[表情]",filename:a.attrs.name||a.attrs.id||"[表情]",channelKey:e.channelKey})])}else return m("span",{class:"message-text-content"},`[${a.attrs.name||a.attrs.id}]`||"[表情]");case"at":return m("span",{class:"message-at",title:a.attrs.name},`${a.attrs.name||a.attrs.id}`);case"json":return m("div",{class:"message-image-container"},[m(ve,{data:a.attrs.data||"",channelKey:e.channelKey})]);case"p":if(a.children&&a.children.length>0){const I=a.children.map((q,H)=>m(be,{key:H,element:q,channelKey:e.channelKey}));return m("div",{class:"message-paragraph"},I)}else return m("div",{class:"message-paragraph"},"");case"figure":return m(E,{element:a,channelKey:e.channelKey});default:return m("span",{class:"message-unknown",title:`未知消息类型: ${a.type}`},a.attrs.content||`[${a.type}]`)}};return()=>t(e.element)}}),u=g({bots:{},channels:{},messages:{}}),U=g({}),K=g({}),ie=g({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=g({}),Y=new Map,Te=100*1024*1024,ge=50;let ye=0,x=null;const He="ChatImageCache",Me=2,$="images",_=50*1024*1024,Xe=100,ue=500,qe=12*1024*1024,Ye=.8,Ge=60*1e3;let j=0,V=0,Ve=0;const y=g(""),S=g(""),ke=g(""),W=g([]),de=g(false),Ke=g(),P=g(false),J=g("bots"),N=g(null),se=g(null),Se=g(false),G=g({show:false,text:""}),L=g(),fe=g(),Be=g(false),oe=g(false),pe=g(false),we=g(false),le=g(""),R=g({x:0,y:0}),A=g({x:0,y:0}),$e=g({x:0,y:0}),De=g({x:0,y:0}),F=80,_e=g(0),O=g(null),ee=g(false),k=g(null),Z=g({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),h=g(new Set),r=g(new Set),M=te(()=>Object.values(u.value.bots).sort((t,a)=>{const n=h.value.has(t.selfId),o=h.value.has(a.selfId);return n&&!o?-1:!n&&o?1:0})),je=te(()=>!y.value||!u.value.channels[y.value]?[]:Object.values(u.value.channels[y.value]).sort((t,a)=>{const n=r.value.has(`${y.value}:${t.id}`),o=r.value.has(`${y.value}:${a.id}`);return n&&!o?-1:!n&&o?1:0})),ht=te(()=>{if(!y.value||!S.value)return[];const e=`${y.value}:${S.value}`,t=u.value.messages[e]||[];return t.filter(a=>a.quote),t}),jt=te(()=>{var t;if(!y.value||!S.value)return"";const e=u.value.channels[y.value];return((t=e==null?void 0:e[S.value])==null?void 0:t.name)||""}),Pt=te(()=>!y.value||!S.value?"":`${y.value}:${S.value}`),mt=te(()=>y.value&&S.value&&(ke.value.trim()||W.value.length>0)&&!pe.value),At=te(()=>y.value&&S.value&&!pe.value),Ut=te(()=>{if(!P.value)return"";switch(J.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),Rt=te(()=>P.value?"输入消息...(屏幕左滑返回)":"输入消息..."),zt=te(()=>({}));function Ze(e){return e.size||0}function Pe(e){ye+=e,ie.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(ye/1024/1024).toFixed(2)}MB`)}function vt(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)}),Pe(-n)}function We(){Object.keys(b.value).length>ge&&vt(Math.floor(ge*.7)),ye>Te&&vt(Math.floor(ge*.5))}function Ot(e){y.value=e,S.value="",lt(),P.value&&(J.value="channels")}function Nt(e,t){if(e.preventDefault(),e.stopPropagation(),Z.value.show&&Z.value.type==="bot"&&Z.value.targetId===t){Q();return}Qe(e,"bot",t)}function Ft(e,t){if(e.preventDefault(),e.stopPropagation(),Z.value.show&&Z.value.type==="channel"&&Z.value.targetId===t){Q();return}Qe(e,"channel",t)}function Qe(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),Z.value={show:true,x:s,y:i,type:t,targetId:a,isSecondClick:false},document.addEventListener("click",Q,{once:true}),document.addEventListener("keydown",Ee)}function Q(){Z.value.show=false,document.removeEventListener("click",Q),document.removeEventListener("keydown",Ee)}function Ee(e){e.key==="Escape"&&Z.value.show&&Q()}async function Ht(e){h.value.has(e)?h.value.delete(e):h.value.add(e),await z("set-pinned-bots",{pinnedBots:Array.from(h.value)}),Q()}async function Xt(e){const t=`${y.value}:${e}`;r.value.has(t)?r.value.delete(t):r.value.add(t),await z("set-pinned-channels",{pinnedChannels:Array.from(r.value)}),Q()}async function Yt(e){try{const t=await z("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 Ne(n);delete u.value.bots[e],delete u.value.channels[e],y.value===e&&(y.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")}Q()}async function Vt(e){try{const t=await z("delete-channel-data",{selfId:y.value,channelId:e});if(t.success){const a=`${y.value}:${e}`;delete u.value.messages[a],delete U.value[a],u.value.channels[y.value]&&delete u.value.channels[y.value][e],await Ne(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")}Q()}async function Wt(e){S.value=e,oe.value=false,lt(),P.value&&(J.value="messages");const t=`${y.value}:${e}`;delete K.value[t],y.value&&await rt(y.value,e,50,0),me(()=>{he(),!P.value&&fe.value&&fe.value.focus()})}async function Jt(){if(!mt.value)return;const e=ke.value.trim();if(!e&&W.value.length===0)return;pe.value=true;const t=[...W.value];try{const a=await z("send-message",{selfId:y.value,channelId:S.value,content:e,images:t.map(n=>({tempId:n.tempId,filename:n.filename}))});if(a.success){if(ke.value="",t.forEach(n=>{URL.revokeObjectURL(n.preview)}),W.value=[],de.value=false,a.tempImageIds&&a.tempImageIds.length>0)try{await z("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{pe.value=false}}function Gt(){de.value=!de.value}function Zt(){Ke.value&&Ke.value.click(),de.value=false}async function Qt(e){const t=e.target,a=t.files;if(!(!a||a.length===0)){for(const n of Array.from(a))await et(n);t.value=""}}async function Et(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}`,l=new File([o],i,{type:n.type,lastModified:Date.now()});await et(l)}}}}async function et(e){try{if(e.size>10*1024*1024){T("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){T("请选择图片文件","error");return}const t=await gt(e),a=URL.createObjectURL(e),n=await z("upload-image",{file:t,filename:e.name,mimeType:e.type,isGif:e.type==="image/gif"});n.success?W.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 ea(e){try{const t=W.value.findIndex(a=>a.tempId===e);if(t!==-1){const a=W.value[t];URL.revokeObjectURL(a.preview),W.value.splice(t,1)}await z("delete-temp-image",{tempId:e})}catch(t){console.error("删除图片失败:",t)}}function gt(e){return new Promise((t,a)=>{const n=new FileReader;n.onload=()=>t(n.result),n.onerror=a,n.readAsDataURL(e)})}function tt(e){const t=e.target;t.closest(".input-actions")||(de.value=false),t.closest(".context-menu")||Q()}function ta(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function aa(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function he(){L.value&&(L.value.scrollTop=L.value.scrollHeight,Be.value=false,oe.value=false)}function Ae(){if(L.value){const{scrollTop:e,scrollHeight:t,clientHeight:a}=L.value,o=t-(e+a)<=50,s=!o;Be.value=s,o?oe.value=false:oe.value=true,e<=10&&y.value&&S.value&&yt()}}async function yt(){if(!y.value||!S.value)return;const e=`${y.value}:${S.value}`,t=K.value[e];if(!(we.value||t&&!t.hasMore)){K.value[e]||(K.value[e]={offset:0,hasMore:true,loading:false}),we.value=true,K.value[e].loading=true;try{const a=(t==null?void 0:t.offset)||0;await rt(y.value,S.value,50,a)||(K.value[e].loading=false)}catch(a){console.error("加载更多消息失败:",a),K.value[e]&&(K.value[e].loading=false)}finally{we.value=false}}}function Ue(){if(!L.value)return true;const{scrollTop:e,scrollHeight:t,clientHeight:a}=L.value;return t-(e+a)<=200}function pt(e){var n;if(!y.value)return 0;const t=`${y.value}:${e}`,a=U.value[t];return a!==void 0?a:((n=u.value.messages[t])==null?void 0:n.length)||0}function na(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;_e.value=Date.now(),R.value={x:a,y:n},A.value={x:a,y:n},ee.value=false;const s=e.target.getBoundingClientRect();$e.value={x:s.left,y:s.top},De.value={x:a-s.left,y:n-s.top},O.value=window.setTimeout(()=>{if(_e.value>0){ee.value=true,le.value=t;const i=e.target,l=i.cloneNode(true);l.classList.add("dragging-clone"),l.style.position="fixed",l.style.zIndex="1000",l.style.pointerEvents="none";const d=i.getBoundingClientRect();l.style.left=`${d.left}px`,l.style.top=`${d.top}px`,l.style.width=`${d.width}px`,l.style.height=`${d.height}px`,document.body.appendChild(l),k.value=l,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),It(R.value.x,R.value.y)}},60),document.addEventListener("mousemove",Re),document.addEventListener("mouseup",ze),document.addEventListener("touchmove",Re),document.addEventListener("touchend",ze)}function Re(e){if(!ee.value||!k.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-R.value.x,o=A.value.y-R.value.y,s=Math.sqrt(n*n+o*o),i=Math.max(.3,1-s/(F*2)),l=Math.max(.8,1-s/(F*3)),d=s>F,v=A.value.x-De.value.x,p=A.value.y-De.value.y;k.value.style.left=`${v}px`,k.value.style.top=`${p}px`,k.value.style.transform=`scale(${l})`,k.value.style.opacity=`${i}`,k.value.style.backgroundColor=d?"#f44336":"#2196f3",k.value.style.boxShadow=d?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",d?k.value.classList.add("will-delete"):k.value.classList.remove("will-delete")}function ze(e){if(O.value&&(clearTimeout(O.value),O.value=null),O.value&&(clearTimeout(O.value),O.value=null),!ee.value||!le.value){Oe();return}const t=le.value;if(Math.sqrt(Math.pow(A.value.x-R.value.x,2)+Math.pow(A.value.y-R.value.y,2))>F)wt(t),Oe();else if(k.value){k.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();k.value.style.left=`${o.left}px`,k.value.style.top=`${o.top}px`,k.value.style.transform="scale(1)",k.value.style.opacity="1",k.value.style.backgroundColor="#2196f3",k.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{Oe()},300)}else Oe()}function Oe(){O.value&&(clearTimeout(O.value),O.value=null),le.value="",R.value={x:0,y:0},A.value={x:0,y:0},$e.value={x:0,y:0},_e.value=0,ee.value=false,document.removeEventListener("mousemove",Re),document.removeEventListener("mouseup",ze),document.removeEventListener("touchmove",Re),document.removeEventListener("touchend",ze),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),k.value&&k.value.parentNode&&(k.value.parentNode.removeChild(k.value),k.value=null),xt()}function sa(e){return le.value===e&&ee.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function oa(e){if(le.value!==e)return 0;const t=A.value.x-R.value.x,a=A.value.y-R.value.y;return Math.sqrt(t*t+a*a)}async function wt(e){if(y.value)try{const t=`${y.value}:${e}`,a=pt(e),n=ie.value.keepMessagesOnClear;if(n>0&&a<=n){T("当前消息还很少诶~ 无需清理","success");return}const o=await z("clear-channel-history",{selfId:y.value,channelId:e});if(o.success)if(o.clearedCount&&o.clearedCount>0){if(u.value.messages[t]){const i=[...u.value.messages[t]].sort((l,d)=>l.timestamp-d.timestamp);u.value.messages[t]=i.slice(-o.keptCount)}U.value[t]=o.keptCount,await Ne(t),T(`历史记录已清理,清理了 ${o.clearedCount} 条消息,保留最新 ${o.keptCount} 条`,"success")}else n===0?(u.value.messages[t]&&(u.value.messages[t]=[]),U.value[t]=0,await Ne(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 st,h,computed as E,watch as S
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 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};
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 It(e,t){const a=document.createElement("div");a.className="drag-threshold-circle",a.style.cssText=`
23
+ left: ${e-F}px;
24
+ top: ${t-F}px;
25
+ width: ${F*2}px;
26
+ height: ${F*2}px;
27
+ `,document.body.appendChild(a),window.dragThresholdCircle=a}function xt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function at(){try{if(!x)return false;const e=Date.now();if(e-Ve<Ge)return true;Ve=e;const t=await Ct();j=t.totalSize,V=t.totalImages,console.log("数据库健康检查:",{大小:`${(j/1024/1024).toFixed(2)}MB / ${(_/1024/1024).toFixed(2)}MB`,图片数量:`${V} / ${ue}`,使用率:`${(j/_*100).toFixed(1)}%`});const a=j/_,n=V/ue;return(a>Ye||n>Ye)&&(console.warn("数据库使用率过高,开始自动清理"),await Je()),(a>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await la()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function Ct(){return x?new Promise(e=>{const n=x.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{const o=n.result||[];let s=0;const i={};o.forEach(l=>{s+=l.size||0,i[l.channelKey]=(i[l.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 Je(){try{console.log("开始自动清理...");const e=await bt();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>Xe){s.sort((l,d)=>l.timestamp-d.timestamp);const i=s.slice(0,s.length-Xe);for(const l of i)await st(l.url),a++,n+=l.size||0,b.value[l.url]&&(URL.revokeObjectURL(b.value[l.url]),delete b.value[l.url])}console.log(`自动清理完成: 清理了 ${a} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),V-=a,j-=n}catch(e){console.error("自动清理失败:",e)}}async function la(){try{console.log("开始紧急清理...");const e=await bt();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 st(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`),V=t,j-=o}catch(e){console.error("紧急清理失败:",e)}}async function bt(){return x?new Promise(e=>{const n=x.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function ra(){return new Promise(e=>{try{x&&(x.close(),x=null);const t=indexedDB.deleteDatabase(He);t.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),j=0,V=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 ca(){try{return await kt()?(setTimeout(async()=>{const t=await Ct();console.log("数据库初始状态:",{大小:`${(t.totalSize/1024/1024).toFixed(2)}MB`,图片数量:t.totalImages,频道分布:t.channelStats}),(t.totalSize>_*.9||t.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await Je())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await ra(),await kt())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function kt(){return new Promise(e=>{try{const t=indexedDB.open(He,Me);t.onerror=()=>{console.error("IndexedDB打开失败:",t.error),e(false)},t.onsuccess=()=>{x=t.result,x.onerror=a=>{console.error("IndexedDB运行时错误:",a)},x.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),x==null||x.close(),x=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 St(e){return x?new Promise((t,a)=>{const s=x.transaction([$],"readonly").objectStore($).get(e);s.onsuccess=()=>{t(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),t(null)}}):null}async function nt(e){if(!x)return false;try{return e.size>qe?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(qe/1024/1024).toFixed(2)}MB`),false):(await at(),j+e.size>_&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await Je(),j+e.size>_)?(console.warn("清理后仍会超过限制,跳过此图片"),false):V>=ue&&(console.warn("图片数量已达上限,执行清理"),await Je(),V>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(t=>{const o=x.transaction([$],"readwrite").objectStore($).put(e);o.onsuccess=()=>{j+=e.size,V+=1,t(true)},o.onerror=()=>{console.error("保存图片到IndexedDB失败:",o.error),t(false)}}))}catch(t){return console.error("保存图片时出错:",t),false}}async function st(e){return x?new Promise(t=>{const o=x.transaction([$],"readwrite").objectStore($).delete(e);o.onsuccess=()=>{t(true)},o.onerror=()=>{console.error("从IndexedDB删除图片失败:",o.error),t(false)}}):false}async function ia(e){return x?new Promise(t=>{const s=x.transaction([$],"readonly").objectStore($).index("channelKey").getAll(e);s.onsuccess=()=>{t(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),t([])}}):[]}async function ot(e,t){if(Y.has(t))return Y.get(t)||null;const a=b.value[t];if(a)return a;const n=(async()=>{try{const o=b.value[t];if(o)return o;const s=await St(t);if(!s)return null;We();const i=URL.createObjectURL(s.blob);return b.value[t]=i,Pe(Ze(s.blob)),s.timestamp=Date.now(),await nt(s),i}catch(o){return console.error("获取缓存图片失败:",o),null}finally{Y.delete(t)}})();return Y.set(t,n),n}async function Ie(e,t){if(Y.has(t))return Y.get(t)||null;const a=b.value[t];if(a)return a;const n=(async()=>{try{const o=b.value[t];if(o)return o;const s=await St(t);if(s){We();const xe=URL.createObjectURL(s.blob);return b.value[t]=xe,Pe(Ze(s.blob)),s.timestamp=Date.now(),await nt(s),xe}const i=await z("fetch-image",{url:t});if(!i.success)return null;const l=i.base64,d=i.contentType||"image/jpeg",v=atob(l),p=new Array(v.length);for(let xe=0;xe<v.length;xe++)p[xe]=v.charCodeAt(xe);const I=new Uint8Array(p),q=new Blob([I],{type:d});if(q.size>qe)return null;const H=b.value[t];if(H)return H;const Ca={url:t,blob:q,timestamp:Date.now(),size:q.size,channelKey:e};if(!await nt(Ca))return null;We();const Lt=URL.createObjectURL(q);return b.value[t]=Lt,Pe(Ze(q)),Lt}catch(o){return console.error("缓存图片失败:",o),null}finally{Y.delete(t)}})();return Y.set(t,n),n}async function Ne(e){try{const t=await ia(e);let a=0;for(const n of t)await st(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],a+=n.size||0);a>0&&Pe(-a)}catch(t){console.error("清理频道图片缓存失败:",t)}}function ua(){const e=Object.keys(b.value).length;return{blobCount:e,estimatedMemoryUsage:ye,maxMemoryLimit:Te,maxBlobLimit:ge,memoryUsagePercent:(ye/Te*100).toFixed(1),blobUsagePercent:(e/ge*100).toFixed(1)}}async function da(){return x?new Promise(e=>{const n=x.transaction([$],"readonly").objectStore($).getAll();n.onsuccess=()=>{const o=n.result||[],s=new Set;let i=0;o.forEach(l=>{s.add(l.channelKey),i+=l.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 lt(){y.value&&S.value&&(localStorage.setItem("chat-selected-bot",y.value),localStorage.setItem("chat-selected-channel",S.value))}function Bt(){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]?(y.value=e,S.value=t,true):false}function $t(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(l=>l.id===e.messageId)){const l={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},d=u.value.messages[s];let v=d.length;for(let I=d.length-1;I>=0;I--){if(d[I].timestamp<=e.timestamp){v=I+1;break}I===0&&(v=0)}d.splice(v,0,l),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const p=Ue();me(()=>{setTimeout(()=>{p&&he()},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 l=i.attrs.src||i.attrs.url||i.attrs.file;l&&Ie(s,l).catch(d=>{console.warn("预缓存图片失败:",l,d)})}})}u.value={...u.value}}function fa(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 l=o.length-1;l>=0;l--){if(o[l].timestamp<=e.timestamp){s=l+1;break}l===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=Ue();me(()=>{setTimeout(()=>{i&&he()},10)})}u.value={...u.value}}function ha(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(l=>l.id===e.messageId)){const l={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},d=u.value.messages[s];let v=d.length;for(let I=d.length-1;I>=0;I--){if(d[I].timestamp<=e.timestamp){v=I+1;break}I===0&&(v=0)}d.splice(v,0,l),d.length>100&&(u.value.messages[s]=d.slice(-100)),U.value[s]=d.length;const p=Ue();me(()=>{setTimeout(()=>{p&&he()},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 l=i.attrs.src||i.attrs.url||i.attrs.file;l&&Ie(s,l).catch(d=>{console.warn("预缓存图片失败:",l,d)})}})}u.value={...u.value}}async function ma(){try{const e=await z("get-chat-data");if(e.success&&e.data){const t={};h.value=new Set(e.data.pinnedBots||[]),r.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 va(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function va(){try{const e=await z("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 ga(){try{const e=await z("get-plugin-config");e.success&&e.config?ie.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function rt(e,t,a,n){try{const o={selfId:e,channelId:t};a!==void 0&&(o.limit=a,o.offset=n||0);const s=await z("get-history-messages",o);if(s.success&&s.messages){const i=`${e}:${t}`,l=s.messages.map(v=>({id:v.id,content:v.content,userId:v.userId,username:v.username,avatar:v.avatar,timestamp:v.timestamp,channelId:v.channelId,selfId:v.selfId,elements:v.elements,isBot:v.type==="bot",quote:v.quote})),d=n||0;if(a!==void 0)if(l.sort((v,p)=>v.timestamp-p.timestamp),n===0)u.value.messages[i]=l,K.value[i]={offset:l.length,hasMore:l.length>=a&&s.total>l.length,loading:false};else{const v=u.value.messages[i]||[];u.value.messages[i]=[...l,...v];const p=n||0;K.value[i]={offset:p+l.length,hasMore:l.length>=a&&s.total>p+l.length,loading:false}}else l.sort((v,p)=>v.timestamp-p.timestamp),u.value.messages[i]=l,K.value[i]={offset:l.length,hasMore:false,loading:false};return U.value[i]=s.total||l.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",s.error),false}catch(o){return console.error("获取历史消息时出错:",o),false}}function ya(e){if(!P.value||e.touches.length!==1)return;const t=e.touches[0];N.value={x:t.clientX,y:t.clientY,time:Date.now()},se.value={x:t.clientX,y:t.clientY},Se.value=false}function pa(e){if(!P.value||!N.value||e.touches.length!==1)return;const t=e.touches[0];se.value={x:t.clientX,y:t.clientY};const a=t.clientX-N.value.x,n=t.clientY-N.value.y;if(Math.abs(a)>Math.abs(n)&&Math.abs(a)>30){const o=a>0,s=J.value==="messages"||J.value==="channels";if(o&&s){Se.value=true;const i=Math.min(a,200),l=150;i>l?G.value={show:true,text:"松开返回"}:G.value={show:true,text:`滑动返回 ${Math.round(i/l*100)}%`},e.preventDefault()}else G.value={show:false,text:""}}else G.value={show:false,text:""}}function wa(e){if(!P.value||!N.value)return;const a=Date.now()-N.value.time;if(se.value){const n=se.value.x-N.value.x,o=se.value.y-N.value.y,s=n>150,i=Math.abs(n)>Math.abs(o),l=a<300&&n>80;(s&&i||l)&&Ia()}N.value=null,se.value=null,Se.value=false,G.value={show:false,text:""}}function Ia(){switch(J.value){case"messages":J.value="channels";break;case"channels":J.value="bots",y.value="",S.value="";break}}function ct(){P.value=window.innerWidth<=768}function Dt(){return!oe.value||Ue()}const _t=()=>{P.value&&L.value&&me(()=>{Dt()&&he()})},xa=()=>{P.value&&setTimeout(()=>{L.value&&Dt()&&he()},300)};return Tt(ht,(e,t)=>{t.length===0&&e.length>0&&me(()=>{he()})}),it(async()=>{ct(),window.addEventListener("resize",ct),window.visualViewport&&window.visualViewport.addEventListener("resize",_t),document.addEventListener("click",tt),await ca()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await at()},2e3),setInterval(async()=>{await at()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ga(),await ma(),me(()=>{Bt()});const t=ft("chat-message-event",$t),a=ft("bot-message-sent-event",fa),n=ft("chat-bot-message-event",ha);Tt(S,o=>{o&&me(()=>{L.value&&(L.value.removeEventListener("scroll",Ae),L.value.addEventListener("scroll",Ae),Ae()),!P.value&&fe.value&&fe.value.focus()})},{immediate:true}),setInterval(()=>{We()},2*60*1e3),ba(()=>{window.removeEventListener("resize",ct),window.visualViewport&&window.visualViewport.removeEventListener("resize",_t),document.removeEventListener("click",tt),t&&typeof t=="function"&&t(),a&&typeof a=="function"&&a(),n&&typeof n=="function"&&n(),L.value&&L.value.removeEventListener("scroll",Ae),Object.values(b.value).forEach(o=>{URL.revokeObjectURL(o)}),b.value={},x&&(x.close(),x=null)})}),{AvatarComponent:ce,ImageComponent:X,JsonCardComponent:ve,ForwardMessageComponent:E,MessageElement:be,chatData:u,channelMessageCounts:U,channelPagination:K,pluginConfig:ie,selectedBot:y,selectedChannel:S,inputMessage:ke,imageBlobUrls:b,pinnedBots:h,pinnedChannels:r,uploadedImages:W,showActionMenu:de,isMobile:P,mobileView:J,touchStart:N,touchCurrent:se,isSwipeActive:Se,swipeIndicator:G,messageHistory:L,messageInput:fe,showScrollButton:Be,isUserScrolling:oe,isSending:pe,isLoadingMore:we,draggingChannel:le,dragStartPos:R,dragCurrentPos:A,dragElementInitialPos:$e,dragOffset:De,dragThreshold:F,isDragReady:ee,draggedBubbleElement:k,contextMenu:Z,fileInput:Ke,bots:M,currentChannels:je,currentMessages:ht,currentChannelName:jt,currentChannelKey:Pt,canSendMessage:mt,canInputMessage:At,mobileViewClass:Ut,inputPlaceholder:Rt,chatContainerStyle:zt,selectBot:Ot,selectChannel:Wt,handleBotRightClick:Nt,handleChannelRightClick:Ft,showContextMenu:Qe,hideContextMenu:Q,handleKeyDown:Ee,toggleBotPin:Ht,toggleChannelPin:Xt,deleteBotMessages:Yt,deleteChannelMessages:Vt,sendMessage:Jt,toggleActionMenu:Gt,triggerImageUpload:Zt,handleFileSelect:Qt,handlePaste:Et,uploadImage:et,removeImage:ea,fileToBase64:gt,handleClickOutside:tt,formatTime:ta,getChannelTypeText:aa,scrollToBottom:he,checkScrollPosition:Ae,isNearBottom:Ue,getChannelMessageCount:pt,startDrag:na,handleDragMove:Re,handleDragEnd:ze,resetDragState:Oe,getDragStyle:sa,getDragDistance:oa,clearChannelHistory:wt,showNotification:T,createThresholdCircle:It,removeThresholdCircle:xt,handleTouchStart:ya,handleTouchMove:pa,handleTouchEnd:wa,handleInputFocus:xa,loadMoreMessages:yt,getCachedImageUrl:ot,cacheImage:Ie,clearChannelImageCache:Ne,getMemoryStats:ua,getCacheStats:da,isFileUrl:ne,loadHistoryMessages:rt,handleMessageEvent:$t,saveSelectionState:lt,restoreSelectionState:Bt}}const Ta={class:"bot-list"},Ma={class:"bot-items"},qa=["onClick","onContextmenu"],Ka={class:"bot-avatar"},ja={key:1,class:"avatar-placeholder"},Pa={class:"bot-info"},Aa={class:"bot-name"},Ua={class:"bot-platform"},Ra={class:"channel-list"},za={key:0,class:"empty-state"},Oa={key:1,class:"channel-items"},Na=["data-channel-id","onClick","onContextmenu"],Fa={class:"channel-info"},Ha={class:"channel-name"},Xa={class:"channel-type"},Ya=["onMousedown","onTouchstart","title"],Va={class:"message-area"},Wa={class:"panel-header"},Ja={key:0,class:"empty-state"},Ga={key:1,class:"message-content"},Za={key:0,class:"loading-more-indicator"},Qa={class:"message-avatar"},Ea={key:1,class:"avatar-placeholder"},en={class:"message-content-wrapper"},tn={class:"message-header"},an={class:"message-username"},nn={class:"message-time"},sn={key:0,class:"message-quote"},on={class:"quote-header"},ln={class:"quote-avatar"},rn={key:1,class:"avatar-placeholder"},cn={class:"quote-username"},un={class:"quote-time"},dn={class:"quote-content"},fn={class:"message-text"},hn={class:"message-input"},mn={key:0,class:"image-preview-container"},vn=["src","alt"],gn=["onClick"],yn={class:"input-row"},pn={class:"input-actions"},wn=["placeholder","disabled"],In=["disabled"],xn=Ce({__name:"index",setup(ne){const ce=La(),{AvatarComponent:X,MessageElement:ve,selectedBot:E,selectedChannel:be,inputMessage:u,pinnedBots:U,pinnedChannels:K,uploadedImages:ie,showActionMenu:b,swipeIndicator:Y,messageHistory:Te,messageInput:ge,showScrollButton:ye,isSending:x,isLoadingMore:He,draggingChannel:Me,dragThreshold:$,contextMenu:_,fileInput:Xe,bots:ue,currentChannels:qe,currentMessages:Ye,currentChannelName:Ge,currentChannelKey:j,canSendMessage:V,canInputMessage:Ve,mobileViewClass:y,inputPlaceholder:S,chatContainerStyle:ke,selectBot:W,selectChannel:de,handleBotRightClick:Ke,handleChannelRightClick:P,toggleBotPin:J,toggleChannelPin:N,deleteBotMessages:se,deleteChannelMessages:Se,sendMessage:G,toggleActionMenu:L,triggerImageUpload:fe,handleFileSelect:Be,handlePaste:oe,removeImage:pe,formatTime:we,getChannelTypeText:le,scrollToBottom:R,getChannelMessageCount:A,startDrag:$e,getDragStyle:De,getDragDistance:F,handleTouchStart:_e,handleTouchMove:O,handleTouchEnd:ee,handleInputFocus:k}=ce;return(Z,h)=>(w(),C("div",{class:re(["chat-container",c(y)]),style:ut(c(ke)),onTouchstart:h[15]||(h[15]=(...r)=>c(_e)&&c(_e)(...r)),onTouchmove:h[16]||(h[16]=(...r)=>c(O)&&c(O)(...r)),onTouchend:h[17]||(h[17]=(...r)=>c(ee)&&c(ee)(...r))},[B(" 左侧机器人列表 "),f("div",Ta,[h[18]||(h[18]=f("div",{class:"panel-header"},[f("h3",null,"机器人")],-1)),f("div",Ma,[(w(true),C(ae,null,Le(c(ue),r=>(w(),C("div",{key:r.selfId,class:re(["bot-item",{active:c(E)===r.selfId,pinned:c(U).has(r.selfId)}]),onClick:M=>c(W)(r.selfId),onContextmenu:M=>c(Ke)(M,r.selfId)},[f("div",Ka,[r.avatar?(w(),Fe(c(X),{key:0,src:r.avatar,alt:r.username,"channel-key":"bot-list"},null,8,["src","alt"])):(w(),C("div",ja,D(r.username.charAt(0).toUpperCase()),1))]),f("div",Pa,[f("div",Aa,D(r.username),1),f("div",Ua,D(r.platform),1)]),f("div",{class:re(["bot-status",r.status])},null,2)],42,qa))),128))])]),B(" 中间频道列表 "),f("div",Ra,[h[19]||(h[19]=f("div",{class:"panel-header"},[f("h3",null,"频道")],-1)),c(E)?(w(),C("div",Oa,[(w(true),C(ae,null,Le(c(qe),r=>(w(),C("div",{key:r.id,class:re(["channel-item",{active:c(be)===r.id,pinned:c(K).has(`${c(E)}:${r.id}`)}]),"data-channel-id":r.id,onClick:M=>c(de)(r.id),onContextmenu:M=>c(P)(M,r.id)},[f("div",Fa,[f("div",Ha,D(r.name),1),f("div",Xa,D(c(le)(r.type)),1)]),c(A)(r.id)>0?(w(),C("div",{key:0,class:re(["channel-message-count draggable-bubble",{dragging:c(Me)===r.id,"will-delete":c(Me)===r.id&&c(F)(r.id)>c($)}]),onMousedown:M=>c($e)(M,r.id),onTouchstart:M=>c($e)(M,r.id),style:ut(c(De)(r.id)),title:c(Me)===r.id?c(F)(r.id)>c($)?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},D(c(A)(r.id)),47,Ya)):B("v-if",true)],42,Na))),128))])):(w(),C("div",za," 请选择一个机器人 "))]),B(" 右侧消息区域 "),f("div",Va,[f("div",Wa,[f("h3",null,D(c(Ge)||"选择频道"),1)]),!c(E)||!c(be)?(w(),C("div",Ja," 请选择机器人和频道 ")):(w(),C("div",Ga,[B(" 消息历史 "),f("div",{class:"message-history",ref_key:"messageHistory",ref:Te},[B(" 加载更多指示器 "),c(He)?(w(),C("div",Za,h[20]||(h[20]=[f("div",{class:"loading-spinner"},null,-1),f("span",null,"加载更多消息中...",-1)]))):B("v-if",true),(w(true),C(ae,null,Le(c(Ye),r=>(w(),C("div",{key:r.id,class:re(["message-item",{"bot-message":r.isBot}])},[f("div",Qa,[r.avatar?(w(),Fe(c(X),{key:0,src:r.avatar,alt:r.username,"channel-key":c(j)},null,8,["src","alt","channel-key"])):(w(),C("div",Ea,D(r.username.charAt(0).toUpperCase()),1))]),f("div",en,[f("div",tn,[f("span",an,D(r.username),1),f("span",nn,D(c(we)(r.timestamp)),1)]),B(" 引用消息显示 "),r.quote?(w(),C("div",sn,[f("div",on,[f("div",ln,[r.quote.user.avatar?(w(),Fe(c(X),{key:0,src:r.quote.user.avatar,alt:r.quote.user.username,"channel-key":c(j)},null,8,["src","alt","channel-key"])):(w(),C("div",rn,D(r.quote.user.username.charAt(0).toUpperCase()),1))]),f("span",cn,D(r.quote.user.username),1),f("span",un,D(c(we)(r.quote.timestamp)),1)]),f("div",dn,[r.quote.elements&&r.quote.elements.length>0?(w(true),C(ae,{key:0},Le(r.quote.elements,(M,je)=>(w(),Fe(c(ve),{key:`quote-${je}`,element:M,"channel-key":c(j)},null,8,["element","channel-key"]))),128)):(w(),C(ae,{key:1},[dt(D(r.quote.content),1)],64))])])):B("v-if",true),f("div",fn,[r.elements&&r.elements.length>0?(w(true),C(ae,{key:0},Le(r.elements,(M,je)=>(w(),Fe(c(ve),{key:je,element:M,"channel-key":c(j)},null,8,["element","channel-key"]))),128)):(w(),C(ae,{key:1},[dt(D(r.content),1)],64))])])],2))),128))],512),B(" 悬浮的滚动到底部按钮 "),Mt(f("div",{class:"floating-scroll-button",onClick:h[0]||(h[0]=(...r)=>c(R)&&c(R)(...r))},h[21]||(h[21]=[f("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[f("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[ka,c(ye)]]),B(" 输入框 "),f("div",hn,[B(" 图片预览区域 "),c(ie).length>0?(w(),C("div",mn,[(w(true),C(ae,null,Le(c(ie),r=>(w(),C("div",{key:r.tempId,class:"image-preview-item"},[f("img",{src:r.preview,alt:r.filename,class:"preview-image"},null,8,vn),f("button",{class:"remove-image-btn",onClick:M=>c(pe)(r.tempId),title:"删除图片"},h[22]||(h[22]=[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,gn)]))),128))])):B("v-if",true),f("div",yn,[B(" 加号按钮 "),f("div",pn,[f("button",{class:re(["add-button",{active:c(b)}]),onClick:h[1]||(h[1]=(...r)=>c(L)&&c(L)(...r)),title:"更多操作"},h[23]||(h[23]=[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(" 操作菜单 "),c(b)?(w(),C("div",{key:0,class:"action-menu",onClick:h[3]||(h[3]=qt(()=>{},["stop"]))},[f("button",{class:"action-menu-item",onClick:h[2]||(h[2]=(...r)=>c(fe)&&c(fe)(...r))},h[24]||(h[24]=[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),dt(" 上传图片 ",-1)]))])):B("v-if",true)]),Mt(f("input",{"onUpdate:modelValue":h[4]||(h[4]=r=>Ba(u)?u.value=r:null),type:"text",placeholder:c(S),onKeyup:h[5]||(h[5]=Sa((...r)=>c(G)&&c(G)(...r),["enter"])),disabled:!c(Ve),ref_key:"messageInput",ref:ge,onPaste:h[6]||(h[6]=(...r)=>c(oe)&&c(oe)(...r)),onFocus:h[7]||(h[7]=(...r)=>c(k)&&c(k)(...r))},null,40,wn),[[$a,c(u)]]),f("button",{onClick:h[8]||(h[8]=(...r)=>c(G)&&c(G)(...r)),disabled:!c(V),class:re({"is-sending":c(x)})},D(c(x)?"发送中...":"发送"),11,In)]),B(" 隐藏的文件输入 "),f("input",{type:"file",ref_key:"fileInput",ref:Xe,onChange:h[9]||(h[9]=(...r)=>c(Be)&&c(Be)(...r)),accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),B(" 右键菜单 "),c(_).show?(w(),C("div",{key:0,class:"context-menu",style:ut({left:c(_).x+"px",top:c(_).y+"px"}),onClick:h[14]||(h[14]=qt(()=>{},["stop"]))},[B(" 机器人右键菜单 "),c(_).type==="bot"?(w(),C(ae,{key:0},[f("div",{class:"context-menu-item",onClick:h[10]||(h[10]=r=>c(J)(c(_).targetId))},D(c(U).has(c(_).targetId)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:h[11]||(h[11]=r=>c(se)(c(_).targetId))}," 彻底删除此机器人所有数据 ")],64)):B("v-if",true),B(" 频道右键菜单 "),c(_).type==="channel"?(w(),C(ae,{key:1},[f("div",{class:"context-menu-item",onClick:h[12]||(h[12]=r=>c(N)(c(_).targetId))},D(c(K).has(`${c(E)}:${c(_).targetId}`)?"取消置顶":"置顶"),1),f("div",{class:"context-menu-item danger",onClick:h[13]||(h[13]=r=>c(Se)(c(_).targetId))}," 彻底删除此频道所有数据 ")],64)):B("v-if",true)],4)):B("v-if",true),B(" 滑动指示器 "),f("div",{class:re(["swipe-indicator",{show:c(Y).show}])},D(c(Y).text),3)],38))}}),Kt=(ne,ce)=>{const X=ne.__vccOpts||ne;for(const[ve,E]of ce)X[ve]=E;return X},Cn=Kt(xn,[["__scopeId","data-v-f8e0fc57"]]),bn={},kn={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function Sn(ne,ce){return w(),C("svg",kn,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 Bn=Kt(bn,[["render",Sn]]);_a.register("activity:chat",Bn);const Ln=ne=>{ne.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Ce({setup(){return()=>m(Da("k-layout"),{},{default:()=>m(Cn)})}})})};export{Ln 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;overflow-x:hidden;max-height:calc(100vh - 140px);-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:rgba(144,147,153,.4) rgba(0,0,0,.05);scroll-behavior:smooth;overscroll-behavior:contain;padding-bottom:8px}.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}.bot-items[data-v-de93bb69],.channel-items[data-v-de93bb69]{flex:1;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 140px);max-height:calc(100dvh - 140px);-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:rgba(144,147,153,.4) rgba(0,0,0,.05);scroll-behavior:smooth;overscroll-behavior:contain;padding-bottom:8px}}@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,.channel-items[data-v-de93bb69]::-webkit-scrollbar{width:8px}.bot-items[data-v-de93bb69]::-webkit-scrollbar-track,.channel-items[data-v-de93bb69]::-webkit-scrollbar-track{background:#0000000d;border-radius:4px}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb{background-color:#90939966;border-radius:4px;transition:all .3s ease;border:1px solid rgba(255,255,255,.1);background-clip:padding-box}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:hover{background-color:#90939999;transform:scaleX(1.2)}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:active,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:active{background-color:#909399cc}.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-track,.channel-items[data-v-de93bb69]::-webkit-scrollbar-track{background:#ffffff0d}.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:#ffffff4d;border-color:#0000001a}.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:#ffffff80}.bot-items[data-v-de93bb69]::-webkit-scrollbar-thumb:active,.channel-items[data-v-de93bb69]::-webkit-scrollbar-thumb:active{background-color:#ffffffb3}}.layout-iframe{width:100%;height:100%;border:none}
1
+ .message-quote[data-v-f8e0fc57]{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-f8e0fc57]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-f8e0fc57]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-f8e0fc57]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-f8e0fc57]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-f8e0fc57]{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-f8e0fc57]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-f8e0fc57]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-f8e0fc57]{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-f8e0fc57]{max-width:min(200px,50vw);max-height:100px}.quote-content .message-image-container[data-v-f8e0fc57]{margin:2px 0}@media (prefers-color-scheme:dark){.message-quote[data-v-f8e0fc57]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-f8e0fc57]{color:#adb5bd}.quote-username[data-v-f8e0fc57]{color:#0d6efd}}.chat-container[data-v-f8e0fc57]{display:flex;height:100vh;background:0 0;margin-left:0;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-f8e0fc57],.channel-list[data-v-f8e0fc57],.message-area[data-v-f8e0fc57]{display:flex;flex-direction:column;background:0 0;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-f8e0fc57]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-f8e0fc57]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-f8e0fc57]{flex:1;border-right:none}.panel-header[data-v-f8e0fc57]{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-f8e0fc57]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-f8e0fc57]{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-f8e0fc57]:hover{background:#8080801a}.bot-items[data-v-f8e0fc57],.channel-items[data-v-f8e0fc57]{flex:1;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 140px);-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:rgba(144,147,153,.4) rgba(0,0,0,.05);scroll-behavior:smooth;overscroll-behavior:contain;padding-bottom:8px}.bot-item[data-v-f8e0fc57],.channel-item[data-v-f8e0fc57]{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-f8e0fc57]:hover,.channel-item[data-v-f8e0fc57]:hover{background:#8080801a}.bot-item.active[data-v-f8e0fc57],.channel-item.active[data-v-f8e0fc57]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-f8e0fc57]{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-f8e0fc57]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-f8e0fc57]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-f8e0fc57]{flex:1}.bot-name[data-v-f8e0fc57]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-f8e0fc57]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-f8e0fc57]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-f8e0fc57]{background:#4caf50}.bot-status.offline[data-v-f8e0fc57]{background:#f44336}.channel-info[data-v-f8e0fc57]{flex:1}.channel-name[data-v-f8e0fc57]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-f8e0fc57]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-f8e0fc57]{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-f8e0fc57]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-f8e0fc57]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble.dragging[data-v-f8e0fc57],.channel-message-count.draggable-bubble[data-v-f8e0fc57]:active{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-f8e0fc57]{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-f8e0fc57]{background:#f44336!important;animation:shake-f8e0fc57 .3s ease-in-out infinite}@keyframes pulseThreshold-f8e0fc57{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-f8e0fc57{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-f8e0fc57]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-f8e0fc57]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-f8e0fc57]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-f8e0fc57]:hover{background-color:#8080801a}.message-item.new-message[data-v-f8e0fc57]{background-color:#4caf5033;animation:highlight-f8e0fc57 2s ease-out}.message-item.bot-message[data-v-f8e0fc57]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-f8e0fc57]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-f8e0fc57]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-f8e0fc57]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-f8e0fc57]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-f8e0fc57]{order:1}.message-item.bot-message .message-text[data-v-f8e0fc57]{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-f8e0fc57{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-f8e0fc57]{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-f8e0fc57]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-f8e0fc57]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-f8e0fc57]{flex:1}.message-header[data-v-f8e0fc57]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-f8e0fc57]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-f8e0fc57]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-f8e0fc57]{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-f8e0fc57]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-f8e0fc57]:active{transform:scale(.95)}.input-row button[data-v-f8e0fc57]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-f8e0fc57]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-f8e0fc57]{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-f8e0fc57],.message-image[src*="image/gif"][data-v-f8e0fc57]{image-rendering:auto!important;-webkit-image-rendering:auto!important;animation-play-state:running!important}.message-image-loading[data-v-f8e0fc57]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-f8e0fc57]{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-f8e0fc57]{display:block;margin-bottom:4px}.message-paragraph[data-v-f8e0fc57]:last-child{margin-bottom:0}.forward-message-container[data-v-f8e0fc57]{border:1px solid #fff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-f8e0fc57]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-f8e0fc57]:hover{background:#f0f0f0}.forward-message-title[data-v-f8e0fc57]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-f8e0fc57]{color:#666;font-size:12px}.forward-message-expanded[data-v-f8e0fc57]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-f8e0fc57]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-f8e0fc57]:last-child{border-bottom:none}.forwarded-message-header[data-v-f8e0fc57]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-f8e0fc57]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-f8e0fc57]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-f8e0fc57]{color:#555;font-size:13px;line-height:1.4;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere}.message-at[data-v-f8e0fc57]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-f8e0fc57]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-f8e0fc57]{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-f8e0fc57]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-f8e0fc57]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-f8e0fc57]{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-f8e0fc57]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-f8e0fc57]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-f8e0fc57]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-f8e0fc57]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-f8e0fc57]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-f8e0fc57]{display:inline;word-wrap:break-word;word-break:break-all;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto}.message-image-container[data-v-f8e0fc57]{display:block;margin:4px 0}.message-image[data-v-f8e0fc57]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-f8e0fc57]:hover{transform:scale(1.02)}.message-image-loading[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]:hover{background:#2196f333}.message-unknown[data-v-f8e0fc57]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-f8e0fc57{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-f8e0fc57]{background:#f44336!important;animation:shake-f8e0fc57 .3s ease-in-out infinite}@keyframes shake-f8e0fc57{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-f8e0fc57]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-f8e0fc57]{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-f8e0fc57 1.5s ease-in-out infinite}.context-menu[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]:last-child{border-bottom:none}.context-menu-item[data-v-f8e0fc57]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-f8e0fc57]{color:#d32f2f}.context-menu-item.danger[data-v-f8e0fc57]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-f8e0fc57],.channel-item.pinned[data-v-f8e0fc57]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-f8e0fc57]:before,.channel-item.pinned[data-v-f8e0fc57]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-f8e0fc57],.channel-item.pinned[data-v-f8e0fc57]{position:relative;padding-left:24px}@media (prefers-color-scheme:dark){.context-menu[data-v-f8e0fc57]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-f8e0fc57]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-f8e0fc57]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-f8e0fc57]{color:#ff8a80}.context-menu-item.danger[data-v-f8e0fc57]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-f8e0fc57],.channel-item.pinned[data-v-f8e0fc57]{background:#ffc10726}}.message-share-card[data-v-f8e0fc57]{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-f8e0fc57]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{transform:scale(1.05)}.share-card-content[data-v-f8e0fc57]{padding:8px}.share-card-header[data-v-f8e0fc57]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-f8e0fc57]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-f8e0fc57]{flex:1;min-width:0}.share-card-app-name[data-v-f8e0fc57]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-f8e0fc57]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-f8e0fc57]:after{transform:translate(2px)}.message-json-error[data-v-f8e0fc57],.message-json-raw[data-v-f8e0fc57]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-f8e0fc57]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-f8e0fc57]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-f8e0fc57]{margin-top:8px}.json-raw-data summary[data-v-f8e0fc57]{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-f8e0fc57]:hover{background:#2196f333}.json-raw-content[data-v-f8e0fc57]{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-f8e0fc57]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-f8e0fc57]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-f8e0fc57]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width:768px){.chat-container[data-v-f8e0fc57]{position:relative;height:100vh;height:100dvh}.bot-list[data-v-f8e0fc57],.channel-list[data-v-f8e0fc57],.message-area[data-v-f8e0fc57]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-f8e0fc57]{transform:translate(0);z-index:3}.channel-list[data-v-f8e0fc57]{transform:translate(100%);z-index:2}.message-area[data-v-f8e0fc57]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-f8e0fc57]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-f8e0fc57]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-f8e0fc57]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-f8e0fc57]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-f8e0fc57]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-f8e0fc57]{transform:translate(0);z-index:3}.back-button[data-v-f8e0fc57]{display:none!important}.panel-header[data-v-f8e0fc57]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-f8e0fc57]{text-align:right}.floating-scroll-button[data-v-f8e0fc57]{right:16px;bottom:calc(90px + env(safe-area-inset-bottom,0px));width:40px;height:40px;transition:bottom .3s ease}.message-input[data-v-f8e0fc57]{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-f8e0fc57]{font-size:16px;padding:10px 12px}.input-row button[data-v-f8e0fc57]{padding:10px 16px;font-size:16px}.message-history[data-v-f8e0fc57]{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-f8e0fc57]{margin-bottom:12px;padding:6px}.message-text[data-v-f8e0fc57]{max-width:90%!important}.message-avatar[data-v-f8e0fc57]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-f8e0fc57]{margin-left:8px}.message-image[data-v-f8e0fc57]{max-width:min(280px,66.67vw);max-height:160px}.quote-content .message-image[data-v-f8e0fc57]{max-width:min(150px,50vw);max-height:80px}.context-menu[data-v-f8e0fc57]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-f8e0fc57]{padding:14px 16px;font-size:16px}.bot-item[data-v-f8e0fc57],.channel-item[data-v-f8e0fc57]{padding:14px 16px}.bot-avatar[data-v-f8e0fc57]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-f8e0fc57],.channel-name[data-v-f8e0fc57]{font-size:15px}.bot-platform[data-v-f8e0fc57],.channel-type[data-v-f8e0fc57]{font-size:13px}.bot-items[data-v-f8e0fc57],.channel-items[data-v-f8e0fc57]{flex:1;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 140px);max-height:calc(100dvh - 140px);-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:rgba(144,147,153,.4) rgba(0,0,0,.05);scroll-behavior:smooth;overscroll-behavior:contain;padding-bottom:8px}}@media (min-width:769px) and (max-width:1024px){.bot-list[data-v-f8e0fc57]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-f8e0fc57]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-f8e0fc57]{max-width:min(350px,66.67vw);max-height:180px}}.chat-container.swiping[data-v-f8e0fc57]{overflow:hidden}.bot-list.swiping[data-v-f8e0fc57],.channel-list.swiping[data-v-f8e0fc57],.message-area.swiping[data-v-f8e0fc57]{transition:none!important}.swipe-indicator[data-v-f8e0fc57]{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-f8e0fc57]{opacity:1}.message-area .message-content[data-v-f8e0fc57]{padding-bottom:80px}.image-preview-container[data-v-f8e0fc57]{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-f8e0fc57]{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-f8e0fc57]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-f8e0fc57]{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-f8e0fc57]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-f8e0fc57]{position:relative;margin-right:8px}.add-button[data-v-f8e0fc57]{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-f8e0fc57]: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-f8e0fc57]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-f8e0fc57]:hover:before{opacity:1}.add-button.active[data-v-f8e0fc57]{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-f8e0fc57]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-f8e0fc57]{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-f8e0fc57 .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-f8e0fc57]{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-f8e0fc57]: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-f8e0fc57]:hover{background:linear-gradient(90deg,#667eea14 0,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-f8e0fc57]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-f8e0fc57]{flex-shrink:0}@media (prefers-color-scheme:dark){.action-menu[data-v-f8e0fc57]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-f8e0fc57]{color:#fff}.action-menu-item[data-v-f8e0fc57]:before{background:linear-gradient(135deg,#4facfe 0,#00f2fe)}.action-menu-item[data-v-f8e0fc57]:hover{background:linear-gradient(90deg,#4facfe1f 0,#00f2fe1f);color:#4facfe}.add-button[data-v-f8e0fc57]{background:linear-gradient(135deg,#4facfe 0,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-f8e0fc57]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-f8e0fc57]{background:linear-gradient(135deg,#fa709a 0,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-f8e0fc57]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width:768px){.image-preview-container[data-v-f8e0fc57]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-f8e0fc57]{width:50px;height:50px}.add-button[data-v-f8e0fc57]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-f8e0fc57]{min-width:100px}.action-menu-item[data-v-f8e0fc57]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-f8e0fc57]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-f8e0fc57]::-webkit-scrollbar{width:6px}.message-history[data-v-f8e0fc57]::-webkit-scrollbar-track{background:0 0}.message-history[data-v-f8e0fc57]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar{width:8px}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-track,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-track{background:#0000000d;border-radius:4px}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb{background-color:#90939966;border-radius:4px;transition:all .3s ease;border:1px solid rgba(255,255,255,.1);background-clip:padding-box}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover{background-color:#90939999;transform:scaleX(1.2)}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:active,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:active{background-color:#909399cc}.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar-track{background:0 0}.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar-track{background:0 0}.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme:dark){.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-track,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-track{background:#ffffff0d}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar-thumb,.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar-thumb,.message-history[data-v-f8e0fc57]::-webkit-scrollbar-thumb{background-color:#ffffff4d;border-color:#0000001a}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover,.message-history[data-v-f8e0fc57]::-webkit-scrollbar-thumb:hover{background-color:#ffffff80}.bot-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:active,.channel-items[data-v-f8e0fc57]::-webkit-scrollbar-thumb:active{background-color:#ffffffb3}}.loading-more-indicator[data-v-f8e0fc57]{display:flex;align-items:center;justify-content:center;padding:12px;color:#6c757d;font-size:14px}.loading-spinner[data-v-f8e0fc57]{width:20px;height:20px;border:2px solid #f3f3f3;border-top:2px solid #2196f3;border-radius:50%;animation:spin-f8e0fc57 1s linear infinite;margin-right:8px}@keyframes spin-f8e0fc57{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.layout-iframe{width:100%;height:100%;border:none}
package/lib/index.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { Console } from '@koishijs/console';
2
+ import { Context } from 'koishi';
3
+ import { Config } from './config';
4
+ export declare const name = "chat-patch";
5
+ export declare const reusable = false;
6
+ export declare const filter = true;
7
+ export declare const inject: {
8
+ required: string[];
9
+ };
10
+ declare module 'koishi' {
11
+ interface Context {
12
+ console: Console;
13
+ }
14
+ }
15
+ export declare const usage = "\n\n---\n\n\u5F00\u542F\u540E\uFF0C\u5373\u53EF\u5728koishi\u63A7\u5236\u53F0\u64CD\u4F5C\u673A\u5668\u4EBA\u6536\u53D1\u6D88\u606F\u5566\n\n\u6682\u65F6\u53EA\u652F\u6301\u63A5\u53D7\u56FE\u6587\u6D88\u606F / \u53D1\u9001\u6587\u5B57\u6D88\u606F\n\n---\n";
16
+ export { Config } from './config';
17
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
package/lib/index.js CHANGED
@@ -538,16 +538,25 @@ var ApiHandlers = class {
538
538
  try {
539
539
  const data = this.fileManager.readChatDataFromFile();
540
540
  const channelKey = `${requestData.selfId}:${requestData.channelId}`;
541
- const messages = data.messages[channelKey] || [];
542
- const sortedMessages = messages.sort((a, b) => a.timestamp - b.timestamp);
543
- this.logInfo("获取历史消息:", channelKey, "共", sortedMessages.length, "条消息");
541
+ let messages = data.messages[channelKey] || [];
542
+ const sortedMessages = messages.sort((a, b) => b.timestamp - a.timestamp);
543
+ if (requestData.limit !== void 0) {
544
+ const limit = requestData.limit;
545
+ const offset = requestData.offset || 0;
546
+ messages = sortedMessages.slice(offset, offset + limit);
547
+ messages = messages.sort((a, b) => a.timestamp - b.timestamp);
548
+ } else {
549
+ messages = sortedMessages.sort((a, b) => a.timestamp - b.timestamp);
550
+ }
551
+ this.logInfo("获取历史消息:", channelKey, "共", messages.length, "条消息");
544
552
  return {
545
553
  success: true,
546
- messages: sortedMessages
554
+ messages,
555
+ total: sortedMessages.length
547
556
  };
548
557
  } catch (error) {
549
558
  this.logger.error("获取历史消息失败:", error);
550
- return { success: false, error: error?.message || String(error), messages: [] };
559
+ return { success: false, error: error?.message || String(error), messages: [], total: 0 };
551
560
  }
552
561
  });
553
562
  this.ctx.console.addListener("get-all-channel-message-counts", async () => {
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.18",
4
+ "version": "1.1.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -37,4 +37,4 @@
37
37
  "@koishijs/client": "^5.11.0",
38
38
  "koishi": "^4.16.0"
39
39
  }
40
- }
40
+ }
@@ -2,7 +2,7 @@ import { FileManager } from './file-manager'
2
2
  import { MessageHandler } from './message-handler'
3
3
  import { Context, h, Logger } from 'koishi'
4
4
  import { Config } from './config'
5
-
5
+ import { } from '@koishijs/plugin-console'
6
6
  import { URL, pathToFileURL } from 'node:url'
7
7
 
8
8
  export class ApiHandlers {
@@ -50,23 +50,39 @@ export class ApiHandlers {
50
50
  this.ctx.console.addListener('get-history-messages' as any, async (requestData: {
51
51
  selfId: string
52
52
  channelId: string
53
+ limit?: number
54
+ offset?: number
53
55
  }) => {
54
56
  try {
55
57
  const data = this.fileManager.readChatDataFromFile()
56
58
  const channelKey = `${requestData.selfId}:${requestData.channelId}`
57
- const messages = data.messages[channelKey] || []
58
-
59
- const sortedMessages = messages.sort((a, b) => a.timestamp - b.timestamp)
59
+ let messages = data.messages[channelKey] || []
60
+
61
+ // 按时间戳降序排列(最新的消息在前面)
62
+ const sortedMessages = messages.sort((a, b) => b.timestamp - a.timestamp)
63
+
64
+ // 如果提供了分页参数,则进行分页处理
65
+ if (requestData.limit !== undefined) {
66
+ const limit = requestData.limit
67
+ const offset = requestData.offset || 0
68
+ messages = sortedMessages.slice(offset, offset + limit)
69
+ // 重新按时间戳升序排列,以保持消息显示顺序
70
+ messages = messages.sort((a, b) => a.timestamp - b.timestamp)
71
+ } else {
72
+ // 默认返回所有消息,按时间戳升序排列
73
+ messages = sortedMessages.sort((a, b) => a.timestamp - b.timestamp)
74
+ }
60
75
 
61
- this.logInfo('获取历史消息:', channelKey, '共', sortedMessages.length, '条消息')
76
+ this.logInfo('获取历史消息:', channelKey, '共', messages.length, '条消息')
62
77
 
63
78
  return {
64
79
  success: true,
65
- messages: sortedMessages
80
+ messages: messages,
81
+ total: sortedMessages.length
66
82
  }
67
83
  } catch (error: any) {
68
84
  this.logger.error('获取历史消息失败:', error)
69
- return { success: false, error: error?.message || String(error), messages: [] }
85
+ return { success: false, error: error?.message || String(error), messages: [], total: 0 }
70
86
  }
71
87
  })
72
88
 
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- import { } from '@koishijs/plugin-console'
2
+ import { Console } from '@koishijs/console'
3
3
  import { Context } from 'koishi'
4
4
  import path from 'node:path'
5
5
 
@@ -16,6 +16,12 @@ export const inject = {
16
16
  required: ['console']
17
17
  }
18
18
 
19
+ declare module 'koishi' {
20
+ interface Context {
21
+ console: Console
22
+ }
23
+ }
24
+
19
25
  export const usage = `
20
26
 
21
27
  ---
@@ -3,6 +3,7 @@ import { Context, Session, h, Logger } from 'koishi'
3
3
  import { FileManager } from './file-manager'
4
4
  import { Config } from './config'
5
5
  import { Utils } from './utils'
6
+ import { } from '@koishijs/plugin-console'
6
7
 
7
8
  export class MessageHandler {
8
9
  private logger: Logger