koishi-plugin-chat-patch 1.0.8 → 1.0.9

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.
@@ -222,7 +222,6 @@ function isFileUrl(url: string): boolean {
222
222
  }
223
223
  }
224
224
 
225
-
226
225
  // 头像组件
227
226
  const AvatarComponent = defineComponent({
228
227
  props: {
@@ -899,13 +898,35 @@ interface ImageCacheItem {
899
898
 
900
899
  // 内存中的URL缓存
901
900
  const imageBlobUrls = ref<Record<string, string>>({})
902
- const maxImagesPerChannel = 200 // 每个频道最大缓存图片数量
903
901
 
904
902
  // 内存管理配置
905
903
  const MAX_MEMORY_USAGE = 100 * 1024 * 1024 // 100MB 最大内存使用量
906
904
  const MAX_BLOB_COUNT = 50 // 最大blob URL数量
907
905
  let currentMemoryUsage = 0 // 当前内存使用量估算
908
906
 
907
+ // IndexedDB 配置和限制
908
+ let imageDB: IDBDatabase | null = null
909
+ const DB_NAME = 'ChatImageCache'
910
+ const DB_VERSION = 2 // 版本号
911
+ const STORE_NAME = 'images'
912
+
913
+ // 严格的存储限制
914
+ const MAX_DB_SIZE = 50 * 1024 * 1024 // 50MB 最大数据库大小
915
+ const MAX_IMAGES_PER_CHANNEL = 100 // 每个频道最多缓存100张图片
916
+ const MAX_TOTAL_IMAGES = 500 // 总共最多缓存500张图片
917
+ const MAX_IMAGE_SIZE = 2 * 1024 * 1024 // 单张图片最大2MB
918
+ const CLEANUP_THRESHOLD = 0.8 // 当达到80%限制时开始清理
919
+ const DB_HEALTH_CHECK_INTERVAL = 60 * 1000 // 每分钟检查一次数据库健康状态
920
+
921
+ // 数据库状态跟踪
922
+ let currentDbSize = 0
923
+ let currentImageCount = 0
924
+ let lastHealthCheck = 0
925
+
926
+ const selectedBot = ref<string>('')
927
+ const selectedChannel = ref<string>('')
928
+ const inputMessage = ref<string>('')
929
+
909
930
  // 内存管理函数
910
931
  function estimateBlobSize(blob: Blob): number {
911
932
  return blob.size || 0
@@ -954,16 +975,6 @@ function checkAndCleanupMemory() {
954
975
  }
955
976
  }
956
977
 
957
- // IndexedDB
958
- let imageDB: IDBDatabase | null = null
959
- const DB_NAME = 'ChatImageCache'
960
- const DB_VERSION = 1
961
- const STORE_NAME = 'images'
962
-
963
- const selectedBot = ref<string>('')
964
- const selectedChannel = ref<string>('')
965
- const inputMessage = ref<string>('')
966
-
967
978
  // 图片上传相关状态
968
979
  const uploadedImages = ref<Array<{
969
980
  tempId: string
@@ -971,6 +982,7 @@ const uploadedImages = ref<Array<{
971
982
  preview: string
972
983
  size: number
973
984
  }>>([])
985
+
974
986
  const showActionMenu = ref<boolean>(false)
975
987
  const fileInput = ref<HTMLInputElement>()
976
988
 
@@ -1771,7 +1783,6 @@ function resetDragState() {
1771
1783
  removeThresholdCircle()
1772
1784
  }
1773
1785
 
1774
- // getDragStyle 不再直接用于拖拽中的元素,而是用于原始元素隐藏
1775
1786
  function getDragStyle(channelId: string) {
1776
1787
  if (draggingChannel.value === channelId && isDragReady.value) {
1777
1788
  // 当拖拽开始且准备就绪时,隐藏原始气泡
@@ -1951,30 +1962,319 @@ function removeThresholdCircle() {
1951
1962
  }
1952
1963
  }
1953
1964
 
1954
- // IndexedDB初始化
1955
- async function initImageDB(): Promise<boolean> {
1956
- return new Promise((resolve, reject) => {
1957
- const request = indexedDB.open(DB_NAME, DB_VERSION)
1965
+ // 数据库健康检查
1966
+ async function checkDatabaseHealth(): Promise<boolean> {
1967
+ try {
1968
+ if (!imageDB) return false
1969
+
1970
+ const now = Date.now()
1971
+ if (now - lastHealthCheck < DB_HEALTH_CHECK_INTERVAL) {
1972
+ return true // 跳过频繁检查
1973
+ }
1974
+
1975
+ lastHealthCheck = now
1976
+
1977
+ // 获取数据库统计信息
1978
+ const stats = await getDatabaseStats()
1979
+ currentDbSize = stats.totalSize
1980
+ currentImageCount = stats.totalImages
1981
+
1982
+ console.log('数据库健康检查:', {
1983
+ 大小: `${(currentDbSize / 1024 / 1024).toFixed(2)}MB / ${(MAX_DB_SIZE / 1024 / 1024).toFixed(2)}MB`,
1984
+ 图片数量: `${currentImageCount} / ${MAX_TOTAL_IMAGES}`,
1985
+ 使用率: `${(currentDbSize / MAX_DB_SIZE * 100).toFixed(1)}%`
1986
+ })
1987
+
1988
+ // 检查是否需要清理
1989
+ const sizeRatio = currentDbSize / MAX_DB_SIZE
1990
+ const countRatio = currentImageCount / MAX_TOTAL_IMAGES
1991
+
1992
+ if (sizeRatio > CLEANUP_THRESHOLD || countRatio > CLEANUP_THRESHOLD) {
1993
+ console.warn('数据库使用率过高,开始自动清理')
1994
+ await performAutomaticCleanup()
1995
+ }
1996
+
1997
+ // 检查是否超过硬限制
1998
+ if (sizeRatio > 0.95 || countRatio > 0.95) {
1999
+ console.error('数据库接近极限,执行紧急清理')
2000
+ await performEmergencyCleanup()
2001
+ }
2002
+
2003
+ return true
2004
+ } catch (error) {
2005
+ console.error('数据库健康检查失败:', error)
2006
+ return false
2007
+ }
2008
+ }
2009
+
2010
+ // 获取数据库统计信息
2011
+ async function getDatabaseStats(): Promise<{ totalSize: number, totalImages: number, channelStats: Record<string, number> }> {
2012
+ if (!imageDB) return { totalSize: 0, totalImages: 0, channelStats: {} }
2013
+
2014
+ return new Promise((resolve) => {
2015
+ const transaction = imageDB!.transaction([STORE_NAME], 'readonly')
2016
+ const store = transaction.objectStore(STORE_NAME)
2017
+ const request = store.getAll()
2018
+
2019
+ request.onsuccess = () => {
2020
+ const items: ImageCacheItem[] = request.result || []
2021
+ let totalSize = 0
2022
+ const channelStats: Record<string, number> = {}
2023
+
2024
+ items.forEach(item => {
2025
+ totalSize += item.size || 0
2026
+ channelStats[item.channelKey] = (channelStats[item.channelKey] || 0) + 1
2027
+ })
2028
+
2029
+ resolve({
2030
+ totalSize,
2031
+ totalImages: items.length,
2032
+ channelStats
2033
+ })
2034
+ }
1958
2035
 
1959
2036
  request.onerror = () => {
1960
- console.error('IndexedDB初始化失败:', request.error)
1961
- resolve(false)
2037
+ console.error('获取数据库统计失败:', request.error)
2038
+ resolve({ totalSize: 0, totalImages: 0, channelStats: {} })
2039
+ }
2040
+ })
2041
+ }
2042
+
2043
+ // 自动清理
2044
+ async function performAutomaticCleanup() {
2045
+ try {
2046
+ console.log('开始自动清理...')
2047
+
2048
+ // 获取所有图片,按时间排序
2049
+ const allImages = await getAllImagesFromDB()
2050
+ if (allImages.length === 0) return
2051
+
2052
+ // 按频道分组
2053
+ const channelGroups: Record<string, ImageCacheItem[]> = {}
2054
+ allImages.forEach(item => {
2055
+ if (!channelGroups[item.channelKey]) {
2056
+ channelGroups[item.channelKey] = []
2057
+ }
2058
+ channelGroups[item.channelKey].push(item)
2059
+ })
2060
+
2061
+ let cleanedCount = 0
2062
+ let freedSize = 0
2063
+
2064
+ // 清理每个频道超出限制的图片
2065
+ for (const [channelKey, images] of Object.entries(channelGroups)) {
2066
+ if (images.length > MAX_IMAGES_PER_CHANNEL) {
2067
+ // 按时间排序,删除最旧的
2068
+ images.sort((a, b) => a.timestamp - b.timestamp)
2069
+ const toDelete = images.slice(0, images.length - MAX_IMAGES_PER_CHANNEL)
2070
+
2071
+ for (const item of toDelete) {
2072
+ await deleteImageFromDB(item.url)
2073
+ cleanedCount++
2074
+ freedSize += item.size || 0
2075
+
2076
+ // 清理内存中的blob URL
2077
+ if (imageBlobUrls.value[item.url]) {
2078
+ URL.revokeObjectURL(imageBlobUrls.value[item.url])
2079
+ delete imageBlobUrls.value[item.url]
2080
+ }
2081
+ }
2082
+ }
2083
+ }
2084
+
2085
+ console.log(`自动清理完成: 清理了 ${cleanedCount} 张图片,释放了 ${(freedSize / 1024 / 1024).toFixed(2)}MB`)
2086
+
2087
+ // 更新统计
2088
+ currentImageCount -= cleanedCount
2089
+ currentDbSize -= freedSize
2090
+
2091
+ } catch (error) {
2092
+ console.error('自动清理失败:', error)
2093
+ }
2094
+ }
2095
+
2096
+ // 紧急清理 // 激进
2097
+ async function performEmergencyCleanup() {
2098
+ try {
2099
+ console.log('开始紧急清理...')
2100
+
2101
+ // 获取所有图片
2102
+ const allImages = await getAllImagesFromDB()
2103
+ if (allImages.length === 0) return
2104
+
2105
+ // 按时间排序,只保留最新的一部分
2106
+ allImages.sort((a, b) => b.timestamp - a.timestamp)
2107
+ const keepCount = Math.floor(MAX_TOTAL_IMAGES * 0.3) // 只保留30%
2108
+ const toDelete = allImages.slice(keepCount)
2109
+
2110
+ let cleanedCount = 0
2111
+ let freedSize = 0
2112
+
2113
+ for (const item of toDelete) {
2114
+ await deleteImageFromDB(item.url)
2115
+ cleanedCount++
2116
+ freedSize += item.size || 0
2117
+
2118
+ // 清理内存中的blob URL
2119
+ if (imageBlobUrls.value[item.url]) {
2120
+ URL.revokeObjectURL(imageBlobUrls.value[item.url])
2121
+ delete imageBlobUrls.value[item.url]
2122
+ }
1962
2123
  }
1963
2124
 
2125
+ console.log(`紧急清理完成: 清理了 ${cleanedCount} 张图片,释放了 ${(freedSize / 1024 / 1024).toFixed(2)}MB`)
2126
+
2127
+ // 更新统计
2128
+ currentImageCount = keepCount
2129
+ currentDbSize -= freedSize
2130
+
2131
+ } catch (error) {
2132
+ console.error('紧急清理失败:', error)
2133
+ }
2134
+ }
2135
+
2136
+ // 获取所有图片
2137
+ async function getAllImagesFromDB(): Promise<ImageCacheItem[]> {
2138
+ if (!imageDB) return []
2139
+
2140
+ return new Promise((resolve) => {
2141
+ const transaction = imageDB!.transaction([STORE_NAME], 'readonly')
2142
+ const store = transaction.objectStore(STORE_NAME)
2143
+ const request = store.getAll()
2144
+
1964
2145
  request.onsuccess = () => {
1965
- imageDB = request.result
1966
- resolve(true)
2146
+ resolve(request.result || [])
2147
+ }
2148
+
2149
+ request.onerror = () => {
2150
+ console.error('获取所有图片失败:', request.error)
2151
+ resolve([])
2152
+ }
2153
+ })
2154
+ }
2155
+
2156
+ // 清理所有IndexedDB数据 //紧急情况使用
2157
+ async function clearAllIndexedDBData(): Promise<boolean> {
2158
+ return new Promise((resolve) => {
2159
+ try {
2160
+ // 先关闭现有连接
2161
+ if (imageDB) {
2162
+ imageDB.close()
2163
+ imageDB = null
2164
+ }
2165
+
2166
+ // 删除整个数据库
2167
+ const deleteRequest = indexedDB.deleteDatabase(DB_NAME)
2168
+
2169
+ deleteRequest.onsuccess = () => {
2170
+ console.log('IndexedDB数据库已完全清理')
2171
+ currentDbSize = 0
2172
+ currentImageCount = 0
2173
+ resolve(true)
2174
+ }
2175
+
2176
+ deleteRequest.onerror = () => {
2177
+ console.error('清理IndexedDB数据库失败:', deleteRequest.error)
2178
+ resolve(false)
2179
+ }
2180
+
2181
+ deleteRequest.onblocked = () => {
2182
+ console.warn('IndexedDB数据库删除被阻塞,可能有其他连接正在使用')
2183
+ // 等待一段时间后重试
2184
+ setTimeout(() => {
2185
+ resolve(false)
2186
+ }, 5000)
2187
+ }
2188
+ } catch (error) {
2189
+ console.error('清理数据库时出错:', error)
2190
+ resolve(false)
1967
2191
  }
2192
+ })
2193
+ }
2194
+
2195
+ // IndexedDB初始化
2196
+ async function initImageDB(): Promise<boolean> {
2197
+ try {
2198
+ // 首先尝试打开数据库
2199
+ const success = await openDatabase()
2200
+ if (!success) {
2201
+ console.warn('数据库打开失败,尝试清理后重新初始化')
2202
+ await clearAllIndexedDBData()
2203
+ return await openDatabase()
2204
+ }
2205
+
2206
+ // 数据库打开成功,进行初始健康检查
2207
+ setTimeout(async () => {
2208
+ const stats = await getDatabaseStats()
2209
+ console.log('数据库初始状态:', {
2210
+ 大小: `${(stats.totalSize / 1024 / 1024).toFixed(2)}MB`,
2211
+ 图片数量: stats.totalImages,
2212
+ 频道分布: stats.channelStats
2213
+ })
2214
+
2215
+ // 如果初始状态就超过限制,执行清理
2216
+ if (stats.totalSize > MAX_DB_SIZE * 0.9 || stats.totalImages > MAX_TOTAL_IMAGES * 0.9) {
2217
+ console.warn('数据库初始状态接近限制,执行清理')
2218
+ await performAutomaticCleanup()
2219
+ }
2220
+ }, 1000)
2221
+
2222
+ return true
2223
+ } catch (error) {
2224
+ console.error('IndexedDB初始化出错:', error)
2225
+ return false
2226
+ }
2227
+ }
2228
+
2229
+ // 打开数据库的内部函数
2230
+ async function openDatabase(): Promise<boolean> {
2231
+ return new Promise((resolve) => {
2232
+ try {
2233
+ const request = indexedDB.open(DB_NAME, DB_VERSION)
1968
2234
 
1969
- request.onupgradeneeded = (event) => {
1970
- const db = (event.target as IDBOpenDBRequest).result
2235
+ request.onerror = () => {
2236
+ console.error('IndexedDB打开失败:', request.error)
2237
+ resolve(false)
2238
+ }
2239
+
2240
+ request.onsuccess = () => {
2241
+ imageDB = request.result
2242
+
2243
+ // 添加错误处理
2244
+ imageDB.onerror = (event) => {
2245
+ console.error('IndexedDB运行时错误:', event)
2246
+ }
2247
+
2248
+ // 添加版本变更处理
2249
+ imageDB.onversionchange = () => {
2250
+ console.warn('IndexedDB版本变更,关闭连接')
2251
+ imageDB?.close()
2252
+ imageDB = null
2253
+ }
2254
+
2255
+ resolve(true)
2256
+ }
2257
+
2258
+ request.onupgradeneeded = (event) => {
2259
+ const db = (event.target as IDBOpenDBRequest).result
2260
+
2261
+ // 创建对象存储
2262
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
2263
+ const store = db.createObjectStore(STORE_NAME, { keyPath: 'url' })
2264
+ store.createIndex('channelKey', 'channelKey', { unique: false })
2265
+ store.createIndex('timestamp', 'timestamp', { unique: false })
2266
+ store.createIndex('size', 'size', { unique: false })
2267
+ console.log('IndexedDB对象存储创建完成')
2268
+ }
2269
+ }
1971
2270
 
1972
- // 创建对象存储
1973
- if (!db.objectStoreNames.contains(STORE_NAME)) {
1974
- const store = db.createObjectStore(STORE_NAME, { keyPath: 'url' })
1975
- store.createIndex('channelKey', 'channelKey', { unique: false })
1976
- store.createIndex('timestamp', 'timestamp', { unique: false })
2271
+ request.onblocked = () => {
2272
+ console.warn('IndexedDB打开被阻塞')
2273
+ resolve(false)
1977
2274
  }
2275
+ } catch (error) {
2276
+ console.error('打开数据库时出错:', error)
2277
+ resolve(false)
1978
2278
  }
1979
2279
  })
1980
2280
  }
@@ -2003,20 +2303,60 @@ async function getImageFromDB(url: string): Promise<ImageCacheItem | null> {
2003
2303
  async function saveImageToDB(item: ImageCacheItem): Promise<boolean> {
2004
2304
  if (!imageDB) return false
2005
2305
 
2006
- return new Promise((resolve) => {
2007
- const transaction = imageDB!.transaction([STORE_NAME], 'readwrite')
2008
- const store = transaction.objectStore(STORE_NAME)
2009
- const request = store.put(item)
2306
+ try {
2307
+ // 检查单张图片大小
2308
+ if (item.size > MAX_IMAGE_SIZE) {
2309
+ console.warn(`图片过大,跳过缓存: ${(item.size / 1024 / 1024).toFixed(2)}MB > ${(MAX_IMAGE_SIZE / 1024 / 1024).toFixed(2)}MB`)
2310
+ return false
2311
+ }
2010
2312
 
2011
- request.onsuccess = () => {
2012
- resolve(true)
2313
+ // 执行健康检查
2314
+ await checkDatabaseHealth()
2315
+
2316
+ // 检查是否会超过限制
2317
+ if (currentDbSize + item.size > MAX_DB_SIZE) {
2318
+ console.warn('添加图片会超过数据库大小限制,执行清理')
2319
+ await performAutomaticCleanup()
2320
+
2321
+ // 清理后再次检查
2322
+ if (currentDbSize + item.size > MAX_DB_SIZE) {
2323
+ console.warn('清理后仍会超过限制,跳过此图片')
2324
+ return false
2325
+ }
2013
2326
  }
2014
2327
 
2015
- request.onerror = () => {
2016
- console.error('保存图片到IndexedDB失败:', request.error)
2017
- resolve(false)
2328
+ if (currentImageCount >= MAX_TOTAL_IMAGES) {
2329
+ console.warn('图片数量已达上限,执行清理')
2330
+ await performAutomaticCleanup()
2331
+
2332
+ // 清理后再次检查
2333
+ if (currentImageCount >= MAX_TOTAL_IMAGES) {
2334
+ console.warn('清理后仍达上限,跳过此图片')
2335
+ return false
2336
+ }
2018
2337
  }
2019
- })
2338
+
2339
+ return new Promise((resolve) => {
2340
+ const transaction = imageDB!.transaction([STORE_NAME], 'readwrite')
2341
+ const store = transaction.objectStore(STORE_NAME)
2342
+ const request = store.put(item)
2343
+
2344
+ request.onsuccess = () => {
2345
+ // 更新统计
2346
+ currentDbSize += item.size
2347
+ currentImageCount += 1
2348
+ resolve(true)
2349
+ }
2350
+
2351
+ request.onerror = () => {
2352
+ console.error('保存图片到IndexedDB失败:', request.error)
2353
+ resolve(false)
2354
+ }
2355
+ })
2356
+ } catch (error) {
2357
+ console.error('保存图片时出错:', error)
2358
+ return false
2359
+ }
2020
2360
  }
2021
2361
 
2022
2362
  // 从IndexedDB删除图片
@@ -2118,22 +2458,10 @@ async function cacheImage(channelKey: string, originalUrl: string): Promise<stri
2118
2458
  const byteArray = new Uint8Array(byteNumbers)
2119
2459
  const blob = new Blob([byteArray], { type: contentType })
2120
2460
 
2121
- // 检查频道缓存数量限制
2122
- const channelImages = await getChannelImagesFromDB(channelKey)
2123
-
2124
- if (channelImages.length >= maxImagesPerChannel) {
2125
- // 清理最旧的图片缓存
2126
- const sortedImages = channelImages.sort((a, b) => a.timestamp - b.timestamp)
2127
- const toDelete = sortedImages.slice(0, channelImages.length - maxImagesPerChannel + 1)
2128
-
2129
- for (const item of toDelete) {
2130
- await deleteImageFromDB(item.url)
2131
- // 清理内存中的blob URL
2132
- if (imageBlobUrls.value[item.url]) {
2133
- URL.revokeObjectURL(imageBlobUrls.value[item.url])
2134
- delete imageBlobUrls.value[item.url]
2135
- }
2136
- }
2461
+ // 检查blob大小
2462
+ if (blob.size > MAX_IMAGE_SIZE) {
2463
+ console.warn(`图片过大,跳过缓存: ${(blob.size / 1024 / 1024).toFixed(2)}MB`)
2464
+ return null
2137
2465
  }
2138
2466
 
2139
2467
  // 创建缓存项
@@ -2369,7 +2697,7 @@ function handleMessageEvent(messageEvent: any) {
2369
2697
  chatData.value = { ...chatData.value }
2370
2698
  }
2371
2699
 
2372
- // 处理机器人发送消息成功事件(通过前端发送消息API触发)
2700
+ // 处理机器人发送消息成功事件
2373
2701
  function handleBotMessageSentEvent(sentEvent: any) {
2374
2702
  const channelKey = `${sentEvent.selfId}:${sentEvent.channelId}`
2375
2703
  if (!chatData.value.messages[channelKey]) {
@@ -2436,7 +2764,7 @@ function handleBotMessageSentEvent(sentEvent: any) {
2436
2764
  chatData.value = { ...chatData.value }
2437
2765
  }
2438
2766
 
2439
- // 处理机器人消息事件(通过before-send事件监听触发)
2767
+ // 处理机器人消息事件
2440
2768
  function handleBotMessageEvent(botMessageEvent: any) {
2441
2769
  // 更新机器人信息
2442
2770
  if (!chatData.value.bots[botMessageEvent.selfId]) {
@@ -2562,7 +2890,7 @@ function handleBotMessageEvent(botMessageEvent: any) {
2562
2890
  chatData.value = { ...chatData.value }
2563
2891
  }
2564
2892
 
2565
- // 监听消息变化,只在切换频道时自动滚动到底部
2893
+ // 监听消息变化
2566
2894
  watch(currentMessages, (newMessages, oldMessages) => {
2567
2895
  // 只有在切换频道时(消息数组完全不同)才自动滚动
2568
2896
  if (oldMessages.length === 0 && newMessages.length > 0) {
@@ -2830,6 +3158,18 @@ onMounted(async () => {
2830
3158
  const dbInitialized = await initImageDB()
2831
3159
  if (!dbInitialized) {
2832
3160
  console.warn('IndexedDB初始化失败,图片缓存功能将不可用')
3161
+ } else {
3162
+ console.log('IndexedDB初始化成功')
3163
+
3164
+ // 启动时进行健康检查
3165
+ setTimeout(async () => {
3166
+ await checkDatabaseHealth()
3167
+ }, 2000) // 延迟2秒,避免影响页面加载
3168
+
3169
+ // 设置定期健康检查(每5分钟)
3170
+ setInterval(async () => {
3171
+ await checkDatabaseHealth()
3172
+ }, 5 * 60 * 1000)
2833
3173
  }
2834
3174
 
2835
3175
  // 首先加载插件配置
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{defineComponent as Q,ref as f,onMounted as Ne,h as d,computed as O,watch as nt,nextTick as re,onUnmounted as Gt,createElementBlock as p,openBlock as v,normalizeStyle as Oe,normalizeClass as F,createElementVNode as c,createCommentVNode as G,Fragment as P,renderList as oe,createBlock as he,unref as me,toDisplayString as x,withDirectives as st,createTextVNode as Pe,vShow as Qt,withModifiers as lt,withKeys as Zt,vModelText as Et,resolveComponent as ea}from"vue";import{receive as Re,send as _,icons as ta}from"@koishijs/client";const aa={class:"bot-list"},na={class:"bot-items"},sa=["onClick","onContextmenu"],la={class:"bot-avatar"},ra={key:1,class:"avatar-placeholder"},oa={class:"bot-info"},ca={class:"bot-name"},ia={class:"bot-platform"},ua={class:"channel-list"},da={key:0,class:"empty-state"},fa={key:1,class:"channel-items"},ha=["data-channel-id","onClick","onContextmenu"],ma={class:"channel-info"},va={class:"channel-name"},ga={class:"channel-type"},ya=["onMousedown","onTouchstart","title"],pa={class:"message-area"},wa={class:"panel-header"},Ia={key:0,class:"empty-state"},xa={key:1,class:"message-content"},Ca={class:"message-avatar"},ka={key:1,class:"avatar-placeholder"},ba={class:"message-content-wrapper"},_a={class:"message-header"},$a={class:"message-username"},Sa={class:"message-time"},Ba={key:0,class:"message-quote"},La={class:"quote-header"},Ta={class:"quote-avatar"},qa={key:1,class:"avatar-placeholder"},Da={class:"quote-username"},Ua={class:"quote-time"},ja={class:"quote-content"},Ka={class:"message-text"},Na={class:"message-input"},Oa={key:0,class:"image-preview-container"},Pa=["src","alt"],Ra=["onClick"],Aa={class:"input-row"},Ma={class:"input-actions"},za=["placeholder","disabled"],Xa=["disabled"],rt=200,Ha=100*1024*1024,Ae=50,Fa="ChatImageCache",Ya=1,R="images",A=80,Wa=Q({__name:"index",setup(Z){function Y(e){try{return new URL(e).protocol==="file:"}catch{return false}}const E=Q({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),l=async()=>{try{a.value="loading";const o=await je(e.channelKey,e.src);if(o){t.value=o,a.value="loaded";return}const r=new Image;r.crossOrigin="anonymous",r.referrerPolicy="no-referrer",r.draggable=false;const i=new Promise((g,y)=>{r.onload=()=>g(),r.onerror=()=>y(new Error("Direct load failed")),r.src=e.src}),h=new Promise((g,y)=>{setTimeout(()=>y(new Error("Timeout")),3e3)});try{await Promise.race([i,h]),t.value=e.src,a.value="loaded",se(e.channelKey,e.src).catch(g=>{console.warn("异步缓存头像失败:",g)})}catch{await s()}}catch(o){console.error("头像加载失败:",o),a.value="error",n.value="头像加载失败"}},s=async()=>{try{a.value="caching";const o=await se(e.channelKey,e.src);if(o)t.value=o,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(o){console.error("缓存系统加载头像失败:",o),a.value="error",n.value=(o==null?void 0:o.message)||"缓存加载失败"}};return Ne(()=>{l()}),()=>{switch(a.value){case"loading":case"caching":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return d("img",{src:t.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),ce=Q({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),l=f(null),s=async()=>{try{a.value="loading";const r=await je(e.channelKey,e.src);if(r){t.value=r,a.value="loaded";return}if(Y(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await o();return}const i=new Image;i.crossOrigin="anonymous",i.referrerPolicy="no-referrer",i.draggable=false;const h=new Promise((y,q)=>{i.onload=()=>y(),i.onerror=()=>q(new Error("Direct load failed")),i.src=e.src}),g=new Promise((y,q)=>{setTimeout(()=>q(new Error("Timeout")),3e3)});try{await Promise.race([h,g]),t.value=e.src,a.value="loaded",se(e.channelKey,e.src).catch(y=>{console.warn("异步缓存图片失败:",y)})}catch{await o()}}catch(r){console.error("图片加载失败:",r),a.value="error",n.value="图片加载失败"}},o=async()=>{try{a.value="caching";const r=await se(e.channelKey,e.src);if(r)t.value=r,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(r){console.error("缓存系统加载图片失败:",r),a.value="error",n.value=(r==null?void 0:r.message)||"缓存加载失败"}};return Ne(()=>{s()}),()=>{switch(a.value){case"loading":return d("div",{class:"message-image-loading"},"加载中...");case"caching":return d("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return d("img",{src:t.value,alt:e.alt,class:"message-image",loading:"lazy",ref:l,draggable:false,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return d("div",{class:"message-image-error"},["图片加载失败",d("br"),d("small",e.filename||e.alt||"未知图片"),d("br"),d("small",{style:"color: #ff9800;"},n.value)]);default:return d("div",{class:"message-image-error"},"未知状态")}}}}),be=Q({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const t=(()=>{try{const l=JSON.parse(e.data);if(l.meta&&l.meta.detail_1){const s=l.meta.detail_1;return{type:"share_card",title:s.title||l.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:l}}catch(l){return console.error("解析JSON数据失败:",l),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{t.type==="share_card"&&t.url&&window.open(t.url,"_blank","noopener,noreferrer")};return()=>t.type==="share_card"&&t.preview?d("img",{src:t.preview,alt:t.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:t.url?"pointer":"default"},title:t.url?`点击打开: ${t.title||"链接"}`:t.title,onError:l=>{const o=l.target.parentElement;o&&(o.style.display="none")}}):t.type==="error"?d("div",{class:"message-json-error"},[d("span",{class:"json-error-text"},t.error),d("details",{class:"json-raw-data"},[d("summary","查看原始数据"),d("pre",{class:"json-raw-content"},e.data)])]):d("div",{class:"message-json-raw"},[d("div",{class:"json-label"},"[JSON数据]"),d("details",{class:"json-raw-data"},[d("summary","查看详情"),d("pre",{class:"json-raw-content"},JSON.stringify(t.data,null,2))])])}}),ct=Q({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=f(false),t=()=>{a.value=!a.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(i=>i.type==="message"),o=s.length;return{previews:s.slice(0,3).map(i=>{var y,q;const h=((y=i.attrs)==null?void 0:y.nickname)||"用户";let g="";if(i.children&&i.children.length>0){const B=i.children[0];B.type==="text"?(g=(((q=B.attrs)==null?void 0:q.content)||"").substring(0,20),g.length>15&&(g+="...")):B.type==="img"?g="[图片]":B.type==="video"?g="[视频]":g=`[${B.type}]`}return`${h}:${g}`}),messageCount:o}},l=(s,o)=>{var h,g,y;const r=((h=s.attrs)==null?void 0:h.nickname)||"用户",i=((g=s.attrs)==null?void 0:g.userId)||"unknown";return d("div",{key:o,class:"forwarded-message-item"},[d("div",{class:"forwarded-message-header"},[d("span",{class:"forwarded-message-nickname"},r),d("span",{class:"forwarded-message-userid"},`(${i})`)]),d("div",{class:"forwarded-message-content"},((y=s.children)==null?void 0:y.map((q,B)=>d(ve,{key:B,element:q,channelKey:e.channelKey})))||[])])};return()=>{var r;const{previews:s,messageCount:o}=n();return d("div",{class:"forward-message-container"},[d("div",{class:"forward-message-preview",onClick:t},[d("div",{class:"forward-message-title"},"聊天记录"),...s.map((i,h)=>d("div",{key:h,class:"forward-message-preview-item"},i)),d("div",{class:"forward-message-footer"},[d("span",{class:"forward-message-count"},`查看${o}条转发消息`),d("span",{class:"forward-message-toggle"},a.value?"▲":"▼")])]),a.value&&d("div",{class:"forward-message-expanded"},((r=e.element.children)==null?void 0:r.filter(i=>i.type==="message").map((i,h)=>l(i,h)))||[])])}}}),ve=Q({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=t=>{var n,l,s,o,r,i;switch(t.type){case"text":return d("span",{class:"message-text-content"},t.attrs.content||"");case"forward":return d("span",{class:"message-text-content"},`[转发消息 ${t.attrs.id}]`||"[转发消息]");case"img":case"image":const h=t.attrs.src||t.attrs.url||t.attrs.file;return h&&Y(h)?console.log("检测到本地文件路径:",h):h!=null&&h.startsWith("http")?console.log("检测到网络图片:",h):console.log("检测到其他类型图片URL:",h),d("div",{class:"message-image-container"},[d(ce,{src:h,alt:t.attrs.summary||"图片",filename:t.attrs.filename||t.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const g=t.attrs.src||t.attrs.url||t.attrs.file;return g&&Y(g)&&console.log("检测到本地表情文件路径:",g),d("div",{class:"message-image-container"},[d(ce,{src:g,alt:t.attrs.summary||"表情",filename:t.attrs.emojiId||t.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((l=(n=t.children[0])==null?void 0:n.attrs)!=null&&l.src){const y=((o=(s=t.children[0])==null?void 0:s.attrs)==null?void 0:o.src)||((i=(r=t.children[0])==null?void 0:r.attrs)==null?void 0:i.url);return d("div",{class:"message-image-container"},[d(ce,{src:y,alt:t.attrs.name||t.attrs.id||"[表情]",filename:t.attrs.name||t.attrs.id||"[表情]",channelKey:e.channelKey})])}else return d("span",{class:"message-text-content"},`[${t.attrs.name||t.attrs.id}]`||"[表情]");case"at":return d("span",{class:"message-at",title:t.attrs.name},`${t.attrs.name||t.attrs.id}`);case"json":return d("div",{class:"message-image-container"},[d(be,{data:t.attrs.data||"",channelKey:e.channelKey})]);case"p":if(t.children&&t.children.length>0){const y=t.children.map((q,B)=>d(ve,{key:B,element:q,channelKey:e.channelKey}));return d("div",{class:"message-paragraph"},y)}else return d("div",{class:"message-paragraph"},"");case"figure":return d(ct,{element:t,channelKey:e.channelKey});default:return d("span",{class:"message-unknown",title:`未知消息类型: ${t.type}`},t.attrs.content||`[${t.type}]`)}};return()=>a(e.element)}}),u=f({bots:{},channels:{},messages:{}}),D=f({}),ie=f({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=f({});let _e=0;function Me(e){return e.size||0}function ge(e){_e+=e,ie.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(_e/1024/1024).toFixed(2)}MB`)}function ze(e=10){const a=Object.entries(b.value);if(a.length<=e)return;const t=a.slice(0,a.length-e);let n=0;t.forEach(([l,s])=>{URL.revokeObjectURL(s),delete b.value[l],n+=500*1024,ie.value.loggerinfo&&console.log("清理旧blob URL:",l)}),ge(-n)}function $e(){Object.keys(b.value).length>Ae&&ze(Math.floor(Ae*.7)),_e>Ha&&ze(Math.floor(Ae*.5))}let S=null;const m=f(""),C=f(""),ue=f(""),U=f([]),J=f(false),Se=f(),L=f(false),W=f("bots"),M=f(null),ee=f(null),Be=f(false),V=f({show:false,text:""}),$=f(),de=f(),Le=f(false),ye=f(false),te=f(false),z=f(""),j=f({x:0,y:0}),T=f({x:0,y:0}),Xe=f({x:0,y:0}),Te=f({x:0,y:0}),qe=f(0),K=f(null),ae=f(false),w=f(null),I=f({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),X=f(new Set),H=f(new Set),it=O(()=>Object.values(u.value.bots).sort((a,t)=>{const n=X.value.has(a.selfId),l=X.value.has(t.selfId);return n&&!l?-1:!n&&l?1:0})),ut=O(()=>!m.value||!u.value.channels[m.value]?[]:Object.values(u.value.channels[m.value]).sort((a,t)=>{const n=H.value.has(`${m.value}:${a.id}`),l=H.value.has(`${m.value}:${t.id}`);return n&&!l?-1:!n&&l?1:0})),He=O(()=>{if(!m.value||!C.value)return[];const e=`${m.value}:${C.value}`,a=u.value.messages[e]||[];return a.filter(t=>t.quote),a}),dt=O(()=>{var a;if(!m.value||!C.value)return"";const e=u.value.channels[m.value];return((a=e==null?void 0:e[C.value])==null?void 0:a.name)||""}),pe=O(()=>!m.value||!C.value?"":`${m.value}:${C.value}`),Fe=O(()=>m.value&&C.value&&(ue.value.trim()||U.value.length>0)&&!te.value),ft=O(()=>m.value&&C.value&&!te.value),ht=O(()=>{if(!L.value)return"";switch(W.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),mt=O(()=>L.value?"输入消息...(屏幕左滑返回)":"输入消息..."),vt=O(()=>{if(L.value){const e=ie.value.chatContainerHeight||80,a=100-e-19;return{height:`${e}vh`,marginTop:`${a}vh`}}return{}});function gt(e){m.value=e,C.value="",L.value&&(W.value="channels")}function yt(e,a){if(e.preventDefault(),e.stopPropagation(),I.value.show&&I.value.type==="bot"&&I.value.targetId===a){N();return}Ye(e,"bot",a)}function pt(e,a){if(e.preventDefault(),e.stopPropagation(),I.value.show&&I.value.type==="channel"&&I.value.targetId===a){N();return}Ye(e,"channel",a)}function Ye(e,a,t){let s=e.clientX,o=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),o+80>window.innerHeight&&(o=window.innerHeight-80-10),I.value={show:true,x:s,y:o,type:a,targetId:t,isSecondClick:false},document.addEventListener("click",N,{once:true}),document.addEventListener("keydown",We)}function N(){I.value.show=false,document.removeEventListener("click",N),document.removeEventListener("keydown",We)}function We(e){e.key==="Escape"&&I.value.show&&N()}async function wt(e){X.value.has(e)?X.value.delete(e):X.value.add(e),await _("set-pinned-bots",{pinnedBots:Array.from(X.value)}),N()}async function It(e){const a=`${m.value}:${e}`;H.value.has(a)?H.value.delete(a):H.value.add(a),await _("set-pinned-channels",{pinnedChannels:Array.from(H.value)}),N()}async function xt(e){try{const a=await _("delete-bot-data",{selfId:e});if(a.success){const t=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of t)delete u.value.messages[n],delete D.value[n],await ke(n);delete u.value.bots[e],delete u.value.channels[e],m.value===e&&(m.value="",C.value=""),k(a.message||"已删除该机器人的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除机器人数据失败:",a),k("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}N()}async function Ct(e){try{const a=await _("delete-channel-data",{selfId:m.value,channelId:e});if(a.success){const t=`${m.value}:${e}`;delete u.value.messages[t],delete D.value[t],u.value.channels[m.value]&&delete u.value.channels[m.value][e],await ke(t),C.value===e&&(C.value=""),k(a.message||"已删除该频道的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除频道数据失败:",a),k("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}N()}async function kt(e){C.value=e,ye.value=false,L.value&&(W.value="messages"),m.value&&await Xt(m.value,e),re(()=>{ne(),!L.value&&de.value&&de.value.focus()})}async function Je(){if(!Fe.value)return;const e=ue.value.trim();if(!e&&U.value.length===0)return;te.value=true;const a=[...U.value];try{const t=await _("send-message",{selfId:m.value,channelId:C.value,content:e,images:a.map(n=>({tempId:n.tempId,filename:n.filename}))});if(t.success){if(ue.value="",a.forEach(n=>{URL.revokeObjectURL(n.preview)}),U.value=[],J.value=false,t.tempImageIds&&t.tempImageIds.length>0)try{await _("cleanup-temp-images",{tempImageIds:t.tempImageIds}),console.log("临时图片清理完成:",t.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",t.error),k("发送失败: "+t.error,"error")}catch(t){console.error("发送消息时出错:",t),k("发送失败: "+((t==null?void 0:t.message)||String(t)),"error")}finally{te.value=false}}function bt(){J.value=!J.value}function _t(){Se.value&&Se.value.click(),J.value=false}async function $t(e){const a=e.target,t=a.files;if(!(!t||t.length===0)){for(const n of Array.from(t))await Ve(n);a.value=""}}async function St(e){var t;const a=(t=e.clipboardData)==null?void 0:t.items;if(a){for(const n of Array.from(a))if(n.type.startsWith("image/")){e.preventDefault();const l=n.getAsFile();l&&await Ve(l)}}}async function Ve(e){try{if(e.size>10*1024*1024){k("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){k("请选择图片文件","error");return}const a=await Lt(e),t=URL.createObjectURL(e),n=await _("upload-image",{file:a,filename:e.name,mimeType:e.type});n.success?U.value.push({tempId:n.tempId,filename:e.name,preview:t,size:e.size}):(URL.revokeObjectURL(t),k("图片上传失败: "+n.error,"error"))}catch(a){console.error("上传图片失败:",a),k("图片上传失败: "+((a==null?void 0:a.message)||String(a)),"error")}}async function Bt(e){try{const a=U.value.findIndex(t=>t.tempId===e);if(a!==-1){const t=U.value[a];URL.revokeObjectURL(t.preview),U.value.splice(a,1)}await _("delete-temp-image",{tempId:e})}catch(a){console.error("删除图片失败:",a)}}function Lt(e){return new Promise((a,t)=>{const n=new FileReader;n.onload=()=>a(n.result),n.onerror=t,n.readAsDataURL(e)})}function Ge(e){const a=e.target;a.closest(".input-actions")||(J.value=false),a.closest(".context-menu")||N()}function Qe(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function Tt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function ne(){$.value&&($.value.scrollTop=$.value.scrollHeight,Le.value=false,ye.value=false)}function we(){if($.value){const{scrollTop:e,scrollHeight:a,clientHeight:t}=$.value,l=a-(e+t)<=50,s=!l;Le.value=s,l?ye.value=false:ye.value=true}}function De(){if(!$.value)return true;const{scrollTop:e,scrollHeight:a,clientHeight:t}=$.value;return a-(e+t)<=200}function Ue(e){var n;if(!m.value)return 0;const a=`${m.value}:${e}`,t=D.value[a];return t!==void 0?t:((n=u.value.messages[a])==null?void 0:n.length)||0}function Ze(e,a){e.preventDefault(),e.stopPropagation();const t="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;qe.value=Date.now(),j.value={x:t,y:n},T.value={x:t,y:n},ae.value=false;const s=e.target.getBoundingClientRect();Xe.value={x:s.left,y:s.top},Te.value={x:t-s.left,y:n-s.top},K.value=window.setTimeout(()=>{if(qe.value>0){ae.value=true,z.value=a;const o=e.target,r=o.cloneNode(true);r.classList.add("dragging-clone"),r.style.position="fixed",r.style.zIndex="1000",r.style.pointerEvents="none";const i=o.getBoundingClientRect();r.style.left=`${i.left}px`,r.style.top=`${i.top}px`,r.style.width=`${i.width}px`,r.style.height=`${i.height}px`,document.body.appendChild(r),w.value=r,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),Ut(j.value.x,j.value.y)}},60),document.addEventListener("mousemove",Ie),document.addEventListener("mouseup",xe),document.addEventListener("touchmove",Ie),document.addEventListener("touchend",xe)}function Ie(e){if(!ae.value||!w.value)return;e.preventDefault();const a="touches"in e?e.touches[0].clientX:e.clientX,t="touches"in e?e.touches[0].clientY:e.clientY;T.value={x:a,y:t};const n=T.value.x-j.value.x,l=T.value.y-j.value.y,s=Math.sqrt(n*n+l*l),o=Math.max(.3,1-s/(A*2)),r=Math.max(.8,1-s/(A*3)),i=s>A,h=T.value.x-Te.value.x,g=T.value.y-Te.value.y;w.value.style.left=`${h}px`,w.value.style.top=`${g}px`,w.value.style.transform=`scale(${r})`,w.value.style.opacity=`${o}`,w.value.style.backgroundColor=i?"#f44336":"#2196f3",w.value.style.boxShadow=i?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",i?w.value.classList.add("will-delete"):w.value.classList.remove("will-delete")}function xe(e){if(K.value&&(clearTimeout(K.value),K.value=null),K.value&&(clearTimeout(K.value),K.value=null),!ae.value||!z.value){Ce();return}const a=z.value;if(Math.sqrt(Math.pow(T.value.x-j.value.x,2)+Math.pow(T.value.y-j.value.y,2))>A)Dt(a),Ce();else if(w.value){w.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${a}"] .channel-message-count`);if(n){const l=n.getBoundingClientRect();w.value.style.left=`${l.left}px`,w.value.style.top=`${l.top}px`,w.value.style.transform="scale(1)",w.value.style.opacity="1",w.value.style.backgroundColor="#2196f3",w.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{Ce()},300)}else Ce()}function Ce(){K.value&&(clearTimeout(K.value),K.value=null),z.value="",j.value={x:0,y:0},T.value={x:0,y:0},Xe.value={x:0,y:0},qe.value=0,ae.value=false,document.removeEventListener("mousemove",Ie),document.removeEventListener("mouseup",xe),document.removeEventListener("touchmove",Ie),document.removeEventListener("touchend",xe),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),w.value&&w.value.parentNode&&(w.value.parentNode.removeChild(w.value),w.value=null),jt()}function qt(e){return z.value===e&&ae.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function Ee(e){if(z.value!==e)return 0;const a=T.value.x-j.value.x,t=T.value.y-j.value.y;return Math.sqrt(a*a+t*t)}async function Dt(e){if(m.value)try{const a=`${m.value}:${e}`,t=Ue(e),n=ie.value.keepMessagesOnClear;if(n>0&&t<=n){k("当前消息还很少诶~ 无需清理","success");return}const l=await _("clear-channel-history",{selfId:m.value,channelId:e});if(l.success)if(l.clearedCount&&l.clearedCount>0){if(u.value.messages[a]){const o=[...u.value.messages[a]].sort((r,i)=>r.timestamp-i.timestamp);u.value.messages[a]=o.slice(-l.keptCount)}D.value[a]=l.keptCount,await ke(a),k(`历史记录已清理,清理了 ${l.clearedCount} 条消息,保留最新 ${l.keptCount} 条`,"success")}else n===0?(u.value.messages[a]&&(u.value.messages[a]=[]),D.value[a]=0,await ke(a),k("历史记录已清理,所有消息已删除","success")):k("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",l.error),k("清理失败: "+l.error,"error")}catch(a){console.error("清理历史记录时出错:",a),k("清理失败: "+((a==null?void 0:a.message)||String(a)),"error")}}function k(e,a="success"){const t=document.createElement("div");t.className=`notification ${a}`,t.textContent=e;let n="#4caf50";switch(a){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}t.style.cssText=`
1
+ import{defineComponent as E,ref as f,onMounted as Pe,h as d,computed as O,watch as dt,nextTick as oe,onUnmounted as oa,createElementBlock as p,openBlock as v,normalizeStyle as Me,normalizeClass as W,createElementVNode as i,createCommentVNode as Q,Fragment as z,renderList as ce,createBlock as ve,unref as ge,toDisplayString as C,withDirectives as ft,createTextVNode as He,vShow as ca,withModifiers as ht,withKeys as ia,vModelText as ua,resolveComponent as da}from"vue";import{receive as Fe,send as S,icons as fa}from"@koishijs/client";const ha={class:"bot-list"},ma={class:"bot-items"},va=["onClick","onContextmenu"],ga={class:"bot-avatar"},ya={key:1,class:"avatar-placeholder"},pa={class:"bot-info"},wa={class:"bot-name"},Ia={class:"bot-platform"},xa={class:"channel-list"},Ca={key:0,class:"empty-state"},ka={key:1,class:"channel-items"},ba=["data-channel-id","onClick","onContextmenu"],_a={class:"channel-info"},$a={class:"channel-name"},Sa={class:"channel-type"},Ba=["onMousedown","onTouchstart","title"],Da={class:"message-area"},La={class:"panel-header"},Ta={key:0,class:"empty-state"},qa={key:1,class:"message-content"},Ka={class:"message-avatar"},Ua={key:1,class:"avatar-placeholder"},ja={class:"message-content-wrapper"},Aa={class:"message-header"},Na={class:"message-username"},Ra={class:"message-time"},Oa={key:0,class:"message-quote"},za={class:"quote-header"},Pa={class:"quote-avatar"},Ma={key:1,class:"avatar-placeholder"},Ha={class:"quote-username"},Fa={class:"quote-time"},Xa={class:"quote-content"},Ya={class:"message-text"},Wa={class:"message-input"},Ja={key:0,class:"image-preview-container"},Va=["src","alt"],Ga=["onClick"],Za={class:"input-row"},Qa={class:"input-actions"},Ea=["placeholder","disabled"],en=["disabled"],tn=100*1024*1024,Xe=50,mt="ChatImageCache",an=2,B="images",ie=50*1024*1024,vt=100,ue=500,Ye=2*1024*1024,gt=.8,nn=60*1e3,P=80,sn=E({__name:"index",setup(ee){function J(e){try{return new URL(e).protocol==="file:"}catch{return false}}const te=E({props:{src:{type:String,required:true},alt:{type:String,default:"头像"},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=async()=>{try{a.value="loading";const o=await Oe(e.channelKey,e.src);if(o){t.value=o,a.value="loaded";return}const l=new Image;l.crossOrigin="anonymous",l.referrerPolicy="no-referrer",l.draggable=false;const c=new Promise((y,g)=>{l.onload=()=>y(),l.onerror=()=>g(new Error("Direct load failed")),l.src=e.src}),h=new Promise((y,g)=>{setTimeout(()=>g(new Error("Timeout")),3e3)});try{await Promise.race([c,h]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(y=>{console.warn("异步缓存头像失败:",y)})}catch{await s()}}catch(o){console.error("头像加载失败:",o),a.value="error",n.value="头像加载失败"}},s=async()=>{try{a.value="caching";const o=await le(e.channelKey,e.src);if(o)t.value=o,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(o){console.error("缓存系统加载头像失败:",o),a.value="error",n.value=(o==null?void 0:o.message)||"缓存加载失败"}};return Pe(()=>{r()}),()=>{switch(a.value){case"loading":case"caching":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());case"loaded":return d("img",{src:t.value,alt:e.alt,draggable:false,style:{width:"100%",height:"100%","object-fit":"cover"}});case"error":return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase());default:return d("div",{class:"avatar-placeholder"},e.alt.charAt(0).toUpperCase())}}}}),de=E({props:{src:{type:String,required:true},alt:{type:String,default:"图片"},filename:{type:String,default:""},channelKey:{type:String,required:true}},setup(e){const a=f("loading"),t=f(e.src),n=f(""),r=f(null),s=async()=>{try{a.value="loading";const l=await Oe(e.channelKey,e.src);if(l){t.value=l,a.value="loaded";return}if(J(e.src)){console.log("ImageComponent: 检测到本地文件,使用代理请求:",e.src),await o();return}const c=new Image;c.crossOrigin="anonymous",c.referrerPolicy="no-referrer",c.draggable=false;const h=new Promise((g,L)=>{c.onload=()=>g(),c.onerror=()=>L(new Error("Direct load failed")),c.src=e.src}),y=new Promise((g,L)=>{setTimeout(()=>L(new Error("Timeout")),3e3)});try{await Promise.race([h,y]),t.value=e.src,a.value="loaded",le(e.channelKey,e.src).catch(g=>{console.warn("异步缓存图片失败:",g)})}catch{await o()}}catch(l){console.error("图片加载失败:",l),a.value="error",n.value="图片加载失败"}},o=async()=>{try{a.value="caching";const l=await le(e.channelKey,e.src);if(l)t.value=l,a.value="loaded";else throw new Error("缓存系统加载失败")}catch(l){console.error("缓存系统加载图片失败:",l),a.value="error",n.value=(l==null?void 0:l.message)||"缓存加载失败"}};return Pe(()=>{s()}),()=>{switch(a.value){case"loading":return d("div",{class:"message-image-loading"},"加载中...");case"caching":return d("div",{class:"message-image-loading"},"[图片加载缓存中...]");case"loaded":return d("img",{src:t.value,alt:e.alt,class:"message-image",loading:"lazy",ref:r,draggable:false,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain"}});case"error":return d("div",{class:"message-image-error"},["图片加载失败",d("br"),d("small",e.filename||e.alt||"未知图片"),d("br"),d("small",{style:"color: #ff9800;"},n.value)]);default:return d("div",{class:"message-image-error"},"未知状态")}}}}),Se=E({props:{data:{type:String,required:true},channelKey:{type:String,required:true}},setup(e){const t=(()=>{try{const r=JSON.parse(e.data);if(r.meta&&r.meta.detail_1){const s=r.meta.detail_1;return{type:"share_card",title:s.title||r.prompt||"分享内容",desc:s.desc||"",preview:s.preview?s.preview.replace(/\\\//g,"/"):"",icon:s.icon?s.icon.replace(/\\\//g,"/"):"",url:s.qqdocurl?s.qqdocurl.replace(/\\\//g,"/"):s.url?s.url.replace(/\\\//g,"/"):"",appName:s.title||"应用"}}return{type:"raw",data:r}}catch(r){return console.error("解析JSON数据失败:",r),{type:"error",error:"无法解析的JSON数据"}}})(),n=()=>{t.type==="share_card"&&t.url&&window.open(t.url,"_blank","noopener,noreferrer")};return()=>t.type==="share_card"&&t.preview?d("img",{src:t.preview,alt:t.title||"[分享小程序]",class:"message-image",loading:"lazy",draggable:false,onClick:n,style:{"max-width":"400px","max-height":"200px",width:"auto",height:"auto","object-fit":"contain",cursor:t.url?"pointer":"default"},title:t.url?`点击打开: ${t.title||"链接"}`:t.title,onError:r=>{const o=r.target.parentElement;o&&(o.style.display="none")}}):t.type==="error"?d("div",{class:"message-json-error"},[d("span",{class:"json-error-text"},t.error),d("details",{class:"json-raw-data"},[d("summary","查看原始数据"),d("pre",{class:"json-raw-content"},e.data)])]):d("div",{class:"message-json-raw"},[d("div",{class:"json-label"},"[JSON数据]"),d("details",{class:"json-raw-data"},[d("summary","查看详情"),d("pre",{class:"json-raw-content"},JSON.stringify(t.data,null,2))])])}}),pt=E({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=f(false),t=()=>{a.value=!a.value},n=()=>{if(!e.element.children||e.element.children.length===0)return{previews:[],messageCount:0};const s=e.element.children.filter(c=>c.type==="message"),o=s.length;return{previews:s.slice(0,3).map(c=>{var g,L;const h=((g=c.attrs)==null?void 0:g.nickname)||"用户";let y="";if(c.children&&c.children.length>0){const $=c.children[0];$.type==="text"?(y=(((L=$.attrs)==null?void 0:L.content)||"").substring(0,20),y.length>15&&(y+="...")):$.type==="img"?y="[图片]":$.type==="video"?y="[视频]":y=`[${$.type}]`}return`${h}:${y}`}),messageCount:o}},r=(s,o)=>{var h,y,g;const l=((h=s.attrs)==null?void 0:h.nickname)||"用户",c=((y=s.attrs)==null?void 0:y.userId)||"unknown";return d("div",{key:o,class:"forwarded-message-item"},[d("div",{class:"forwarded-message-header"},[d("span",{class:"forwarded-message-nickname"},l),d("span",{class:"forwarded-message-userid"},`(${c})`)]),d("div",{class:"forwarded-message-content"},((g=s.children)==null?void 0:g.map((L,$)=>d(ye,{key:$,element:L,channelKey:e.channelKey})))||[])])};return()=>{var l;const{previews:s,messageCount:o}=n();return d("div",{class:"forward-message-container"},[d("div",{class:"forward-message-preview",onClick:t},[d("div",{class:"forward-message-title"},"聊天记录"),...s.map((c,h)=>d("div",{key:h,class:"forward-message-preview-item"},c)),d("div",{class:"forward-message-footer"},[d("span",{class:"forward-message-count"},`查看${o}条转发消息`),d("span",{class:"forward-message-toggle"},a.value?"▲":"▼")])]),a.value&&d("div",{class:"forward-message-expanded"},((l=e.element.children)==null?void 0:l.filter(c=>c.type==="message").map((c,h)=>r(c,h)))||[])])}}}),ye=E({props:{element:{type:Object,required:true},channelKey:{type:String,required:true}},setup(e){const a=t=>{var n,r,s,o,l,c;switch(t.type){case"text":return d("span",{class:"message-text-content"},t.attrs.content||"");case"forward":return d("span",{class:"message-text-content"},`[转发消息 ${t.attrs.id}]`||"[转发消息]");case"img":case"image":const h=t.attrs.src||t.attrs.url||t.attrs.file;return h&&J(h)?console.log("检测到本地文件路径:",h):h!=null&&h.startsWith("http")?console.log("检测到网络图片:",h):console.log("检测到其他类型图片URL:",h),d("div",{class:"message-image-container"},[d(de,{src:h,alt:t.attrs.summary||"图片",filename:t.attrs.filename||t.attrs.summary||"",channelKey:e.channelKey})]);case"mface":const y=t.attrs.src||t.attrs.url||t.attrs.file;return y&&J(y)&&console.log("检测到本地表情文件路径:",y),d("div",{class:"message-image-container"},[d(de,{src:y,alt:t.attrs.summary||"表情",filename:t.attrs.emojiId||t.attrs.summary||"",channelKey:e.channelKey})]);case"face":if((r=(n=t.children[0])==null?void 0:n.attrs)!=null&&r.src){const g=((o=(s=t.children[0])==null?void 0:s.attrs)==null?void 0:o.src)||((c=(l=t.children[0])==null?void 0:l.attrs)==null?void 0:c.url);return d("div",{class:"message-image-container"},[d(de,{src:g,alt:t.attrs.name||t.attrs.id||"[表情]",filename:t.attrs.name||t.attrs.id||"[表情]",channelKey:e.channelKey})])}else return d("span",{class:"message-text-content"},`[${t.attrs.name||t.attrs.id}]`||"[表情]");case"at":return d("span",{class:"message-at",title:t.attrs.name},`${t.attrs.name||t.attrs.id}`);case"json":return d("div",{class:"message-image-container"},[d(Se,{data:t.attrs.data||"",channelKey:e.channelKey})]);case"p":if(t.children&&t.children.length>0){const g=t.children.map((L,$)=>d(ye,{key:$,element:L,channelKey:e.channelKey}));return d("div",{class:"message-paragraph"},g)}else return d("div",{class:"message-paragraph"},"");case"figure":return d(pt,{element:t,channelKey:e.channelKey});default:return d("span",{class:"message-unknown",title:`未知消息类型: ${t.type}`},t.attrs.content||`[${t.type}]`)}};return()=>a(e.element)}}),u=f({bots:{},channels:{},messages:{}}),K=f({}),fe=f({maxMessagesPerChannel:1e3,keepMessagesOnClear:50,loggerinfo:false,blockedPlatforms:[],chatContainerHeight:80}),b=f({});let Be=0,w=null,U=0,M=0,We=0;const m=f(""),k=f(""),he=f("");function Je(e){return e.size||0}function pe(e){Be+=e,fe.value.loggerinfo&&console.log(`内存使用量变化: ${e>0?"+":""}${(e/1024/1024).toFixed(2)}MB, 总计: ${(Be/1024/1024).toFixed(2)}MB`)}function Ve(e=10){const a=Object.entries(b.value);if(a.length<=e)return;const t=a.slice(0,a.length-e);let n=0;t.forEach(([r,s])=>{URL.revokeObjectURL(s),delete b.value[r],n+=500*1024,fe.value.loggerinfo&&console.log("清理旧blob URL:",r)}),pe(-n)}function De(){Object.keys(b.value).length>Xe&&Ve(Math.floor(Xe*.7)),Be>tn&&Ve(Math.floor(Xe*.5))}const j=f([]),G=f(false),Le=f(),T=f(false),V=f("bots"),H=f(null),ae=f(null),Te=f(false),Z=f({show:false,text:""}),D=f(),me=f(),qe=f(false),we=f(false),ne=f(false),F=f(""),A=f({x:0,y:0}),q=f({x:0,y:0}),Ge=f({x:0,y:0}),Ke=f({x:0,y:0}),Ue=f(0),N=f(null),se=f(false),I=f(null),x=f({show:false,x:0,y:0,type:null,targetId:"",isSecondClick:false}),X=f(new Set),Y=f(new Set),wt=O(()=>Object.values(u.value.bots).sort((a,t)=>{const n=X.value.has(a.selfId),r=X.value.has(t.selfId);return n&&!r?-1:!n&&r?1:0})),It=O(()=>!m.value||!u.value.channels[m.value]?[]:Object.values(u.value.channels[m.value]).sort((a,t)=>{const n=Y.value.has(`${m.value}:${a.id}`),r=Y.value.has(`${m.value}:${t.id}`);return n&&!r?-1:!n&&r?1:0})),Ze=O(()=>{if(!m.value||!k.value)return[];const e=`${m.value}:${k.value}`,a=u.value.messages[e]||[];return a.filter(t=>t.quote),a}),xt=O(()=>{var a;if(!m.value||!k.value)return"";const e=u.value.channels[m.value];return((a=e==null?void 0:e[k.value])==null?void 0:a.name)||""}),Ie=O(()=>!m.value||!k.value?"":`${m.value}:${k.value}`),Qe=O(()=>m.value&&k.value&&(he.value.trim()||j.value.length>0)&&!ne.value),Ct=O(()=>m.value&&k.value&&!ne.value),kt=O(()=>{if(!T.value)return"";switch(V.value){case"channels":return"show-channels";case"messages":return"show-messages";default:return""}}),bt=O(()=>T.value?"输入消息...(屏幕左滑返回)":"输入消息..."),_t=O(()=>{if(T.value){const e=fe.value.chatContainerHeight||80,a=100-e-19;return{height:`${e}vh`,marginTop:`${a}vh`}}return{}});function $t(e){m.value=e,k.value="",T.value&&(V.value="channels")}function St(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="bot"&&x.value.targetId===a){R();return}Ee(e,"bot",a)}function Bt(e,a){if(e.preventDefault(),e.stopPropagation(),x.value.show&&x.value.type==="channel"&&x.value.targetId===a){R();return}Ee(e,"channel",a)}function Ee(e,a,t){let s=e.clientX,o=e.clientY;s+180>window.innerWidth&&(s=window.innerWidth-180-10),o+80>window.innerHeight&&(o=window.innerHeight-80-10),x.value={show:true,x:s,y:o,type:a,targetId:t,isSecondClick:false},document.addEventListener("click",R,{once:true}),document.addEventListener("keydown",et)}function R(){x.value.show=false,document.removeEventListener("click",R),document.removeEventListener("keydown",et)}function et(e){e.key==="Escape"&&x.value.show&&R()}async function Dt(e){X.value.has(e)?X.value.delete(e):X.value.add(e),await S("set-pinned-bots",{pinnedBots:Array.from(X.value)}),R()}async function Lt(e){const a=`${m.value}:${e}`;Y.value.has(a)?Y.value.delete(a):Y.value.add(a),await S("set-pinned-channels",{pinnedChannels:Array.from(Y.value)}),R()}async function Tt(e){try{const a=await S("delete-bot-data",{selfId:e});if(a.success){const t=Object.keys(u.value.messages).filter(n=>n.startsWith(`${e}:`));for(const n of t)delete u.value.messages[n],delete K.value[n],await $e(n);delete u.value.bots[e],delete u.value.channels[e],m.value===e&&(m.value="",k.value=""),_(a.message||"已删除该机器人的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除机器人数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}R()}async function qt(e){try{const a=await S("delete-channel-data",{selfId:m.value,channelId:e});if(a.success){const t=`${m.value}:${e}`;delete u.value.messages[t],delete K.value[t],u.value.channels[m.value]&&delete u.value.channels[m.value][e],await $e(t),k.value===e&&(k.value=""),_(a.message||"已删除该频道的所有数据","success")}else throw new Error(a.error||"删除失败")}catch(a){console.error("删除频道数据失败:",a),_("删除失败: "+((a==null?void 0:a.message)||String(a)),"error")}R()}async function Kt(e){k.value=e,we.value=false,T.value&&(V.value="messages"),m.value&&await aa(m.value,e),oe(()=>{re(),!T.value&&me.value&&me.value.focus()})}async function tt(){if(!Qe.value)return;const e=he.value.trim();if(!e&&j.value.length===0)return;ne.value=true;const a=[...j.value];try{const t=await S("send-message",{selfId:m.value,channelId:k.value,content:e,images:a.map(n=>({tempId:n.tempId,filename:n.filename}))});if(t.success){if(he.value="",a.forEach(n=>{URL.revokeObjectURL(n.preview)}),j.value=[],G.value=false,t.tempImageIds&&t.tempImageIds.length>0)try{await S("cleanup-temp-images",{tempImageIds:t.tempImageIds}),console.log("临时图片清理完成:",t.tempImageIds)}catch(n){console.warn("清理临时图片失败:",n)}}else console.error("消息发送失败:",t.error),_("发送失败: "+t.error,"error")}catch(t){console.error("发送消息时出错:",t),_("发送失败: "+((t==null?void 0:t.message)||String(t)),"error")}finally{ne.value=false}}function Ut(){G.value=!G.value}function jt(){Le.value&&Le.value.click(),G.value=false}async function At(e){const a=e.target,t=a.files;if(!(!t||t.length===0)){for(const n of Array.from(t))await at(n);a.value=""}}async function Nt(e){var t;const a=(t=e.clipboardData)==null?void 0:t.items;if(a){for(const n of Array.from(a))if(n.type.startsWith("image/")){e.preventDefault();const r=n.getAsFile();r&&await at(r)}}}async function at(e){try{if(e.size>10*1024*1024){_("图片文件过大,请选择小于10MB的图片","error");return}if(!e.type.startsWith("image/")){_("请选择图片文件","error");return}const a=await Ot(e),t=URL.createObjectURL(e),n=await S("upload-image",{file:a,filename:e.name,mimeType:e.type});n.success?j.value.push({tempId:n.tempId,filename:e.name,preview:t,size:e.size}):(URL.revokeObjectURL(t),_("图片上传失败: "+n.error,"error"))}catch(a){console.error("上传图片失败:",a),_("图片上传失败: "+((a==null?void 0:a.message)||String(a)),"error")}}async function Rt(e){try{const a=j.value.findIndex(t=>t.tempId===e);if(a!==-1){const t=j.value[a];URL.revokeObjectURL(t.preview),j.value.splice(a,1)}await S("delete-temp-image",{tempId:e})}catch(a){console.error("删除图片失败:",a)}}function Ot(e){return new Promise((a,t)=>{const n=new FileReader;n.onload=()=>a(n.result),n.onerror=t,n.readAsDataURL(e)})}function nt(e){const a=e.target;a.closest(".input-actions")||(G.value=false),a.closest(".context-menu")||R()}function st(e){return new Date(e).toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"})}function zt(e){if(typeof e=="number")switch(e){case 0:return"文本";case 1:return"私聊";default:return"未知"}return String(e)}function re(){D.value&&(D.value.scrollTop=D.value.scrollHeight,qe.value=false,we.value=false)}function xe(){if(D.value){const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value,r=a-(e+t)<=50,s=!r;qe.value=s,r?we.value=false:we.value=true}}function je(){if(!D.value)return true;const{scrollTop:e,scrollHeight:a,clientHeight:t}=D.value;return a-(e+t)<=200}function Ae(e){var n;if(!m.value)return 0;const a=`${m.value}:${e}`,t=K.value[a];return t!==void 0?t:((n=u.value.messages[a])==null?void 0:n.length)||0}function rt(e,a){e.preventDefault(),e.stopPropagation();const t="touches"in e?e.touches[0].clientX:e.clientX,n="touches"in e?e.touches[0].clientY:e.clientY;Ue.value=Date.now(),A.value={x:t,y:n},q.value={x:t,y:n},se.value=false;const s=e.target.getBoundingClientRect();Ge.value={x:s.left,y:s.top},Ke.value={x:t-s.left,y:n-s.top},N.value=window.setTimeout(()=>{if(Ue.value>0){se.value=true,F.value=a;const o=e.target,l=o.cloneNode(true);l.classList.add("dragging-clone"),l.style.position="fixed",l.style.zIndex="1000",l.style.pointerEvents="none";const c=o.getBoundingClientRect();l.style.left=`${c.left}px`,l.style.top=`${c.top}px`,l.style.width=`${c.width}px`,l.style.height=`${c.height}px`,document.body.appendChild(l),I.value=l,document.body.style.userSelect="none",document.body.style.cursor="grabbing",document.body.classList.add("dragging-bubble-global"),Ht(A.value.x,A.value.y)}},60),document.addEventListener("mousemove",Ce),document.addEventListener("mouseup",ke),document.addEventListener("touchmove",Ce),document.addEventListener("touchend",ke)}function Ce(e){if(!se.value||!I.value)return;e.preventDefault();const a="touches"in e?e.touches[0].clientX:e.clientX,t="touches"in e?e.touches[0].clientY:e.clientY;q.value={x:a,y:t};const n=q.value.x-A.value.x,r=q.value.y-A.value.y,s=Math.sqrt(n*n+r*r),o=Math.max(.3,1-s/(P*2)),l=Math.max(.8,1-s/(P*3)),c=s>P,h=q.value.x-Ke.value.x,y=q.value.y-Ke.value.y;I.value.style.left=`${h}px`,I.value.style.top=`${y}px`,I.value.style.transform=`scale(${l})`,I.value.style.opacity=`${o}`,I.value.style.backgroundColor=c?"#f44336":"#2196f3",I.value.style.boxShadow=c?"0 4px 12px rgba(244, 67, 54, 0.4)":"0 4px 12px rgba(33, 150, 243, 0.4)",c?I.value.classList.add("will-delete"):I.value.classList.remove("will-delete")}function ke(e){if(N.value&&(clearTimeout(N.value),N.value=null),N.value&&(clearTimeout(N.value),N.value=null),!se.value||!F.value){be();return}const a=F.value;if(Math.sqrt(Math.pow(q.value.x-A.value.x,2)+Math.pow(q.value.y-A.value.y,2))>P)Mt(a),be();else if(I.value){I.value.style.transition="all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)";const n=document.querySelector(`[data-channel-id="${a}"] .channel-message-count`);if(n){const r=n.getBoundingClientRect();I.value.style.left=`${r.left}px`,I.value.style.top=`${r.top}px`,I.value.style.transform="scale(1)",I.value.style.opacity="1",I.value.style.backgroundColor="#2196f3",I.value.style.boxShadow="0 4px 12px rgba(33, 150, 243, 0.4)"}setTimeout(()=>{be()},300)}else be()}function be(){N.value&&(clearTimeout(N.value),N.value=null),F.value="",A.value={x:0,y:0},q.value={x:0,y:0},Ge.value={x:0,y:0},Ue.value=0,se.value=false,document.removeEventListener("mousemove",Ce),document.removeEventListener("mouseup",ke),document.removeEventListener("touchmove",Ce),document.removeEventListener("touchend",ke),document.body.style.userSelect="",document.body.style.cursor="",document.body.classList.remove("dragging-bubble-global"),I.value&&I.value.parentNode&&(I.value.parentNode.removeChild(I.value),I.value=null),Ft()}function Pt(e){return F.value===e&&se.value?{visibility:"hidden",pointerEvents:"none",transition:"none"}:{}}function lt(e){if(F.value!==e)return 0;const a=q.value.x-A.value.x,t=q.value.y-A.value.y;return Math.sqrt(a*a+t*t)}async function Mt(e){if(m.value)try{const a=`${m.value}:${e}`,t=Ae(e),n=fe.value.keepMessagesOnClear;if(n>0&&t<=n){_("当前消息还很少诶~ 无需清理","success");return}const r=await S("clear-channel-history",{selfId:m.value,channelId:e});if(r.success)if(r.clearedCount&&r.clearedCount>0){if(u.value.messages[a]){const o=[...u.value.messages[a]].sort((l,c)=>l.timestamp-c.timestamp);u.value.messages[a]=o.slice(-r.keptCount)}K.value[a]=r.keptCount,await $e(a),_(`历史记录已清理,清理了 ${r.clearedCount} 条消息,保留最新 ${r.keptCount} 条`,"success")}else n===0?(u.value.messages[a]&&(u.value.messages[a]=[]),K.value[a]=0,await $e(a),_("历史记录已清理,所有消息已删除","success")):_("当前消息还很少诶~ 无需清理","success");else console.error("清理历史记录失败:",r.error),_("清理失败: "+r.error,"error")}catch(a){console.error("清理历史记录时出错:",a),_("清理失败: "+((a==null?void 0:a.message)||String(a)),"error")}}function _(e,a="success"){const t=document.createElement("div");t.className=`notification ${a}`,t.textContent=e;let n="#4caf50";switch(a){case"info":n="#2196f3";break;case"warn":n="#ff9800";break;case"error":n="#f44336";break;case"success":n="#4caf50";break}t.style.cssText=`
2
2
  position: fixed;
3
3
  top: 20px;
4
4
  right: 20px;
@@ -10,7 +10,7 @@ import{defineComponent as Q,ref as f,onMounted as Ne,h as d,computed as O,watch
10
10
  animation: slideIn 0.3s ease-out;
11
11
  background: ${n};
12
12
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
13
- `;const l=document.createElement("style");l.textContent=`
13
+ `;const r=document.createElement("style");r.textContent=`
14
14
  @keyframes slideIn {
15
15
  from { transform: translateX(100%); opacity: 0; }
16
16
  to { transform: translateX(0); opacity: 1; }
@@ -19,9 +19,9 @@ import{defineComponent as Q,ref as f,onMounted as Ne,h as d,computed as O,watch
19
19
  from { transform: translateX(0); opacity: 1; }
20
20
  to { transform: translateX(100%); opacity: 0; }
21
21
  }
22
- `,document.head.appendChild(l),document.body.appendChild(t),setTimeout(()=>{t.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t),l.parentNode&&l.parentNode.removeChild(l)},300)},3e3)}function Ut(e,a){const t=document.createElement("div");t.className="drag-threshold-circle",t.style.cssText=`
23
- left: ${e-A}px;
24
- top: ${a-A}px;
25
- width: ${A*2}px;
26
- height: ${A*2}px;
27
- `,document.body.appendChild(t),window.dragThresholdCircle=t}function jt(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function Kt(){return new Promise((e,a)=>{const t=indexedDB.open(Fa,Ya);t.onerror=()=>{console.error("IndexedDB初始化失败:",t.error),e(false)},t.onsuccess=()=>{S=t.result,e(true)},t.onupgradeneeded=n=>{const l=n.target.result;if(!l.objectStoreNames.contains(R)){const s=l.createObjectStore(R,{keyPath:"url"});s.createIndex("channelKey","channelKey",{unique:false}),s.createIndex("timestamp","timestamp",{unique:false})}}})}async function Nt(e){return S?new Promise((a,t)=>{const s=S.transaction([R],"readonly").objectStore(R).get(e);s.onsuccess=()=>{a(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),a(null)}}):null}async function et(e){return S?new Promise(a=>{const l=S.transaction([R],"readwrite").objectStore(R).put(e);l.onsuccess=()=>{a(true)},l.onerror=()=>{console.error("保存图片到IndexedDB失败:",l.error),a(false)}}):false}async function tt(e){return S?new Promise(a=>{const l=S.transaction([R],"readwrite").objectStore(R).delete(e);l.onsuccess=()=>{a(true)},l.onerror=()=>{console.error("从IndexedDB删除图片失败:",l.error),a(false)}}):false}async function at(e){return S?new Promise(a=>{const s=S.transaction([R],"readonly").objectStore(R).index("channelKey").getAll(e);s.onsuccess=()=>{a(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),a([])}}):[]}async function je(e,a){const t=b.value[a];if(t)return t;const n=await Nt(a);if(!n)return null;$e();const l=URL.createObjectURL(n.blob);return b.value[a]=l,ge(Me(n.blob)),n.timestamp=Date.now(),await et(n),l}async function se(e,a){try{const t=await je(e,a);if(t)return t;const n=await _("fetch-image",{url:a});if(!n.success)return console.error("获取图片失败:",n.error),null;const l=n.base64,s=n.contentType||"image/jpeg",o=atob(l),r=new Array(o.length);for(let fe=0;fe<o.length;fe++)r[fe]=o.charCodeAt(fe);const i=new Uint8Array(r),h=new Blob([i],{type:s}),g=await at(e);if(g.length>=rt){const Jt=g.sort((le,Vt)=>le.timestamp-Vt.timestamp).slice(0,g.length-rt+1);for(const le of Jt)await tt(le.url),b.value[le.url]&&(URL.revokeObjectURL(b.value[le.url]),delete b.value[le.url])}const y={url:a,blob:h,timestamp:Date.now(),size:h.size,channelKey:e};if(!await et(y))return console.error("保存图片到IndexedDB失败"),null;$e();const B=URL.createObjectURL(h);return b.value[a]=B,ge(Me(h)),B}catch(t){return console.error("缓存图片失败:",t),null}}async function ke(e){try{const a=await at(e);let t=0;for(const n of a)await tt(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],t+=n.size||0);t>0&&ge(-t)}catch(a){console.error("清理频道图片缓存失败:",a)}}function Ot(e){var a,t,n,l;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(l=e.bot)!=null&&l.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(r=>r.id===e.messageId)){const r={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},i=u.value.messages[s];let h=i.length;for(let y=i.length-1;y>=0;y--){if(i[y].timestamp<=e.timestamp){h=y+1;break}y===0&&(h=0)}i.splice(h,0,r),i.length>100&&(u.value.messages[s]=i.slice(-100)),D.value[s]=i.length;const g=De();re(()=>{setTimeout(()=>{g&&ne()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const r=o.attrs.src||o.attrs.url||o.attrs.file;r&&se(s,r).catch(i=>{console.warn("预缓存图片失败:",r,i)})}})}u.value={...u.value}}function Pt(e){const a=`${e.selfId}:${e.channelId}`;if(u.value.messages[a]||(u.value.messages[a]=[]),!u.value.messages[a].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},l=u.value.messages[a];let s=l.length;for(let r=l.length-1;r>=0;r--){if(l[r].timestamp<=e.timestamp){s=r+1;break}r===0&&(s=0)}l.splice(s,0,n),l.length>100&&(u.value.messages[a]=l.slice(-100)),D.value[a]=l.length;const o=De();re(()=>{setTimeout(()=>{o&&ne()},10)})}u.value={...u.value}}function Rt(e){var a,t,n,l;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(l=e.bot)!=null&&l.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(r=>r.id===e.messageId)){const r={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},i=u.value.messages[s];let h=i.length;for(let y=i.length-1;y>=0;y--){if(i[y].timestamp<=e.timestamp){h=y+1;break}y===0&&(h=0)}i.splice(h,0,r),i.length>100&&(u.value.messages[s]=i.slice(-100)),D.value[s]=i.length;const g=De();re(()=>{setTimeout(()=>{g&&ne()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const r=o.attrs.src||o.attrs.url||o.attrs.file;r&&se(s,r).catch(i=>{console.warn("预缓存图片失败:",r,i)})}})}u.value={...u.value}}nt(He,(e,a)=>{a.length===0&&e.length>0&&re(()=>{ne()})});async function At(){try{const e=await _("get-chat-data");if(e.success&&e.data){const a={};X.value=new Set(e.data.pinnedBots||[]),H.value=new Set(e.data.pinnedChannels||[]);for(const[t,n]of Object.entries(e.data.messages||{})){const l=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}));l.sort((s,o)=>s.timestamp-o.timestamp),a[t]=l}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:a},await Mt(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function Mt(){try{const e=await _("get-all-channel-message-counts");if(e.success&&e.counts){const a={};for(const[t,n]of Object.entries(e.counts))a[t]=n;D.value=a}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function zt(){try{const e=await _("get-plugin-config");e.success&&e.config?ie.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function Xt(e,a){try{const t=await _("get-history-messages",{selfId:e,channelId:a});if(t.success&&t.messages){const n=`${e}:${a}`,l=t.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return l.sort((s,o)=>s.timestamp-o.timestamp),u.value.messages[n]=l,D.value[n]=l.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",t.error),false}catch(t){return console.error("获取历史消息时出错:",t),false}}function Ht(e){if(!L.value||e.touches.length!==1)return;const a=e.touches[0];M.value={x:a.clientX,y:a.clientY,time:Date.now()},ee.value={x:a.clientX,y:a.clientY},Be.value=false}function Ft(e){if(!L.value||!M.value||e.touches.length!==1)return;const a=e.touches[0];ee.value={x:a.clientX,y:a.clientY};const t=a.clientX-M.value.x,n=a.clientY-M.value.y;if(Math.abs(t)>Math.abs(n)&&Math.abs(t)>30){const l=t>0,s=W.value==="messages"||W.value==="channels";if(l&&s){Be.value=true;const o=Math.min(t,200),r=150;o>r?V.value={show:true,text:"松开返回"}:V.value={show:true,text:`滑动返回 ${Math.round(o/r*100)}%`},e.preventDefault()}else V.value={show:false,text:""}}else V.value={show:false,text:""}}function Yt(e){if(!L.value||!M.value)return;const t=Date.now()-M.value.time;if(ee.value){const n=ee.value.x-M.value.x,l=ee.value.y-M.value.y,s=n>150,o=Math.abs(n)>Math.abs(l),r=t<300&&n>80;(s&&o||r)&&Wt()}M.value=null,ee.value=null,Be.value=false,V.value={show:false,text:""}}function Wt(){switch(W.value){case"messages":W.value="channels";break;case"channels":W.value="bots",m.value="",C.value="";break}}function Ke(){L.value=window.innerWidth<=768}return Ne(async()=>{Ke(),window.addEventListener("resize",Ke),document.addEventListener("click",Ge),await Kt()||console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await zt(),await At();const a=Re("chat-message-event",Ot),t=Re("bot-message-sent-event",Pt),n=Re("chat-bot-message-event",Rt);nt(C,l=>{l&&re(()=>{$.value&&($.value.removeEventListener("scroll",we),$.value.addEventListener("scroll",we),we()),!L.value&&de.value&&de.value.focus()})},{immediate:true}),setInterval(()=>{$e()},2*60*1e3),Gt(()=>{window.removeEventListener("resize",Ke),document.removeEventListener("click",Ge),a&&typeof a=="function"&&a(),t&&typeof t=="function"&&t(),n&&typeof n=="function"&&n(),$.value&&$.value.removeEventListener("scroll",we),Object.values(b.value).forEach(l=>{URL.revokeObjectURL(l)}),b.value={},S&&(S.close(),S=null)})}),(e,a)=>(v(),p("div",{class:F(["chat-container",ht.value]),style:Oe(vt.value),onTouchstart:Ht,onTouchmove:Ft,onTouchend:Yt},[c("div",aa,[a[7]||(a[7]=c("div",{class:"panel-header"},[c("h3",null,"机器人")],-1)),c("div",na,[(v(true),p(P,null,oe(it.value,t=>(v(),p("div",{key:t.selfId,class:F(["bot-item",{active:m.value===t.selfId,pinned:X.value.has(t.selfId)}]),onClick:n=>gt(t.selfId),onContextmenu:n=>yt(n,t.selfId)},[c("div",la,[t.avatar?(v(),he(me(E),{key:0,src:t.avatar,alt:t.username,"channel-key":"bot-list"},null,8,["src","alt"])):(v(),p("div",ra,x(t.username.charAt(0).toUpperCase()),1))]),c("div",oa,[c("div",ca,x(t.username),1),c("div",ia,x(t.platform),1)]),c("div",{class:F(["bot-status",t.status])},null,2)],42,sa))),128))])]),c("div",ua,[a[8]||(a[8]=c("div",{class:"panel-header"},[c("h3",null,"频道")],-1)),m.value?(v(),p("div",fa,[(v(true),p(P,null,oe(ut.value,t=>(v(),p("div",{key:t.id,class:F(["channel-item",{active:C.value===t.id,pinned:H.value.has(`${m.value}:${t.id}`)}]),"data-channel-id":t.id,onClick:n=>kt(t.id),onContextmenu:n=>pt(n,t.id)},[c("div",ma,[c("div",va,x(t.name),1),c("div",ga,x(Tt(t.type)),1)]),Ue(t.id)>0?(v(),p("div",{key:0,class:F(["channel-message-count draggable-bubble",{dragging:z.value===t.id,"will-delete":z.value===t.id&&Ee(t.id)>A}]),onMousedown:n=>Ze(n,t.id),onTouchstart:n=>Ze(n,t.id),style:Oe(qt(t.id)),title:z.value===t.id?Ee(t.id)>A?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},x(Ue(t.id)),47,ya)):G("",true)],42,ha))),128))])):(v(),p("div",da," 请选择一个机器人 "))]),c("div",pa,[c("div",wa,[c("h3",null,x(dt.value||"选择频道"),1)]),!m.value||!C.value?(v(),p("div",Ia," 请选择机器人和频道 ")):(v(),p("div",xa,[c("div",{class:"message-history",ref_key:"messageHistory",ref:$},[(v(true),p(P,null,oe(He.value,t=>(v(),p("div",{key:t.id,class:F(["message-item",{"bot-message":t.isBot}])},[c("div",Ca,[t.avatar?(v(),he(me(E),{key:0,src:t.avatar,alt:t.username,"channel-key":pe.value},null,8,["src","alt","channel-key"])):(v(),p("div",ka,x(t.username.charAt(0).toUpperCase()),1))]),c("div",ba,[c("div",_a,[c("span",$a,x(t.username),1),c("span",Sa,x(Qe(t.timestamp)),1)]),t.quote?(v(),p("div",Ba,[c("div",La,[c("div",Ta,[t.quote.user.avatar?(v(),he(me(E),{key:0,src:t.quote.user.avatar,alt:t.quote.user.username,"channel-key":pe.value},null,8,["src","alt","channel-key"])):(v(),p("div",qa,x(t.quote.user.username.charAt(0).toUpperCase()),1))]),c("span",Da,x(t.quote.user.username),1),c("span",Ua,x(Qe(t.quote.timestamp)),1)]),c("div",ja,[t.quote.elements&&t.quote.elements.length>0?(v(true),p(P,{key:0},oe(t.quote.elements,(n,l)=>(v(),he(me(ve),{key:`quote-${l}`,element:n,"channel-key":pe.value},null,8,["element","channel-key"]))),128)):(v(),p(P,{key:1},[Pe(x(t.quote.content),1)],64))])])):G("",true),c("div",Ka,[t.elements&&t.elements.length>0?(v(true),p(P,{key:0},oe(t.elements,(n,l)=>(v(),he(me(ve),{key:l,element:n,"channel-key":pe.value},null,8,["element","channel-key"]))),128)):(v(),p(P,{key:1},[Pe(x(t.content),1)],64))])])],2))),128))],512),st(c("div",{class:"floating-scroll-button",onClick:ne},a[9]||(a[9]=[c("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[c("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[Qt,Le.value]]),c("div",Na,[U.value.length>0?(v(),p("div",Oa,[(v(true),p(P,null,oe(U.value,t=>(v(),p("div",{key:t.tempId,class:"image-preview-item"},[c("img",{src:t.preview,alt:t.filename,class:"preview-image"},null,8,Pa),c("button",{class:"remove-image-btn",onClick:n=>Bt(t.tempId),title:"删除图片"},a[10]||(a[10]=[c("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[c("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,Ra)]))),128))])):G("",true),c("div",Aa,[c("div",Ma,[c("button",{class:F(["add-button",{active:J.value}]),onClick:bt,title:"更多操作"},a[11]||(a[11]=[c("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[c("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),c("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),J.value?(v(),p("div",{key:0,class:"action-menu",onClick:a[0]||(a[0]=lt(()=>{},["stop"]))},[c("button",{class:"action-menu-item",onClick:_t},a[12]||(a[12]=[c("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[c("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),c("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),c("polyline",{points:"21,15 16,10 5,21"})],-1),Pe(" 上传图片 ",-1)]))])):G("",true)]),st(c("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>ue.value=t),type:"text",placeholder:mt.value,onKeyup:Zt(Je,["enter"]),disabled:!ft.value,ref_key:"messageInput",ref:de,onPaste:St},null,40,za),[[Et,ue.value]]),c("button",{onClick:Je,disabled:!Fe.value,class:F({"is-sending":te.value})},x(te.value?"发送中...":"发送"),11,Xa)]),c("input",{type:"file",ref_key:"fileInput",ref:Se,onChange:$t,accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),I.value.show?(v(),p("div",{key:0,class:"context-menu",style:Oe({left:I.value.x+"px",top:I.value.y+"px"}),onClick:a[6]||(a[6]=lt(()=>{},["stop"]))},[I.value.type==="bot"?(v(),p(P,{key:0},[c("div",{class:"context-menu-item",onClick:a[2]||(a[2]=t=>wt(I.value.targetId))},x(X.value.has(I.value.targetId)?"取消置顶":"置顶"),1),c("div",{class:"context-menu-item danger",onClick:a[3]||(a[3]=t=>xt(I.value.targetId))}," 彻底删除此机器人所有数据 ")],64)):G("",true),I.value.type==="channel"?(v(),p(P,{key:1},[c("div",{class:"context-menu-item",onClick:a[4]||(a[4]=t=>It(I.value.targetId))},x(H.value.has(`${m.value}:${I.value.targetId}`)?"取消置顶":"置顶"),1),c("div",{class:"context-menu-item danger",onClick:a[5]||(a[5]=t=>Ct(I.value.targetId))}," 彻底删除此频道所有数据 ")],64)):G("",true)],4)):G("",true),c("div",{class:F(["swipe-indicator",{show:V.value.show}])},x(V.value.text),3)],38))}}),ot=(Z,Y)=>{const E=Z.__vccOpts||Z;for(const[ce,be]of Y)E[ce]=be;return E},Ja=ot(Wa,[["__scopeId","data-v-fc970c70"]]),Va={},Ga={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function Qa(Z,Y){return v(),p("svg",Ga,Y[0]||(Y[0]=[c("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),c("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),c("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 Za=ot(Va,[["render",Qa]]);ta.register("activity:chat",Za);const tn=Z=>{Z.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:Q({setup(){return()=>d(ea("k-layout"),{},{default:()=>d(Ja)})}})})};export{tn as default};
22
+ `,document.head.appendChild(r),document.body.appendChild(t),setTimeout(()=>{t.style.animation="slideOut 0.3s ease-in",setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t),r.parentNode&&r.parentNode.removeChild(r)},300)},3e3)}function Ht(e,a){const t=document.createElement("div");t.className="drag-threshold-circle",t.style.cssText=`
23
+ left: ${e-P}px;
24
+ top: ${a-P}px;
25
+ width: ${P*2}px;
26
+ height: ${P*2}px;
27
+ `,document.body.appendChild(t),window.dragThresholdCircle=t}function Ft(){const e=window.dragThresholdCircle;e&&e.parentNode&&(e.parentNode.removeChild(e),window.dragThresholdCircle=null)}async function Ne(){try{if(!w)return false;const e=Date.now();if(e-We<nn)return true;We=e;const a=await ot();U=a.totalSize,M=a.totalImages,console.log("数据库健康检查:",{大小:`${(U/1024/1024).toFixed(2)}MB / ${(ie/1024/1024).toFixed(2)}MB`,图片数量:`${M} / ${ue}`,使用率:`${(U/ie*100).toFixed(1)}%`});const t=U/ie,n=M/ue;return(t>gt||n>gt)&&(console.warn("数据库使用率过高,开始自动清理"),await _e()),(t>.95||n>.95)&&(console.error("数据库接近极限,执行紧急清理"),await Xt()),true}catch(e){return console.error("数据库健康检查失败:",e),false}}async function ot(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{const r=n.result||[];let s=0;const o={};r.forEach(l=>{s+=l.size||0,o[l.channelKey]=(o[l.channelKey]||0)+1}),e({totalSize:s,totalImages:r.length,channelStats:o})},n.onerror=()=>{console.error("获取数据库统计失败:",n.error),e({totalSize:0,totalImages:0,channelStats:{}})}}):{totalSize:0,totalImages:0,channelStats:{}}}async function _e(){try{console.log("开始自动清理...");const e=await ct();if(e.length===0)return;const a={};e.forEach(r=>{a[r.channelKey]||(a[r.channelKey]=[]),a[r.channelKey].push(r)});let t=0,n=0;for(const[r,s]of Object.entries(a))if(s.length>vt){s.sort((l,c)=>l.timestamp-c.timestamp);const o=s.slice(0,s.length-vt);for(const l of o)await Re(l.url),t++,n+=l.size||0,b.value[l.url]&&(URL.revokeObjectURL(b.value[l.url]),delete b.value[l.url])}console.log(`自动清理完成: 清理了 ${t} 张图片,释放了 ${(n/1024/1024).toFixed(2)}MB`),M-=t,U-=n}catch(e){console.error("自动清理失败:",e)}}async function Xt(){try{console.log("开始紧急清理...");const e=await ct();if(e.length===0)return;e.sort((s,o)=>o.timestamp-s.timestamp);const a=Math.floor(ue*.3),t=e.slice(a);let n=0,r=0;for(const s of t)await Re(s.url),n++,r+=s.size||0,b.value[s.url]&&(URL.revokeObjectURL(b.value[s.url]),delete b.value[s.url]);console.log(`紧急清理完成: 清理了 ${n} 张图片,释放了 ${(r/1024/1024).toFixed(2)}MB`),M=a,U-=r}catch(e){console.error("紧急清理失败:",e)}}async function ct(){return w?new Promise(e=>{const n=w.transaction([B],"readonly").objectStore(B).getAll();n.onsuccess=()=>{e(n.result||[])},n.onerror=()=>{console.error("获取所有图片失败:",n.error),e([])}}):[]}async function Yt(){return new Promise(e=>{try{w&&(w.close(),w=null);const a=indexedDB.deleteDatabase(mt);a.onsuccess=()=>{console.log("IndexedDB数据库已完全清理"),U=0,M=0,e(true)},a.onerror=()=>{console.error("清理IndexedDB数据库失败:",a.error),e(false)},a.onblocked=()=>{console.warn("IndexedDB数据库删除被阻塞,可能有其他连接正在使用"),setTimeout(()=>{e(false)},5e3)}}catch(a){console.error("清理数据库时出错:",a),e(false)}})}async function Wt(){try{return await it()?(setTimeout(async()=>{const a=await ot();console.log("数据库初始状态:",{大小:`${(a.totalSize/1024/1024).toFixed(2)}MB`,图片数量:a.totalImages,频道分布:a.channelStats}),(a.totalSize>ie*.9||a.totalImages>ue*.9)&&(console.warn("数据库初始状态接近限制,执行清理"),await _e())},1e3),true):(console.warn("数据库打开失败,尝试清理后重新初始化"),await Yt(),await it())}catch(e){return console.error("IndexedDB初始化出错:",e),false}}async function it(){return new Promise(e=>{try{const a=indexedDB.open(mt,an);a.onerror=()=>{console.error("IndexedDB打开失败:",a.error),e(false)},a.onsuccess=()=>{w=a.result,w.onerror=t=>{console.error("IndexedDB运行时错误:",t)},w.onversionchange=()=>{console.warn("IndexedDB版本变更,关闭连接"),w==null||w.close(),w=null},e(true)},a.onupgradeneeded=t=>{const n=t.target.result;if(!n.objectStoreNames.contains(B)){const r=n.createObjectStore(B,{keyPath:"url"});r.createIndex("channelKey","channelKey",{unique:false}),r.createIndex("timestamp","timestamp",{unique:false}),r.createIndex("size","size",{unique:false}),console.log("IndexedDB对象存储创建完成")}},a.onblocked=()=>{console.warn("IndexedDB打开被阻塞"),e(false)}}catch(a){console.error("打开数据库时出错:",a),e(false)}})}async function Jt(e){return w?new Promise((a,t)=>{const s=w.transaction([B],"readonly").objectStore(B).get(e);s.onsuccess=()=>{a(s.result||null)},s.onerror=()=>{console.error("从IndexedDB获取图片失败:",s.error),a(null)}}):null}async function ut(e){if(!w)return false;try{return e.size>Ye?(console.warn(`图片过大,跳过缓存: ${(e.size/1024/1024).toFixed(2)}MB > ${(Ye/1024/1024).toFixed(2)}MB`),false):(await Ne(),U+e.size>ie&&(console.warn("添加图片会超过数据库大小限制,执行清理"),await _e(),U+e.size>ie)?(console.warn("清理后仍会超过限制,跳过此图片"),false):M>=ue&&(console.warn("图片数量已达上限,执行清理"),await _e(),M>=ue)?(console.warn("清理后仍达上限,跳过此图片"),false):new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).put(e);r.onsuccess=()=>{U+=e.size,M+=1,a(true)},r.onerror=()=>{console.error("保存图片到IndexedDB失败:",r.error),a(false)}}))}catch(a){return console.error("保存图片时出错:",a),false}}async function Re(e){return w?new Promise(a=>{const r=w.transaction([B],"readwrite").objectStore(B).delete(e);r.onsuccess=()=>{a(true)},r.onerror=()=>{console.error("从IndexedDB删除图片失败:",r.error),a(false)}}):false}async function Vt(e){return w?new Promise(a=>{const s=w.transaction([B],"readonly").objectStore(B).index("channelKey").getAll(e);s.onsuccess=()=>{a(s.result||[])},s.onerror=()=>{console.error("获取频道图片失败:",s.error),a([])}}):[]}async function Oe(e,a){const t=b.value[a];if(t)return t;const n=await Jt(a);if(!n)return null;De();const r=URL.createObjectURL(n.blob);return b.value[a]=r,pe(Je(n.blob)),n.timestamp=Date.now(),await ut(n),r}async function le(e,a){try{const t=await Oe(e,a);if(t)return t;const n=await S("fetch-image",{url:a});if(!n.success)return console.error("获取图片失败:",n.error),null;const r=n.base64,s=n.contentType||"image/jpeg",o=atob(r),l=new Array(o.length);for(let $=0;$<o.length;$++)l[$]=o.charCodeAt($);const c=new Uint8Array(l),h=new Blob([c],{type:s});if(h.size>Ye)return console.warn(`图片过大,跳过缓存: ${(h.size/1024/1024).toFixed(2)}MB`),null;const y={url:a,blob:h,timestamp:Date.now(),size:h.size,channelKey:e};if(!await ut(y))return console.error("保存图片到IndexedDB失败"),null;De();const L=URL.createObjectURL(h);return b.value[a]=L,pe(Je(h)),L}catch(t){return console.error("缓存图片失败:",t),null}}async function $e(e){try{const a=await Vt(e);let t=0;for(const n of a)await Re(n.url),b.value[n.url]&&(URL.revokeObjectURL(b.value[n.url]),delete b.value[n.url],t+=n.size||0);t>0&&pe(-t)}catch(a){console.error("清理频道图片缓存失败:",a)}}function Gt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(r=e.bot)!=null&&r.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(l=>l.id===e.messageId)){const l={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:false,quote:e.quote},c=u.value.messages[s];let h=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){h=g+1;break}g===0&&(h=0)}c.splice(h,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),K.value[s]=c.length;const y=je();oe(()=>{setTimeout(()=>{y&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}function Zt(e){const a=`${e.selfId}:${e.channelId}`;if(u.value.messages[a]||(u.value.messages[a]=[]),!u.value.messages[a].find(n=>n.id===e.messageId)){const n={id:e.messageId,content:e.content,userId:e.selfId,username:e.botUsername,avatar:e.botAvatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},r=u.value.messages[a];let s=r.length;for(let l=r.length-1;l>=0;l--){if(r[l].timestamp<=e.timestamp){s=l+1;break}l===0&&(s=0)}r.splice(s,0,n),r.length>100&&(u.value.messages[a]=r.slice(-100)),K.value[a]=r.length;const o=je();oe(()=>{setTimeout(()=>{o&&re()},10)})}u.value={...u.value}}function Qt(e){var a,t,n,r;if(!u.value.bots[e.selfId])u.value.bots[e.selfId]={selfId:e.selfId,platform:e.platform,username:((a=e.bot)==null?void 0:a.name)||`Bot-${e.selfId}`,avatar:(t=e.bot)==null?void 0:t.avatar,status:"online"};else{const s=u.value.bots[e.selfId];s.status="online",(n=e.bot)!=null&&n.name&&s.username!==e.bot.name&&(s.username=e.bot.name),(r=e.bot)!=null&&r.avatar&&s.avatar!==e.bot.avatar&&(s.avatar=e.bot.avatar)}if(u.value.channels[e.selfId]||(u.value.channels[e.selfId]={}),e.channelId&&!u.value.channels[e.selfId][e.channelId]){const s=e.guildId?`${e.guildName||e.guildId} (${e.channelId})`:`私信 ${e.channelId}`;u.value.channels[e.selfId][e.channelId]={id:e.channelId,name:s,type:e.channelType||0,guildId:e.guildId,guildName:e.guildName||e.guildId||"私聊"}}if(e.messageId&&e.content&&e.channelId){const s=`${e.selfId}:${e.channelId}`;if(u.value.messages[s]||(u.value.messages[s]=[]),!u.value.messages[s].find(l=>l.id===e.messageId)){const l={id:e.messageId,content:e.content,userId:e.userId,username:e.username,avatar:e.avatar,timestamp:e.timestamp,channelId:e.channelId,selfId:e.selfId,elements:e.elements,isBot:true,quote:e.quote},c=u.value.messages[s];let h=c.length;for(let g=c.length-1;g>=0;g--){if(c[g].timestamp<=e.timestamp){h=g+1;break}g===0&&(h=0)}c.splice(h,0,l),c.length>100&&(u.value.messages[s]=c.slice(-100)),K.value[s]=c.length;const y=je();oe(()=>{setTimeout(()=>{y&&re()},10)})}}if(e.elements&&e.elements.length>0){const s=`${e.selfId}:${e.channelId}`;e.elements.forEach(o=>{if((o.type==="img"||o.type==="image"||o.type==="mface")&&o.attrs){const l=o.attrs.src||o.attrs.url||o.attrs.file;l&&le(s,l).catch(c=>{console.warn("预缓存图片失败:",l,c)})}})}u.value={...u.value}}dt(Ze,(e,a)=>{a.length===0&&e.length>0&&oe(()=>{re()})});async function Et(){try{const e=await S("get-chat-data");if(e.success&&e.data){const a={};X.value=new Set(e.data.pinnedBots||[]),Y.value=new Set(e.data.pinnedChannels||[]);for(const[t,n]of Object.entries(e.data.messages||{})){const r=n.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));r.sort((s,o)=>s.timestamp-o.timestamp),a[t]=r}return u.value={bots:e.data.bots||{},channels:e.data.channels||{},messages:a},await ea(),true}else return console.warn("获取聊天数据失败:",e.error),false}catch(e){return console.error("获取聊天数据时出错:",e),false}}async function ea(){try{const e=await S("get-all-channel-message-counts");if(e.success&&e.counts){const a={};for(const[t,n]of Object.entries(e.counts))a[t]=n;K.value=a}else console.warn("获取频道消息数量失败:",e.error)}catch(e){console.error("获取频道消息数量时出错:",e)}}async function ta(){try{const e=await S("get-plugin-config");e.success&&e.config?fe.value=e.config:console.warn("获取插件配置失败:",e.error)}catch(e){console.error("获取插件配置时出错:",e)}}async function aa(e,a){try{const t=await S("get-history-messages",{selfId:e,channelId:a});if(t.success&&t.messages){const n=`${e}:${a}`,r=t.messages.map(s=>({id:s.id,content:s.content,userId:s.userId,username:s.username,avatar:s.avatar,timestamp:s.timestamp,channelId:s.channelId,selfId:s.selfId,elements:s.elements,isBot:s.type==="bot",quote:s.quote}));return r.sort((s,o)=>s.timestamp-o.timestamp),u.value.messages[n]=r,K.value[n]=r.length,u.value={...u.value},true}else return console.warn("获取历史消息失败:",t.error),false}catch(t){return console.error("获取历史消息时出错:",t),false}}function na(e){if(!T.value||e.touches.length!==1)return;const a=e.touches[0];H.value={x:a.clientX,y:a.clientY,time:Date.now()},ae.value={x:a.clientX,y:a.clientY},Te.value=false}function sa(e){if(!T.value||!H.value||e.touches.length!==1)return;const a=e.touches[0];ae.value={x:a.clientX,y:a.clientY};const t=a.clientX-H.value.x,n=a.clientY-H.value.y;if(Math.abs(t)>Math.abs(n)&&Math.abs(t)>30){const r=t>0,s=V.value==="messages"||V.value==="channels";if(r&&s){Te.value=true;const o=Math.min(t,200),l=150;o>l?Z.value={show:true,text:"松开返回"}:Z.value={show:true,text:`滑动返回 ${Math.round(o/l*100)}%`},e.preventDefault()}else Z.value={show:false,text:""}}else Z.value={show:false,text:""}}function ra(e){if(!T.value||!H.value)return;const t=Date.now()-H.value.time;if(ae.value){const n=ae.value.x-H.value.x,r=ae.value.y-H.value.y,s=n>150,o=Math.abs(n)>Math.abs(r),l=t<300&&n>80;(s&&o||l)&&la()}H.value=null,ae.value=null,Te.value=false,Z.value={show:false,text:""}}function la(){switch(V.value){case"messages":V.value="channels";break;case"channels":V.value="bots",m.value="",k.value="";break}}function ze(){T.value=window.innerWidth<=768}return Pe(async()=>{ze(),window.addEventListener("resize",ze),document.addEventListener("click",nt),await Wt()?(console.log("IndexedDB初始化成功"),setTimeout(async()=>{await Ne()},2e3),setInterval(async()=>{await Ne()},5*60*1e3)):console.warn("IndexedDB初始化失败,图片缓存功能将不可用"),await ta(),await Et();const a=Fe("chat-message-event",Gt),t=Fe("bot-message-sent-event",Zt),n=Fe("chat-bot-message-event",Qt);dt(k,r=>{r&&oe(()=>{D.value&&(D.value.removeEventListener("scroll",xe),D.value.addEventListener("scroll",xe),xe()),!T.value&&me.value&&me.value.focus()})},{immediate:true}),setInterval(()=>{De()},2*60*1e3),oa(()=>{window.removeEventListener("resize",ze),document.removeEventListener("click",nt),a&&typeof a=="function"&&a(),t&&typeof t=="function"&&t(),n&&typeof n=="function"&&n(),D.value&&D.value.removeEventListener("scroll",xe),Object.values(b.value).forEach(r=>{URL.revokeObjectURL(r)}),b.value={},w&&(w.close(),w=null)})}),(e,a)=>(v(),p("div",{class:W(["chat-container",kt.value]),style:Me(_t.value),onTouchstart:na,onTouchmove:sa,onTouchend:ra},[i("div",ha,[a[7]||(a[7]=i("div",{class:"panel-header"},[i("h3",null,"机器人")],-1)),i("div",ma,[(v(true),p(z,null,ce(wt.value,t=>(v(),p("div",{key:t.selfId,class:W(["bot-item",{active:m.value===t.selfId,pinned:X.value.has(t.selfId)}]),onClick:n=>$t(t.selfId),onContextmenu:n=>St(n,t.selfId)},[i("div",ga,[t.avatar?(v(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":"bot-list"},null,8,["src","alt"])):(v(),p("div",ya,C(t.username.charAt(0).toUpperCase()),1))]),i("div",pa,[i("div",wa,C(t.username),1),i("div",Ia,C(t.platform),1)]),i("div",{class:W(["bot-status",t.status])},null,2)],42,va))),128))])]),i("div",xa,[a[8]||(a[8]=i("div",{class:"panel-header"},[i("h3",null,"频道")],-1)),m.value?(v(),p("div",ka,[(v(true),p(z,null,ce(It.value,t=>(v(),p("div",{key:t.id,class:W(["channel-item",{active:k.value===t.id,pinned:Y.value.has(`${m.value}:${t.id}`)}]),"data-channel-id":t.id,onClick:n=>Kt(t.id),onContextmenu:n=>Bt(n,t.id)},[i("div",_a,[i("div",$a,C(t.name),1),i("div",Sa,C(zt(t.type)),1)]),Ae(t.id)>0?(v(),p("div",{key:0,class:W(["channel-message-count draggable-bubble",{dragging:F.value===t.id,"will-delete":F.value===t.id&&lt(t.id)>P}]),onMousedown:n=>rt(n,t.id),onTouchstart:n=>rt(n,t.id),style:Me(Pt(t.id)),title:F.value===t.id?lt(t.id)>P?"松开清理历史记录":"拖拽更远以清理历史记录":"拖拽清理历史记录"},C(Ae(t.id)),47,Ba)):Q("",true)],42,ba))),128))])):(v(),p("div",Ca," 请选择一个机器人 "))]),i("div",Da,[i("div",La,[i("h3",null,C(xt.value||"选择频道"),1)]),!m.value||!k.value?(v(),p("div",Ta," 请选择机器人和频道 ")):(v(),p("div",qa,[i("div",{class:"message-history",ref_key:"messageHistory",ref:D},[(v(true),p(z,null,ce(Ze.value,t=>(v(),p("div",{key:t.id,class:W(["message-item",{"bot-message":t.isBot}])},[i("div",Ka,[t.avatar?(v(),ve(ge(te),{key:0,src:t.avatar,alt:t.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(v(),p("div",Ua,C(t.username.charAt(0).toUpperCase()),1))]),i("div",ja,[i("div",Aa,[i("span",Na,C(t.username),1),i("span",Ra,C(st(t.timestamp)),1)]),t.quote?(v(),p("div",Oa,[i("div",za,[i("div",Pa,[t.quote.user.avatar?(v(),ve(ge(te),{key:0,src:t.quote.user.avatar,alt:t.quote.user.username,"channel-key":Ie.value},null,8,["src","alt","channel-key"])):(v(),p("div",Ma,C(t.quote.user.username.charAt(0).toUpperCase()),1))]),i("span",Ha,C(t.quote.user.username),1),i("span",Fa,C(st(t.quote.timestamp)),1)]),i("div",Xa,[t.quote.elements&&t.quote.elements.length>0?(v(true),p(z,{key:0},ce(t.quote.elements,(n,r)=>(v(),ve(ge(ye),{key:`quote-${r}`,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(v(),p(z,{key:1},[He(C(t.quote.content),1)],64))])])):Q("",true),i("div",Ya,[t.elements&&t.elements.length>0?(v(true),p(z,{key:0},ce(t.elements,(n,r)=>(v(),ve(ge(ye),{key:r,element:n,"channel-key":Ie.value},null,8,["element","channel-key"]))),128)):(v(),p(z,{key:1},[He(C(t.content),1)],64))])])],2))),128))],512),ft(i("div",{class:"floating-scroll-button",onClick:re},a[9]||(a[9]=[i("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor"},[i("path",{d:"M7 10l5 5 5-5z"})],-1)]),512),[[ca,qe.value]]),i("div",Wa,[j.value.length>0?(v(),p("div",Ja,[(v(true),p(z,null,ce(j.value,t=>(v(),p("div",{key:t.tempId,class:"image-preview-item"},[i("img",{src:t.preview,alt:t.filename,class:"preview-image"},null,8,Va),i("button",{class:"remove-image-btn",onClick:n=>Rt(t.tempId),title:"删除图片"},a[10]||(a[10]=[i("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"currentColor"},[i("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"})],-1)]),8,Ga)]))),128))])):Q("",true),i("div",Za,[i("div",Qa,[i("button",{class:W(["add-button",{active:G.value}]),onClick:Ut,title:"更多操作"},a[11]||(a[11]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2.5","stroke-linecap":"round","stroke-linejoin":"round"},[i("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),i("line",{x1:"5",y1:"12",x2:"19",y2:"12"})],-1)]),2),G.value?(v(),p("div",{key:0,class:"action-menu",onClick:a[0]||(a[0]=ht(()=>{},["stop"]))},[i("button",{class:"action-menu-item",onClick:jt},a[12]||(a[12]=[i("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[i("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),i("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),i("polyline",{points:"21,15 16,10 5,21"})],-1),He(" 上传图片 ",-1)]))])):Q("",true)]),ft(i("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>he.value=t),type:"text",placeholder:bt.value,onKeyup:ia(tt,["enter"]),disabled:!Ct.value,ref_key:"messageInput",ref:me,onPaste:Nt},null,40,Ea),[[ua,he.value]]),i("button",{onClick:tt,disabled:!Qe.value,class:W({"is-sending":ne.value})},C(ne.value?"发送中...":"发送"),11,en)]),i("input",{type:"file",ref_key:"fileInput",ref:Le,onChange:At,accept:"image/*",multiple:"",style:{display:"none"}},null,544)])]))]),x.value.show?(v(),p("div",{key:0,class:"context-menu",style:Me({left:x.value.x+"px",top:x.value.y+"px"}),onClick:a[6]||(a[6]=ht(()=>{},["stop"]))},[x.value.type==="bot"?(v(),p(z,{key:0},[i("div",{class:"context-menu-item",onClick:a[2]||(a[2]=t=>Dt(x.value.targetId))},C(X.value.has(x.value.targetId)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[3]||(a[3]=t=>Tt(x.value.targetId))}," 彻底删除此机器人所有数据 ")],64)):Q("",true),x.value.type==="channel"?(v(),p(z,{key:1},[i("div",{class:"context-menu-item",onClick:a[4]||(a[4]=t=>Lt(x.value.targetId))},C(Y.value.has(`${m.value}:${x.value.targetId}`)?"取消置顶":"置顶"),1),i("div",{class:"context-menu-item danger",onClick:a[5]||(a[5]=t=>qt(x.value.targetId))}," 彻底删除此频道所有数据 ")],64)):Q("",true)],4)):Q("",true),i("div",{class:W(["swipe-indicator",{show:Z.value.show}])},C(Z.value.text),3)],38))}}),yt=(ee,J)=>{const te=ee.__vccOpts||ee;for(const[de,Se]of J)te[de]=Se;return te},rn=yt(sn,[["__scopeId","data-v-fbeb5b9c"]]),ln={},on={class:"k-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none"};function cn(ee,J){return v(),p("svg",on,J[0]||(J[0]=[i("path",{d:"M8 10.5H16",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("path",{d:"M8 14H13.5",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),i("path",{d:"M17 3.33782C15.5291 2.48697 13.8214 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22C17.5228 22 22 17.5228 22 12C22 10.1786 21.513 8.47087 20.6622 7",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)]))}const un=yt(ln,[["render",cn]]);fa.register("activity:chat",un);const hn=ee=>{ee.page({name:"聊天室",path:"/chat-patch",desc:"",authority:4,icon:"activity:chat",component:E({setup(){return()=>d(da("k-layout"),{},{default:()=>d(rn)})}})})};export{hn as default};
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .message-quote[data-v-fc970c70]{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-fc970c70]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-fc970c70]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-fc970c70]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-fc970c70]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-fc970c70]{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-fc970c70]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-fc970c70]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-fc970c70]{color:#7276b7;line-height:1.3;word-wrap:break-word}.quote-content .message-image[data-v-fc970c70]{max-width:200px;max-height:100px}.quote-content .message-image-container[data-v-fc970c70]{margin:2px 0}@media (prefers-color-scheme: dark){.message-quote[data-v-fc970c70]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-fc970c70]{color:#adb5bd}.quote-username[data-v-fc970c70]{color:#0d6efd}}.chat-container[data-v-fc970c70]{display:flex;height:100vh;background:transparent;margin-left:0%;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-fc970c70],.channel-list[data-v-fc970c70],.message-area[data-v-fc970c70]{display:flex;flex-direction:column;background:transparent;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-fc970c70]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-fc970c70]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-fc970c70]{flex:1;border-right:none}.panel-header[data-v-fc970c70]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:transparent;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-fc970c70]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-fc970c70]{display:none;background:none;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-fc970c70]:hover{background:#8080801a}.bot-items[data-v-fc970c70],.channel-items[data-v-fc970c70]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-fc970c70],.channel-item[data-v-fc970c70]{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-fc970c70]:hover,.channel-item[data-v-fc970c70]:hover{background:#8080801a}.bot-item.active[data-v-fc970c70],.channel-item.active[data-v-fc970c70]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-fc970c70]{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-fc970c70]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-fc970c70]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-fc970c70]{flex:1}.bot-name[data-v-fc970c70]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-fc970c70]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-fc970c70]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-fc970c70]{background:#4caf50}.bot-status.offline[data-v-fc970c70]{background:#f44336}.channel-info[data-v-fc970c70]{flex:1}.channel-name[data-v-fc970c70]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-fc970c70]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-fc970c70]{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-fc970c70]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-fc970c70]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble[data-v-fc970c70]:active,.channel-message-count.draggable-bubble.dragging[data-v-fc970c70]{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-fc970c70]{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-fc970c70]{background:#f44336!important;animation:shake-fc970c70 .3s ease-in-out infinite}@keyframes pulseThreshold-fc970c70{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-fc970c70{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-fc970c70]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-fc970c70]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-fc970c70]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-fc970c70]:hover{background-color:#8080801a}.message-item.new-message[data-v-fc970c70]{background-color:#4caf5033;animation:highlight-fc970c70 2s ease-out}.message-item.bot-message[data-v-fc970c70]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-fc970c70]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-fc970c70]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-fc970c70]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-fc970c70]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-fc970c70]{order:1}.message-item.bot-message .message-text[data-v-fc970c70]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left}@keyframes highlight-fc970c70{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-fc970c70]{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-fc970c70]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-fc970c70]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-fc970c70]{flex:1}.message-header[data-v-fc970c70]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-fc970c70]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-fc970c70]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-fc970c70]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;max-width:100%;overflow-wrap:break-word}.message-item:not(.bot-message) .message-text[data-v-fc970c70]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%}.message-input[data-v-fc970c70]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:transparent;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-fc970c70]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-fc970c70]{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-fc970c70]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-fc970c70]:active{transform:scale(.95)}.input-row button[data-v-fc970c70]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-fc970c70]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-fc970c70]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease}.message-image-loading[data-v-fc970c70]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-fc970c70]{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-fc970c70]{display:block;margin-bottom:4px}.message-paragraph[data-v-fc970c70]:last-child{margin-bottom:0}.forward-message-container[data-v-fc970c70]{border:1px solid #ffffff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-fc970c70]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-fc970c70]:hover{background:#f0f0f0}.forward-message-title[data-v-fc970c70]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-fc970c70]{color:#666;font-size:13px;margin:2px 0;line-height:1.4}.forward-message-footer[data-v-fc970c70]{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-fc970c70]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-fc970c70]{color:#666;font-size:12px}.forward-message-expanded[data-v-fc970c70]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-fc970c70]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-fc970c70]:last-child{border-bottom:none}.forwarded-message-header[data-v-fc970c70]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-fc970c70]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-fc970c70]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-fc970c70]{color:#555;font-size:13px;line-height:1.4}.message-at[data-v-fc970c70]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-fc970c70]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-fc970c70]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:none;background:transparent;color:currentColor}.input-row input[data-v-fc970c70]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-fc970c70]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-fc970c70]{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-fc970c70]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-fc970c70]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-fc970c70]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-fc970c70]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-fc970c70]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-fc970c70]{display:inline}.message-image-container[data-v-fc970c70]{display:block;margin:4px 0}.message-image[data-v-fc970c70]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-fc970c70]:hover{transform:scale(1.02)}.message-image-loading[data-v-fc970c70]{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-fc970c70]{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-fc970c70]{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-fc970c70]:hover{background:#2196f333}.message-unknown[data-v-fc970c70]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-fc970c70{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-fc970c70]{background:#f44336!important;animation:shake-fc970c70 .3s ease-in-out infinite}@keyframes shake-fc970c70{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-fc970c70]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-fc970c70]{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-fc970c70 1.5s ease-in-out infinite}.context-menu[data-v-fc970c70]{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-fc970c70]{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-fc970c70]:last-child{border-bottom:none}.context-menu-item[data-v-fc970c70]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-fc970c70]{color:#d32f2f}.context-menu-item.danger[data-v-fc970c70]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-fc970c70],.channel-item.pinned[data-v-fc970c70]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-fc970c70]:before,.channel-item.pinned[data-v-fc970c70]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-fc970c70],.channel-item.pinned[data-v-fc970c70]{position:relative;padding-left:24px}@media (prefers-color-scheme: dark){.context-menu[data-v-fc970c70]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-fc970c70]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-fc970c70]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-fc970c70]{color:#ff8a80}.context-menu-item.danger[data-v-fc970c70]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-fc970c70],.channel-item.pinned[data-v-fc970c70]{background:#ffc10726}}.message-share-card[data-v-fc970c70]{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-fc970c70]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-fc970c70]{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-fc970c70]{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-fc970c70]{transform:scale(1.05)}.share-card-content[data-v-fc970c70]{padding:8px}.share-card-header[data-v-fc970c70]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-fc970c70]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-fc970c70]{flex:1;min-width:0}.share-card-app-name[data-v-fc970c70]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-fc970c70]{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-fc970c70]{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-fc970c70]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-fc970c70]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-fc970c70]:after{transform:translate(2px)}.message-json-error[data-v-fc970c70],.message-json-raw[data-v-fc970c70]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-fc970c70]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-fc970c70]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-fc970c70]{margin-top:8px}.json-raw-data summary[data-v-fc970c70]{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-fc970c70]:hover{background:#2196f333}.json-raw-content[data-v-fc970c70]{margin-top:8px;padding:12px;background:#8080801a;border-radius:8px;font-family:Courier New,monospace;font-size:12px;color:currentColor;opacity:.8;white-space:pre-wrap;word-wrap:break-word;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme: dark){.message-share-card[data-v-fc970c70]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-fc970c70]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-fc970c70]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width: 768px){.chat-container[data-v-fc970c70]{position:relative}.bot-list[data-v-fc970c70],.channel-list[data-v-fc970c70],.message-area[data-v-fc970c70]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-fc970c70]{transform:translate(0);z-index:3}.channel-list[data-v-fc970c70]{transform:translate(100%);z-index:2}.message-area[data-v-fc970c70]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-fc970c70]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-fc970c70]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-fc970c70]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-fc970c70]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-fc970c70]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-fc970c70]{transform:translate(0);z-index:3}.back-button[data-v-fc970c70]{display:none!important}.panel-header[data-v-fc970c70]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-fc970c70]{text-align:right}.floating-scroll-button[data-v-fc970c70]{right:16px;bottom:70px;width:40px;height:40px}.message-input[data-v-fc970c70]{padding:8px 12px 12px;position:fixed;bottom:0;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10}.input-row input[data-v-fc970c70]{font-size:16px;padding:10px 12px}.input-row button[data-v-fc970c70]{padding:10px 16px;font-size:16px}.message-history[data-v-fc970c70]{padding:12px 12px 80px;max-height:calc(100vh - 140px)}.message-item[data-v-fc970c70]{margin-bottom:12px;padding:6px}.message-avatar[data-v-fc970c70]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-fc970c70]{margin-left:8px}.message-image[data-v-fc970c70]{max-width:280px;max-height:160px}.quote-content .message-image[data-v-fc970c70]{max-width:150px;max-height:80px}.context-menu[data-v-fc970c70]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-fc970c70]{padding:14px 16px;font-size:16px}.bot-item[data-v-fc970c70],.channel-item[data-v-fc970c70]{padding:14px 16px}.bot-avatar[data-v-fc970c70]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-fc970c70],.channel-name[data-v-fc970c70]{font-size:15px}.bot-platform[data-v-fc970c70],.channel-type[data-v-fc970c70]{font-size:13px}}@media (min-width: 769px) and (max-width: 1024px){.bot-list[data-v-fc970c70]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-fc970c70]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-fc970c70]{max-width:350px;max-height:180px}}.chat-container.swiping[data-v-fc970c70]{overflow:hidden}.bot-list.swiping[data-v-fc970c70],.channel-list.swiping[data-v-fc970c70],.message-area.swiping[data-v-fc970c70]{transition:none!important}.swipe-indicator[data-v-fc970c70]{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-fc970c70]{opacity:1}.message-area .message-content[data-v-fc970c70]{padding-bottom:80px}.image-preview-container[data-v-fc970c70]{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-fc970c70]{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-fc970c70]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-fc970c70]{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-fc970c70]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-fc970c70]{position:relative;margin-right:8px}.add-button[data-v-fc970c70]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea,#764ba2);border:none;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;box-shadow:0 2px 8px #667eea4d;position:relative;overflow:hidden}.add-button[data-v-fc970c70]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-fc970c70]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-fc970c70]:hover:before{opacity:1}.add-button.active[data-v-fc970c70]{background:linear-gradient(135deg,#f093fb,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-fc970c70]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-fc970c70]{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-fc970c70 .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-fc970c70]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:none;border:none;color:#333;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);width:100%;text-align:left;position:relative}.action-menu-item[data-v-fc970c70]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-fc970c70]:hover{background:linear-gradient(90deg,#667eea14,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-fc970c70]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-fc970c70]{flex-shrink:0}@media (prefers-color-scheme: dark){.action-menu[data-v-fc970c70]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-fc970c70]{color:#fff}.action-menu-item[data-v-fc970c70]:before{background:linear-gradient(135deg,#4facfe,#00f2fe)}.action-menu-item[data-v-fc970c70]:hover{background:linear-gradient(90deg,#4facfe1f,#00f2fe1f);color:#4facfe}.add-button[data-v-fc970c70]{background:linear-gradient(135deg,#4facfe,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-fc970c70]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-fc970c70]{background:linear-gradient(135deg,#fa709a,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-fc970c70]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width: 768px){.image-preview-container[data-v-fc970c70]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-fc970c70]{width:50px;height:50px}.add-button[data-v-fc970c70]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-fc970c70]{min-width:100px}.action-menu-item[data-v-fc970c70]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-fc970c70]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-fc970c70]::-webkit-scrollbar{width:6px}.message-history[data-v-fc970c70]::-webkit-scrollbar-track{background:transparent}.message-history[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-fc970c70]::-webkit-scrollbar{width:6px}.bot-items[data-v-fc970c70]::-webkit-scrollbar-track{background:transparent}.bot-items[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-fc970c70]::-webkit-scrollbar{width:6px}.channel-items[data-v-fc970c70]::-webkit-scrollbar-track{background:transparent}.channel-items[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar-track{background:transparent}.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-fc970c70]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-fc970c70]::-webkit-scrollbar-track{background:transparent}.json-raw-content[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme: dark){.message-history[data-v-fc970c70]::-webkit-scrollbar-thumb,.bot-items[data-v-fc970c70]::-webkit-scrollbar-thumb,.channel-items[data-v-fc970c70]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar-thumb,.json-raw-content[data-v-fc970c70]::-webkit-scrollbar-thumb{background-color:#fff3}.message-history[data-v-fc970c70]::-webkit-scrollbar-thumb:hover,.bot-items[data-v-fc970c70]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-fc970c70]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-fc970c70]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-fc970c70]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
1
+ .message-quote[data-v-fbeb5b9c]{margin:8px 0;padding:8px 12px;background-color:#bebebe1a;border-left:4px solid rgba(151,152,152,.45);border-radius:6px;font-size:.9em;position:relative}.quote-indicator[data-v-fbeb5b9c]{font-size:.75em;color:#007bff;font-weight:600;margin-bottom:4px;text-transform:uppercase}.quote-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:4px;gap:6px}.quote-avatar[data-v-fbeb5b9c]{width:20px;height:20px;border-radius:50%;overflow:hidden;flex-shrink:0}.quote-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.quote-avatar .avatar-placeholder[data-v-fbeb5b9c]{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#6c757d;color:#fff;font-size:10px;font-weight:700}.quote-username[data-v-fbeb5b9c]{font-weight:600;color:#007bff;font-size:.85em}.quote-time[data-v-fbeb5b9c]{color:#6c757d;font-size:.75em;margin-left:auto}.quote-content[data-v-fbeb5b9c]{color:#7276b7;line-height:1.3;word-wrap:break-word}.quote-content .message-image[data-v-fbeb5b9c]{max-width:200px;max-height:100px}.quote-content .message-image-container[data-v-fbeb5b9c]{margin:2px 0}@media (prefers-color-scheme: dark){.message-quote[data-v-fbeb5b9c]{background-color:#ffffff14;border-left-color:#0d6efd}.quote-content[data-v-fbeb5b9c]{color:#adb5bd}.quote-username[data-v-fbeb5b9c]{color:#0d6efd}}.chat-container[data-v-fbeb5b9c]{display:flex;height:100vh;background:transparent;margin-left:0%;width:100%;overflow:hidden;color:inherit;position:relative}.bot-list[data-v-fbeb5b9c],.channel-list[data-v-fbeb5b9c],.message-area[data-v-fbeb5b9c]{display:flex;flex-direction:column;background:transparent;border-right:1px solid rgba(128,128,128,.2)}.bot-list[data-v-fbeb5b9c]{width:250px;min-width:250px;max-width:250px;flex-shrink:0}.channel-list[data-v-fbeb5b9c]{width:300px;min-width:300px;max-width:300px;flex-shrink:0}.message-area[data-v-fbeb5b9c]{flex:1;border-right:none}.panel-header[data-v-fbeb5b9c]{padding:16px;border-bottom:1px solid rgba(128,128,128,.2);background:transparent;display:flex;align-items:center;justify-content:space-between}.panel-header h3[data-v-fbeb5b9c]{margin:0;font-size:16px;font-weight:600;color:currentColor}.back-button[data-v-fbeb5b9c]{display:none;background:none;border:none;color:currentColor;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:4px;transition:background-color .2s}.back-button[data-v-fbeb5b9c]:hover{background:#8080801a}.bot-items[data-v-fbeb5b9c],.channel-items[data-v-fbeb5b9c]{flex:1;overflow-y:auto;max-height:calc(100vh - 60px)}.bot-item[data-v-fbeb5b9c],.channel-item[data-v-fbeb5b9c]{display:flex;align-items:center;padding:12px 16px;cursor:pointer;border-bottom:1px solid rgba(128,128,128,.1);transition:background-color .2s}.bot-item[data-v-fbeb5b9c]:hover,.channel-item[data-v-fbeb5b9c]:hover{background:#8080801a}.bot-item.active[data-v-fbeb5b9c],.channel-item.active[data-v-fbeb5b9c]{background:#2196f31a;border-right:3px solid #2196f3}.bot-avatar[data-v-fbeb5b9c]{width:40px;height:40px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0}.bot-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.avatar-placeholder[data-v-fbeb5b9c]{font-size:16px;font-weight:700;color:currentColor;opacity:.7}.bot-info[data-v-fbeb5b9c]{flex:1}.bot-name[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-bottom:2px}.bot-platform[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7}.bot-status[data-v-fbeb5b9c]{width:8px;height:8px;border-radius:50%;margin-left:8px}.bot-status.online[data-v-fbeb5b9c]{background:#4caf50}.bot-status.offline[data-v-fbeb5b9c]{background:#f44336}.channel-info[data-v-fbeb5b9c]{flex:1}.channel-name[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-bottom:2px}.channel-type[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7}.channel-message-count[data-v-fbeb5b9c]{background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;position:relative;transition:all .2s ease}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]{cursor:grab;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 2px 8px #2196f34d}.channel-message-count.draggable-bubble[data-v-fbeb5b9c]:active,.channel-message-count.draggable-bubble.dragging[data-v-fbeb5b9c]{cursor:grabbing;background:#1565c0;box-shadow:0 4px 12px #2196f366}.dragging-clone[data-v-fbeb5b9c]{position:fixed;z-index:1000;pointer-events:none;transition:none;box-sizing:border-box;display:flex;align-items:center;justify-content:center;background:#2196f3;color:#fff;font-size:12px;padding:2px 6px;border-radius:10px;min-width:18px;text-align:center;box-shadow:0 4px 12px #2196f366}.dragging-clone.will-delete[data-v-fbeb5b9c]{background:#f44336!important;animation:shake-fbeb5b9c .3s ease-in-out infinite}@keyframes pulseThreshold-fbeb5b9c{0%,to{opacity:.4;transform:scale(.9);border-color:#f4433699;box-shadow:0 0 15px #f4433633}50%{opacity:.8;transform:scale(1.1);border-color:#f44336;box-shadow:0 0 25px #f4433666}}@keyframes menuSlideIn-fbeb5b9c{0%{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}.message-content[data-v-fbeb5b9c]{display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden;position:relative}.message-history[data-v-fbeb5b9c]{flex:1;overflow-y:auto;padding:16px 16px 8px;max-height:calc(100vh - 200px)}.message-item[data-v-fbeb5b9c]{display:flex;margin-bottom:16px;padding:8px;border-radius:8px;transition:background-color .3s ease}.message-item[data-v-fbeb5b9c]:hover{background-color:#8080801a}.message-item.new-message[data-v-fbeb5b9c]{background-color:#4caf5033;animation:highlight-fbeb5b9c 2s ease-out}.message-item.bot-message[data-v-fbeb5b9c]{flex-direction:row-reverse;justify-content:flex-start}.message-item.bot-message .message-avatar[data-v-fbeb5b9c]{margin-right:0;margin-left:12px}.message-item.bot-message .message-content-wrapper[data-v-fbeb5b9c]{display:flex;flex-direction:column;align-items:flex-end}.message-item.bot-message .message-header[data-v-fbeb5b9c]{display:flex;align-items:center;justify-content:flex-end;margin-bottom:4px}.message-item.bot-message .message-username[data-v-fbeb5b9c]{margin-right:0;margin-left:8px;order:2}.message-item.bot-message .message-time[data-v-fbeb5b9c]{order:1}.message-item.bot-message .message-text[data-v-fbeb5b9c]{background-color:#2196f31a;padding:8px 12px;border-radius:12px 12px 4px;display:inline-block;max-width:80%;text-align:left}@keyframes highlight-fbeb5b9c{0%{background-color:#4caf504d}to{background-color:transparent}}.message-avatar[data-v-fbeb5b9c]{width:32px;height:32px;margin-right:12px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#e0e0e0;flex-shrink:0}.message-avatar img[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover}.message-avatar .avatar-placeholder[data-v-fbeb5b9c]{font-size:12px;font-weight:700;color:currentColor;opacity:.7}.message-content-wrapper[data-v-fbeb5b9c]{flex:1}.message-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:4px}.message-username[data-v-fbeb5b9c]{font-weight:500;color:currentColor;margin-right:8px}.message-time[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.5}.message-text[data-v-fbeb5b9c]{color:currentColor;line-height:1.4;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;max-width:100%;overflow-wrap:break-word}.message-item:not(.bot-message) .message-text[data-v-fbeb5b9c]{background-color:#8080801a;padding:8px 12px;border-radius:12px 12px 12px 4px;display:inline-block;max-width:80%}.message-input[data-v-fbeb5b9c]{display:flex;flex-direction:column;padding:12px 16px 16px;border-top:1px solid rgba(128,128,128,.2);background:transparent;flex-shrink:0;position:sticky;bottom:0;margin-top:-10px}.input-row[data-v-fbeb5b9c]{display:flex;gap:8px;align-items:center}.floating-scroll-button[data-v-fbeb5b9c]{position:absolute;right:24px;bottom:18%;width:48px;height:48px;background:#2196f3;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px #2196f34d;color:#fff;transition:all .3s ease;z-index:100;border:2px solid rgba(255,255,255,.2)}.floating-scroll-button[data-v-fbeb5b9c]:hover{background:#1976d2;transform:scale(1.1);box-shadow:0 6px 16px #2196f366}.floating-scroll-button[data-v-fbeb5b9c]:active{transform:scale(.95)}.input-row button[data-v-fbeb5b9c]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s}.message-image-container[data-v-fbeb5b9c]{margin:8px 0;max-width:100%;display:block}.message-image[data-v-fbeb5b9c]{border-radius:8px;object-fit:contain;display:block;cursor:pointer;transition:transform .2s ease}.message-image-loading[data-v-fbeb5b9c]{display:inline-block;padding:8px 12px;background:#8080801a;border-radius:4px;color:currentColor;opacity:.7;font-size:12px}.message-image-error[data-v-fbeb5b9c]{display:inline-block;padding:8px 12px;background:#f443361a;border:1px solid rgba(244,67,54,.3);border-radius:4px;color:#f44336;font-size:12px;max-width:300px;word-break:break-word}.message-paragraph[data-v-fbeb5b9c]{display:block;margin-bottom:4px}.message-paragraph[data-v-fbeb5b9c]:last-child{margin-bottom:0}.forward-message-container[data-v-fbeb5b9c]{border:1px solid #ffffff;border-radius:8px;margin:4px 0;overflow:hidden;background:#f9f9f900}.forward-message-preview[data-v-fbeb5b9c]{padding:12px;cursor:pointer;transition:background-color .2s}.forward-message-preview[data-v-fbeb5b9c]:hover{background:#f0f0f0}.forward-message-title[data-v-fbeb5b9c]{font-weight:600;color:#333;margin-bottom:8px;font-size:14px}.forward-message-preview-item[data-v-fbeb5b9c]{color:#666;font-size:13px;margin:2px 0;line-height:1.4}.forward-message-footer[data-v-fbeb5b9c]{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px solid #e8e8e8}.forward-message-count[data-v-fbeb5b9c]{color:#2196f3;font-size:12px}.forward-message-toggle[data-v-fbeb5b9c]{color:#666;font-size:12px}.forward-message-expanded[data-v-fbeb5b9c]{border-top:1px solid #e0e0e0;background:#fff;max-height:400px;overflow-y:auto}.forwarded-message-item[data-v-fbeb5b9c]{padding:12px;border-bottom:1px solid #f0f0f0}.forwarded-message-item[data-v-fbeb5b9c]:last-child{border-bottom:none}.forwarded-message-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:6px}.forwarded-message-nickname[data-v-fbeb5b9c]{font-weight:600;color:#333;font-size:13px}.forwarded-message-userid[data-v-fbeb5b9c]{color:#999;font-size:11px;margin-left:6px}.forwarded-message-content[data-v-fbeb5b9c]{color:#555;font-size:13px;line-height:1.4}.message-at[data-v-fbeb5b9c]{background:#2196f31a;color:#2196f3;padding:2px 4px;border-radius:3px;font-weight:500;cursor:pointer}.message-unknown[data-v-fbeb5b9c]{background:#ff98001a;color:#ff9800;padding:2px 4px;border-radius:3px;font-style:italic;cursor:help}.input-row input[data-v-fbeb5b9c]{flex:1;min-width:0;padding:8px 12px;border:1px solid rgba(128,128,128,.3);border-radius:4px;outline:none;background:transparent;color:currentColor}.input-row input[data-v-fbeb5b9c]:focus{border-color:#2196f3;box-shadow:0 0 0 2px #2196f333}.input-row input[data-v-fbeb5b9c]::placeholder{color:currentColor;opacity:.5}.input-row button[data-v-fbeb5b9c]{padding:8px 16px;background:#2196f3;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;flex-shrink:0;white-space:nowrap}.input-row button[data-v-fbeb5b9c]:hover:not(:disabled){background:#1976d2}.input-row button[data-v-fbeb5b9c]:disabled{background:#8080804d;cursor:not-allowed}.input-row button.is-sending[data-v-fbeb5b9c]{background:#ffc107!important;color:#333!important;cursor:default!important}.message-input .input-row button.is-sending[data-v-fbeb5b9c]{background:#ffc107!important;color:#333!important;cursor:default!important;border-color:#ffc107!important}.empty-state[data-v-fbeb5b9c]{display:flex;align-items:center;justify-content:center;height:100%;color:currentColor;opacity:.5;font-size:14px}.message-text-content[data-v-fbeb5b9c]{display:inline}.message-image-container[data-v-fbeb5b9c]{display:block;margin:4px 0}.message-image[data-v-fbeb5b9c]{border-radius:8px;margin:4px 0;display:block;cursor:pointer;transition:transform .2s ease;object-fit:contain;background:#8080801a}.message-image[data-v-fbeb5b9c]:hover{transform:scale(1.02)}.message-image-loading[data-v-fbeb5b9c]{height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3)}.message-image-error[data-v-fbeb5b9c]{min-height:60px;width:200px;border-radius:8px;margin:4px 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#8080801a;color:currentColor;opacity:.7;font-size:14px;border:1px dashed rgba(128,128,128,.3);padding:8px;text-align:center}.message-at[data-v-fbeb5b9c]{background:#2196f31a;color:#2196f3;padding:2px 6px;border-radius:4px;font-weight:500;cursor:pointer;display:inline-block;margin:0 2px}.message-at[data-v-fbeb5b9c]:hover{background:#2196f333}.message-unknown[data-v-fbeb5b9c]{background:#ff98001a;color:#ff9800;padding:2px 6px;border-radius:4px;font-size:12px;display:inline-block;margin:0 2px;cursor:help}@keyframes pulse-fbeb5b9c{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.1)}}.channel-message-count.will-delete[data-v-fbeb5b9c]{background:#f44336!important;animation:shake-fbeb5b9c .3s ease-in-out infinite}@keyframes shake-fbeb5b9c{0%,to{transform:translate(0)}25%{transform:translate(-2px)}75%{transform:translate(2px)}}body.dragging-bubble-global[data-v-fbeb5b9c]{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:grabbing}.drag-threshold-circle[data-v-fbeb5b9c]{position:fixed;pointer-events:none;border:3px dashed rgba(244,67,54,.8);border-radius:50%;z-index:999;background:#f443361a;box-shadow:0 0 20px #f443364d;animation:pulseThreshold-fbeb5b9c 1.5s ease-in-out infinite}.context-menu[data-v-fbeb5b9c]{position:fixed;background:#ffffffa6;border:1px solid rgba(0,0,0,.1);border-radius:8px;box-shadow:0 8px 32px #00000026;z-index:10000;min-width:180px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);overflow:hidden}.context-menu-item[data-v-fbeb5b9c]{padding:12px 16px;cursor:pointer;color:#333;font-size:14px;font-weight:500;transition:all .2s ease;border-bottom:1px solid rgba(0,0,0,.08);position:relative}.context-menu-item[data-v-fbeb5b9c]:last-child{border-bottom:none}.context-menu-item[data-v-fbeb5b9c]:hover{background:#2196f31a;color:#1976d2;transform:translate(2px)}.context-menu-item.danger[data-v-fbeb5b9c]{color:#d32f2f}.context-menu-item.danger[data-v-fbeb5b9c]:hover{background:#f443361a;color:#c62828}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{background:#ffc1071a;border-left:3px solid #ffc107}.bot-item.pinned[data-v-fbeb5b9c]:before,.channel-item.pinned[data-v-fbeb5b9c]:before{content:"📌";position:absolute;left:4px;top:50%;transform:translateY(-50%);font-size:12px;opacity:.7}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{position:relative;padding-left:24px}@media (prefers-color-scheme: dark){.context-menu[data-v-fbeb5b9c]{background:#ffffff26;border-color:#fff3;box-shadow:0 8px 32px #0006}.context-menu-item[data-v-fbeb5b9c]{color:#fff;border-bottom-color:#ffffff1a}.context-menu-item[data-v-fbeb5b9c]:hover{background:#2196f333;color:#64b5f6}.context-menu-item.danger[data-v-fbeb5b9c]{color:#ff8a80}.context-menu-item.danger[data-v-fbeb5b9c]:hover{background:#f4433633;color:#ffab91}.bot-item.pinned[data-v-fbeb5b9c],.channel-item.pinned[data-v-fbeb5b9c]{background:#ffc10726}}.message-share-card[data-v-fbeb5b9c]{display:inline-block;width:75px;margin:8px 0;border:1px solid rgba(128,128,128,.2);border-radius:12px;background:#ffffff0d;transition:all .3s ease;cursor:pointer;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.message-share-card[data-v-fbeb5b9c]:hover{transform:translateY(-2px);box-shadow:0 8px 24px #00000026;border-color:#2196f34d}.share-card-preview[data-v-fbeb5b9c]{width:100%;position:relative;display:flex;align-items:center;justify-content:center;padding:4px;border-radius:12px 12px 0 0}.share-card-image[data-v-fbeb5b9c]{max-width:calc(100% - 8px);width:auto;height:auto;object-fit:contain;transition:transform .3s ease;display:block;border-radius:4px}.message-share-card:hover .share-card-image[data-v-fbeb5b9c]{transform:scale(1.05)}.share-card-content[data-v-fbeb5b9c]{padding:8px}.share-card-header[data-v-fbeb5b9c]{display:flex;align-items:center;margin-bottom:12px;gap:12px}.share-card-icon[data-v-fbeb5b9c]{width:32px;height:32px;border-radius:8px;object-fit:cover;flex-shrink:0}.share-card-app-info[data-v-fbeb5b9c]{flex:1;min-width:0}.share-card-app-name[data-v-fbeb5b9c]{font-size:12px;color:currentColor;opacity:.7;margin-bottom:2px;font-weight:500}.share-card-title[data-v-fbeb5b9c]{font-size:10px;font-weight:600;color:currentColor;line-height:1.2;word-wrap:break-word;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}.share-card-desc[data-v-fbeb5b9c]{font-size:14px;color:currentColor;opacity:.8;line-height:1.4;margin-bottom:12px;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;word-wrap:break-word}.share-card-link-hint[data-v-fbeb5b9c]{font-size:12px;color:#2196f3;font-weight:500;display:flex;align-items:center;gap:4px}.share-card-link-hint[data-v-fbeb5b9c]:after{content:"→";transition:transform .2s ease}.message-share-card:hover .share-card-link-hint[data-v-fbeb5b9c]:after{transform:translate(2px)}.message-json-error[data-v-fbeb5b9c],.message-json-raw[data-v-fbeb5b9c]{display:inline-block;margin:8px 0;max-width:400px}.json-error-text[data-v-fbeb5b9c]{color:#f44336;font-size:14px;font-weight:500}.json-label[data-v-fbeb5b9c]{color:currentColor;opacity:.7;font-size:12px;font-weight:500;margin-bottom:8px}.json-raw-data[data-v-fbeb5b9c]{margin-top:8px}.json-raw-data summary[data-v-fbeb5b9c]{cursor:pointer;font-size:12px;color:#2196f3;font-weight:500;padding:4px 8px;border-radius:4px;background:#2196f31a;display:inline-block;transition:background-color .2s ease}.json-raw-data summary[data-v-fbeb5b9c]:hover{background:#2196f333}.json-raw-content[data-v-fbeb5b9c]{margin-top:8px;padding:12px;background:#8080801a;border-radius:8px;font-family:Courier New,monospace;font-size:12px;color:currentColor;opacity:.8;white-space:pre-wrap;word-wrap:break-word;max-height:200px;overflow-y:auto;border:1px solid rgba(128,128,128,.2)}@media (prefers-color-scheme: dark){.message-share-card[data-v-fbeb5b9c]{background:#ffffff14;border-color:#ffffff26}.message-share-card[data-v-fbeb5b9c]:hover{border-color:#2196f380;box-shadow:0 8px 24px #0000004d}.json-raw-content[data-v-fbeb5b9c]{background:#ffffff0d;border-color:#ffffff1a}}@media (max-width: 768px){.chat-container[data-v-fbeb5b9c]{position:relative}.bot-list[data-v-fbeb5b9c],.channel-list[data-v-fbeb5b9c],.message-area[data-v-fbeb5b9c]{position:absolute;top:0;left:0;width:100%;height:100%;transition:transform .3s ease;z-index:1}.bot-list[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.channel-list[data-v-fbeb5b9c]{transform:translate(100%);z-index:2}.message-area[data-v-fbeb5b9c]{transform:translate(200%);z-index:1}.chat-container.show-channels .bot-list[data-v-fbeb5b9c]{transform:translate(-100%)}.chat-container.show-channels .channel-list[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.chat-container.show-channels .message-area[data-v-fbeb5b9c]{transform:translate(100%)}.chat-container.show-messages .bot-list[data-v-fbeb5b9c]{transform:translate(-200%)}.chat-container.show-messages .channel-list[data-v-fbeb5b9c]{transform:translate(-100%)}.chat-container.show-messages .message-area[data-v-fbeb5b9c]{transform:translate(0);z-index:3}.back-button[data-v-fbeb5b9c]{display:none!important}.panel-header[data-v-fbeb5b9c]{flex-direction:row-reverse;position:sticky;top:0;z-index:5;background:inherit}.panel-header h3[data-v-fbeb5b9c]{text-align:right}.floating-scroll-button[data-v-fbeb5b9c]{right:16px;bottom:70px;width:40px;height:40px}.message-input[data-v-fbeb5b9c]{padding:8px 12px 12px;position:fixed;bottom:0;left:0;right:0;background:inherit;border-top:1px solid rgba(128,128,128,.2);z-index:10}.input-row input[data-v-fbeb5b9c]{font-size:16px;padding:10px 12px}.input-row button[data-v-fbeb5b9c]{padding:10px 16px;font-size:16px}.message-history[data-v-fbeb5b9c]{padding:12px 12px 80px;max-height:calc(100vh - 140px)}.message-item[data-v-fbeb5b9c]{margin-bottom:12px;padding:6px}.message-avatar[data-v-fbeb5b9c]{width:28px;height:28px;margin-right:8px}.message-item.bot-message .message-avatar[data-v-fbeb5b9c]{margin-left:8px}.message-image[data-v-fbeb5b9c]{max-width:280px;max-height:160px}.quote-content .message-image[data-v-fbeb5b9c]{max-width:150px;max-height:80px}.context-menu[data-v-fbeb5b9c]{min-width:160px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.context-menu-item[data-v-fbeb5b9c]{padding:14px 16px;font-size:16px}.bot-item[data-v-fbeb5b9c],.channel-item[data-v-fbeb5b9c]{padding:14px 16px}.bot-avatar[data-v-fbeb5b9c]{width:36px;height:36px;margin-right:10px}.bot-name[data-v-fbeb5b9c],.channel-name[data-v-fbeb5b9c]{font-size:15px}.bot-platform[data-v-fbeb5b9c],.channel-type[data-v-fbeb5b9c]{font-size:13px}}@media (min-width: 769px) and (max-width: 1024px){.bot-list[data-v-fbeb5b9c]{width:220px;min-width:220px;max-width:220px}.channel-list[data-v-fbeb5b9c]{width:280px;min-width:280px;max-width:280px}.message-image[data-v-fbeb5b9c]{max-width:350px;max-height:180px}}.chat-container.swiping[data-v-fbeb5b9c]{overflow:hidden}.bot-list.swiping[data-v-fbeb5b9c],.channel-list.swiping[data-v-fbeb5b9c],.message-area.swiping[data-v-fbeb5b9c]{transition:none!important}.swipe-indicator[data-v-fbeb5b9c]{position:fixed;top:50%;left:20px;transform:translateY(-50%);background:#2196f3cc;color:#fff;padding:8px 12px;border-radius:20px;font-size:14px;z-index:1000;opacity:0;transition:opacity .2s ease;pointer-events:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.swipe-indicator.show[data-v-fbeb5b9c]{opacity:1}.message-area .message-content[data-v-fbeb5b9c]{padding-bottom:80px}.image-preview-container[data-v-fbeb5b9c]{display:flex;flex-wrap:wrap;gap:8px;padding:8px 0;margin-bottom:8px;border-bottom:1px solid rgba(128,128,128,.1)}.image-preview-item[data-v-fbeb5b9c]{position:relative;width:60px;height:60px;border-radius:8px;overflow:hidden;border:2px solid rgba(33,150,243,.3);background:#8080801a}.preview-image[data-v-fbeb5b9c]{width:100%;height:100%;object-fit:cover;display:block}.remove-image-btn[data-v-fbeb5b9c]{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;background:#f44336;color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;transition:all .2s ease;box-shadow:0 2px 4px #0003}.remove-image-btn[data-v-fbeb5b9c]:hover{background:#d32f2f;transform:scale(1.1)}.input-actions[data-v-fbeb5b9c]{position:relative;margin-right:8px}.add-button[data-v-fbeb5b9c]{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#667eea,#764ba2);border:none;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;box-shadow:0 2px 8px #667eea4d;position:relative;overflow:hidden}.add-button[data-v-fbeb5b9c]:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(135deg,#fff3,#ffffff1a);border-radius:12px;opacity:0;transition:opacity .3s ease}.add-button[data-v-fbeb5b9c]:hover{transform:translateY(-2px) scale(1.05);box-shadow:0 4px 16px #667eea66}.add-button[data-v-fbeb5b9c]:hover:before{opacity:1}.add-button.active[data-v-fbeb5b9c]{background:linear-gradient(135deg,#f093fb,#f5576c);transform:translateY(-2px) scale(1.05) rotate(45deg);box-shadow:0 4px 16px #f5576c66}.add-button[data-v-fbeb5b9c]:active{transform:translateY(0) scale(.98);transition:all .1s ease}.action-menu[data-v-fbeb5b9c]{position:absolute;bottom:100%;left:0;margin-bottom:12px;background:#fffffffa;border:none;border-radius:16px;box-shadow:0 8px 32px #0000001f,0 2px 8px #00000014;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);overflow:hidden;z-index:1000;min-width:140px;transform:translateY(8px);opacity:0;animation:menuSlideIn-fbeb5b9c .3s cubic-bezier(.4,0,.2,1) forwards}.action-menu-item[data-v-fbeb5b9c]{display:flex;align-items:center;gap:12px;padding:14px 18px;background:none;border:none;color:#333;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);width:100%;text-align:left;position:relative}.action-menu-item[data-v-fbeb5b9c]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(135deg,#667eea,#764ba2);transform:scaleY(0);transition:transform .2s cubic-bezier(.4,0,.2,1)}.action-menu-item[data-v-fbeb5b9c]:hover{background:linear-gradient(90deg,#667eea14,#764ba214);color:#667eea;transform:translate(4px)}.action-menu-item[data-v-fbeb5b9c]:hover:before{transform:scaleY(1)}.action-menu-item svg[data-v-fbeb5b9c]{flex-shrink:0}@media (prefers-color-scheme: dark){.action-menu[data-v-fbeb5b9c]{background:#1e1e1efa;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003}.action-menu-item[data-v-fbeb5b9c]{color:#fff}.action-menu-item[data-v-fbeb5b9c]:before{background:linear-gradient(135deg,#4facfe,#00f2fe)}.action-menu-item[data-v-fbeb5b9c]:hover{background:linear-gradient(90deg,#4facfe1f,#00f2fe1f);color:#4facfe}.add-button[data-v-fbeb5b9c]{background:linear-gradient(135deg,#4facfe,#00f2fe);box-shadow:0 2px 8px #4facfe4d}.add-button[data-v-fbeb5b9c]:hover{box-shadow:0 4px 16px #4facfe66}.add-button.active[data-v-fbeb5b9c]{background:linear-gradient(135deg,#fa709a,#fee140);box-shadow:0 4px 16px #fa709a66}.image-preview-item[data-v-fbeb5b9c]{border-color:#64b5f680;background:#ffffff0d}}@media (max-width: 768px){.image-preview-container[data-v-fbeb5b9c]{padding:6px 0;margin-bottom:6px}.image-preview-item[data-v-fbeb5b9c]{width:50px;height:50px}.add-button[data-v-fbeb5b9c]{width:32px;height:32px;border-radius:10px}.action-menu[data-v-fbeb5b9c]{min-width:100px}.action-menu-item[data-v-fbeb5b9c]{padding:10px 12px;font-size:13px}.remove-image-btn[data-v-fbeb5b9c]{width:18px;height:18px;top:-5px;right:-5px}}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar{width:6px}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-track{background:transparent}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#9093994d;border-radius:4px;transition:background-color .3s}.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#90939980}@media (prefers-color-scheme: dark){.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb,.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb{background-color:#fff3}.message-history[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.bot-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.channel-items[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.forward-message-expanded[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover,.json-raw-content[data-v-fbeb5b9c]::-webkit-scrollbar-thumb:hover{background-color:#fff6}}.layout-iframe{width:100%;height:100%;border:none}
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.8",
4
+ "version": "1.0.9",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -1,17 +0,0 @@
1
- import { Context } from 'koishi';
2
- import { Config } from './config';
3
- import { FileManager } from './file-manager';
4
- export declare class ApiHandlers {
5
- private ctx;
6
- private config;
7
- private fileManager;
8
- private logger;
9
- constructor(ctx: Context, config: Config, fileManager: FileManager);
10
- registerApiHandlers(): void;
11
- private isFileUrl;
12
- private createFileUrl;
13
- private handleLocalFileRequest;
14
- private setupTempFileCleanup;
15
- private cleanupTempImagesByCount;
16
- private logInfo;
17
- }
package/lib/config.d.ts DELETED
@@ -1,13 +0,0 @@
1
- import { Schema } from 'koishi';
2
- export interface Config {
3
- loggerinfo: boolean;
4
- maxMessagesPerChannel: number;
5
- keepMessagesOnClear: number;
6
- keepTempImages: number;
7
- blockedPlatforms: Array<{
8
- platformName: string;
9
- exactMatch: boolean;
10
- }>;
11
- chatContainerHeight: number;
12
- }
13
- export declare const Config: Schema<Config>;
@@ -1,18 +0,0 @@
1
- import { Context } from 'koishi';
2
- import { ChatData, MessageInfo } from './types';
3
- import { Config } from './config';
4
- export declare class FileManager {
5
- private ctx;
6
- private config;
7
- private dataFilePath;
8
- private fileOperationLock;
9
- private logger;
10
- private utils;
11
- constructor(ctx: Context, config: Config);
12
- private ensureDataDir;
13
- readChatDataFromFile(): ChatData;
14
- writeChatDataToFile(data: ChatData): void;
15
- cleanExcessMessages(data: ChatData): ChatData;
16
- addMessageToFile(messageInfo: MessageInfo): Promise<void>;
17
- private logInfo;
18
- }
package/lib/index.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import { Context } from 'koishi';
2
- import { Config } from './config';
3
- export declare const name = "chat-patch";
4
- export declare const reusable = false;
5
- export declare const filter = false;
6
- export declare const inject: {
7
- required: string[];
8
- };
9
- export declare const usage = "\n\n---\n\n\u5F00\u542F\u540E\uFF0C\u5373\u53EF\u5728koishi\u63A7\u5236\u53F0\u64CD\u4F5C\u673A\u5668\u4EBA\u6536\u53D1\u6D88\u606F\u5566\n\n\u6682\u65F6\u53EA\u652F\u6301\u63A5\u53D7\u56FE\u6587\u6D88\u606F / \u53D1\u9001\u6587\u5B57\u6D88\u606F\n\n---\n";
10
- export { Config } from './config';
11
- export declare function apply(ctx: Context, config: Config): Promise<void>;
@@ -1,16 +0,0 @@
1
- import { Context, Session } from 'koishi';
2
- import { Config } from './config';
3
- import { FileManager } from './file-manager';
4
- export declare class MessageHandler {
5
- private ctx;
6
- private config;
7
- private fileManager;
8
- private logger;
9
- private utils;
10
- constructor(ctx: Context, config: Config, fileManager: FileManager);
11
- updateBotInfoToFile(session: Session): Promise<void>;
12
- updateChannelInfoToFile(session: Session): Promise<string>;
13
- broadcastMessageEvent(session: Session): Promise<void>;
14
- broadcastBotMessageEvent(session: Session): Promise<void>;
15
- private logInfo;
16
- }
package/lib/types.d.ts DELETED
@@ -1,53 +0,0 @@
1
- import { h } from 'koishi';
2
- export interface BotInfo {
3
- selfId: string;
4
- platform: string;
5
- username: string;
6
- avatar?: string;
7
- status: 'online' | 'offline';
8
- }
9
- export interface ChannelInfo {
10
- id: string;
11
- name: string;
12
- type: number | string;
13
- guildId?: string;
14
- guildName?: string;
15
- }
16
- export interface QuoteInfo {
17
- messageId: string;
18
- id: string;
19
- content: string;
20
- elements?: h[];
21
- user: {
22
- id: string;
23
- name: string;
24
- userId: string;
25
- avatar?: string;
26
- username: string;
27
- };
28
- timestamp: number;
29
- }
30
- export interface MessageInfo {
31
- id: string;
32
- content: string;
33
- userId: string;
34
- username: string;
35
- avatar?: string;
36
- timestamp: number;
37
- channelId: string;
38
- selfId: string;
39
- elements?: h[];
40
- type: 'user' | 'bot';
41
- guildId?: string;
42
- guildName?: string;
43
- platform: string;
44
- quote?: QuoteInfo;
45
- }
46
- export interface ChatData {
47
- bots: Record<string, BotInfo>;
48
- channels: Record<string, Record<string, ChannelInfo>>;
49
- messages: Record<string, MessageInfo[]>;
50
- pinnedBots: string[];
51
- pinnedChannels: string[];
52
- lastSaveTime?: number;
53
- }
package/lib/utils.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import { Config } from './config';
2
- export declare class Utils {
3
- private config;
4
- constructor(config: Config);
5
- isPlatformBlocked(platform: string): boolean;
6
- extractTextContent(elements: any[]): string;
7
- private isBase64;
8
- cleanBase64Content(obj: any): any;
9
- }