koishi-plugin-chat-patch 5.3.1 → 5.5.1

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.
Files changed (65) hide show
  1. package/client/web/dist/assets/Chat-B5Jdrz_2.js +28 -0
  2. package/client/web/dist/assets/{Chat-C-rmzMIw.css → Chat-DTEsebnY.css} +1 -1
  3. package/client/web/dist/assets/{MsgBody-h4C1nnBQ.js → MsgBody-tPnKSZOs.js} +1 -1
  4. package/client/web/dist/assets/{MsgBody.vue_vue_type_script_setup_true_lang-a902ps2r.js → MsgBody.vue_vue_type_script_setup_true_lang-ClDybRo_.js} +1 -1
  5. package/client/web/dist/assets/{append_darwin-CqBNU62J.css → append_darwin-Cql-dV6d.css} +1 -1
  6. package/client/web/dist/assets/{append_full_vibrancy-j0D2LM9m.css → append_full_vibrancy-ih3loy1O.css} +1 -1
  7. package/client/web/dist/assets/{append_linux-uhxeBqeC.css → append_linux-B3LvR8KB.css} +1 -1
  8. package/client/web/dist/assets/{append_new-407Lo5_V.css → append_new-DfhN_NX9.css} +1 -1
  9. package/client/web/dist/assets/{append_vibrancy-6FHctkOY.css → append_vibrancy-D3pVsmAa.css} +1 -1
  10. package/client/web/dist/assets/{append_win32-srmD-78y.css → append_win32-Dh9JlmlE.css} +1 -1
  11. package/client/web/dist/assets/index-B71pPwae.css +1 -0
  12. package/client/web/dist/assets/{index-CdTmWcO4.js → index-CSGfOsfr.js} +97 -76
  13. package/client/web/dist/index.html +2 -2
  14. package/client/web/src/App.vue +2 -2
  15. package/client/web/src/assets/css/append/append_darwin.css +2 -2
  16. package/client/web/src/assets/css/append/append_full_vibrancy.css +2 -2
  17. package/client/web/src/assets/css/append/append_linux.css +2 -2
  18. package/client/web/src/assets/css/append/append_new.css +2 -2
  19. package/client/web/src/assets/css/append/append_vibrancy.css +1 -1
  20. package/client/web/src/assets/css/append/append_win32.css +2 -2
  21. package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +1 -1
  22. package/client/web/src/assets/css/chat.css +4 -3
  23. package/client/web/src/assets/css/msg.css +7 -3
  24. package/client/web/src/assets/css/options.css +2 -2
  25. package/client/web/src/assets/css/view.css +14 -3
  26. package/client/web/src/assets/l10n/zh-CN.po +21 -0
  27. package/client/web/src/components/AboutPan.vue +5 -3
  28. package/client/web/src/components/DepPan.vue +1 -1
  29. package/client/web/src/components/MsgBody.vue +0 -3
  30. package/client/web/src/components/ThemeColorPickerPan.vue +1 -1
  31. package/client/web/src/components/UmamiInfoPan.vue +1 -1
  32. package/client/web/src/components/WelPan.vue +1 -1
  33. package/client/web/src/function/connect.ts +232 -72
  34. package/client/web/src/function/elements/information.ts +1 -0
  35. package/client/web/src/function/msg.ts +43 -24
  36. package/client/web/src/function/satori-model.ts +47 -15
  37. package/client/web/src/function/satori.ts +2 -1
  38. package/client/web/src/function/utils/appUtil.ts +3 -11
  39. package/client/web/src/function/utils/localHistoryUtil.ts +36 -12
  40. package/client/web/src/function/utils/msgUtil.ts +32 -21
  41. package/client/web/src/function/utils/sessionUtil.ts +20 -18
  42. package/client/web/src/pages/Chat.vue +47 -43
  43. package/client/web/src/pages/Friends.vue +5 -7
  44. package/client/web/src/pages/Info.vue +2 -2
  45. package/client/web/src/pages/Messages.vue +37 -23
  46. package/client/web/src/pages/chat-view/ChatTerminal.vue +4 -1
  47. package/client/web/src/pages/options/OptDev.vue +45 -2
  48. package/lib/database.d.ts +58 -0
  49. package/lib/index.js +220 -68
  50. package/lib/media.d.ts +24 -0
  51. package/lib/recorder.d.ts +21 -0
  52. package/lib/self-message.d.ts +27 -0
  53. package/lib/types.d.ts +6 -0
  54. package/lib/web.d.ts +7 -0
  55. package/package.json +1 -1
  56. package/src/cache.ts +1 -5
  57. package/src/database.ts +52 -8
  58. package/src/index.ts +4 -4
  59. package/src/media.ts +97 -0
  60. package/src/recorder.ts +28 -19
  61. package/src/self-message.ts +68 -19
  62. package/src/types.ts +6 -0
  63. package/src/web.ts +49 -39
  64. package/client/web/dist/assets/Chat-Bo5JdcNg.js +0 -28
  65. package/client/web/dist/assets/index-wjp_A4n1.css +0 -1
@@ -738,12 +738,6 @@ const searchRequestId = ref(0)
738
738
  const forwardList = ref(contactStore.userList)
739
739
  const chatImg = ref<any>(undefined)
740
740
  const trueLang = getTrueLang()
741
- let selfRefreshTimer: number | null = null
742
-
743
- function ensureChannelPrefix(channelId: string, prefix: string): string {
744
- if (/^(?:group|room|chat|channel|guild|private):/i.test(channelId)) return channelId
745
- return `${prefix}:${channelId}`
746
- }
747
741
 
748
742
  function messageLocalTimeMs(item: any): number {
749
743
  const local = Number(item?.local_time ?? item?.timestamp_ms ?? item?.time_ms ?? 0)
@@ -756,8 +750,8 @@ async function refreshSelfHistory() {
756
750
  const id = chat.show.id
757
751
  if (!id || id === 0 || details.value[3].open || tags.value.showForwardPan) return
758
752
  const channelId = chat.show.type === 'group'
759
- ? ensureChannelPrefix(String(chat.show.channel_id ?? id), 'group')
760
- : ensureChannelPrefix(String(chat.show.channel_id ?? id), 'private')
753
+ ? String(chat.show.channel_id ?? id)
754
+ : String(chat.show.channel_id ?? id)
761
755
  let cached: Record<string, unknown>[] = []
762
756
  try {
763
757
  cached = await loadChatHistoryFromCache({
@@ -798,22 +792,8 @@ async function refreshSelfHistory() {
798
792
  }
799
793
 
800
794
  function startSelfRefresh() {
801
- if (selfRefreshTimer !== null) {
802
- window.clearInterval(selfRefreshTimer)
803
- selfRefreshTimer = null
804
- }
805
795
  if (!chat.show.id) return
806
796
  void refreshSelfHistory()
807
- selfRefreshTimer = window.setInterval(() => {
808
- void refreshSelfHistory()
809
- }, 2500)
810
- }
811
-
812
- function stopSelfRefresh() {
813
- if (selfRefreshTimer !== null) {
814
- window.clearInterval(selfRefreshTimer)
815
- selfRefreshTimer = null
816
- }
817
797
  }
818
798
 
819
799
  //#region == 窗口移动相关 ==================================================
@@ -973,7 +953,6 @@ onMounted(() => {
973
953
  })
974
954
 
975
955
  onBeforeUnmount(() => {
976
- stopSelfRefresh()
977
956
  if (resizeMainInputFrame !== null) {
978
957
  cancelAnimationFrame(resizeMainInputFrame)
979
958
  resizeMainInputFrame = null
@@ -1217,19 +1196,24 @@ async function loadMoreHistory() {
1217
1196
  }
1218
1197
  uiStore.loadHistoryFail = false
1219
1198
 
1199
+ const channelId = String(
1200
+ chatStore.chatInfo.show.channel_id
1201
+ ?? chatStore.chatInfo.show.id
1202
+ ?? '',
1203
+ )
1220
1204
  if (useMixedHistory) {
1221
1205
  let localMsgs = [] as any[]
1222
1206
  if (Number.isFinite(firstMsgTime)) {
1223
1207
  localMsgs = await dbGetBeforeByTime(
1224
1208
  authStore.loginInfo.uin,
1225
- chatStore.chatInfo.show.id,
1209
+ channelId,
1226
1210
  firstMsgTime,
1227
1211
  20,
1228
1212
  )
1229
1213
  } else {
1230
1214
  localMsgs = await dbGetBefore(
1231
1215
  authStore.loginInfo.uin,
1232
- chatStore.chatInfo.show.id,
1216
+ channelId,
1233
1217
  firstMsgId,
1234
1218
  20,
1235
1219
  )
@@ -1251,12 +1235,6 @@ async function loadMoreHistory() {
1251
1235
  }
1252
1236
  }
1253
1237
 
1254
- const type = chatStore.chatInfo.show.type
1255
- const id = chatStore.chatInfo.show.id
1256
- const rawChannelId = String(chatStore.chatInfo.show.channel_id ?? '')
1257
- const channelId = type === 'group'
1258
- ? ensureChannelPrefix(rawChannelId || String(id), 'group')
1259
- : ensureChannelPrefix(rawChannelId || String(id), 'private')
1260
1238
  const cached = await loadChatHistoryFromCache({
1261
1239
  platform: String(authStore.loginInfo.platform ?? ''),
1262
1240
  selfId: String(authStore.loginInfo.uin ?? ''),
@@ -2030,6 +2008,7 @@ function forwardMsg(data: UserFriendElem & UserGroupElem) {
2030
2008
  targetType as 'group' | 'user',
2031
2009
  targetId,
2032
2010
  msgBody,
2011
+ targetChannelId || undefined,
2033
2012
  )
2034
2013
  if (!result.ok) {
2035
2014
  new PopInfo().add(PopType.ERR, $t('合并转发发送失败'))
@@ -2072,11 +2051,7 @@ function forwardMsg(data: UserFriendElem & UserGroupElem) {
2072
2051
  scrollToMsg('chat-' + sentMsg.message_id, true)
2073
2052
  })
2074
2053
  }
2075
- const sentChannelId = targetType === 'group'
2076
- ? (targetChannelId || targetId)
2077
- : /^(?:private|direct):/i.test(targetChannelId || '')
2078
- ? targetChannelId
2079
- : `private:${targetId}`
2054
+ const sentChannelId = result.channelId || targetChannelId || targetId
2080
2055
  if (result.native && !result.messageId) {
2081
2056
  // 原生路径已经由后端 before-send/发送拦截写入,缺少消息 id 时不再重复写入
2082
2057
  } else {
@@ -2096,7 +2071,8 @@ function forwardMsg(data: UserFriendElem & UserGroupElem) {
2096
2071
  kind: 'forward',
2097
2072
  })
2098
2073
  }
2099
- const targetSession = contactStore.baseOnMsgList.get(normalizeSessionId(targetId))
2074
+ const targetSessionKey = targetChannelId || targetId
2075
+ const targetSession = contactStore.baseOnMsgList.get(normalizeSessionId(targetSessionKey))
2100
2076
  if (targetSession) {
2101
2077
  const preview = `[${$t('聊天记录')}]`
2102
2078
  targetSession.raw_msg_base = preview
@@ -2104,7 +2080,7 @@ function forwardMsg(data: UserFriendElem & UserGroupElem) {
2104
2080
  ? `${String(authStore.loginInfo.nickname ?? '')}: ${preview}`
2105
2081
  : preview
2106
2082
  targetSession.time = Math.floor(sentTime / 1000)
2107
- contactStore.baseOnMsgList.set(normalizeSessionId(targetId), targetSession)
2083
+ contactStore.baseOnMsgList.set(normalizeSessionId(targetSessionKey), targetSession)
2108
2084
  updateBaseOnMsgList()
2109
2085
  }
2110
2086
  }
@@ -2153,8 +2129,9 @@ function forwardMsg(data: UserFriendElem & UserGroupElem) {
2153
2129
 
2154
2130
  function finishForward(data: UserFriendElem & UserGroupElem, id: string | number) {
2155
2131
  cancelForward()
2156
- if(contactStore.baseOnMsgList.get(normalizeSessionId(id)) == undefined) {
2157
- contactStore.baseOnMsgList.set(normalizeSessionId(id), data)
2132
+ const sessionKey = String(data.channel_id ?? data.channelId ?? id ?? '')
2133
+ if(contactStore.baseOnMsgList.get(normalizeSessionId(sessionKey)) == undefined) {
2134
+ contactStore.baseOnMsgList.set(normalizeSessionId(sessionKey), data)
2158
2135
  }
2159
2136
  nextTick(() => {
2160
2137
  const user = document.getElementById('user-' + id)
@@ -2267,7 +2244,15 @@ async function revokeMsg() {
2267
2244
  ?? chatStore.chatInfo.show.channel_id
2268
2245
  ?? chat.show.id,
2269
2246
  )
2270
- await Connector.callApi('delete_msg', { channel_id: channelId, message_id: msgId })
2247
+ try {
2248
+ await Connector.callApi('delete_msg', { channel_id: channelId, message_id: msgId })
2249
+ } catch {
2250
+ new PopInfo().add(PopType.ERR, $t('撤回失败'))
2251
+ return
2252
+ }
2253
+ msgData.revoke = true
2254
+ msgData.revoked = true
2255
+ msgData.revokeTime = Date.now() / 1000
2271
2256
  }
2272
2257
 
2273
2258
  async function reeditMsg() {
@@ -2629,13 +2614,31 @@ function sendVideo(file: File, fileName: string | null) {
2629
2614
  sendMedia(file, fileName, 'video')
2630
2615
  }
2631
2616
 
2617
+ async function isGifImage(file: File): Promise<boolean> {
2618
+ if (file.type === 'image/gif' || /\.gif$/i.test(file.name || '')) return true
2619
+ try {
2620
+ const buffer = await file.slice(0, 6).arrayBuffer()
2621
+ const bytes = new Uint8Array(buffer)
2622
+ return bytes.length >= 6
2623
+ && bytes[0] === 0x47
2624
+ && bytes[1] === 0x49
2625
+ && bytes[2] === 0x46
2626
+ && bytes[3] === 0x38
2627
+ && (bytes[4] === 0x37 || bytes[4] === 0x39)
2628
+ && bytes[5] === 0x61
2629
+ } catch {
2630
+ return false
2631
+ }
2632
+ }
2633
+
2632
2634
  async function setImg(file: File | null) {
2633
2635
  const popInfo = new PopInfo()
2634
2636
  if (!file) return
2635
2637
  if (!file.type.includes('image/')) return
2636
2638
  if (file.size === 0) return
2639
+ const isGif = await isGifImage(file)
2637
2640
 
2638
- if (file.size > 3145728) {
2641
+ if (file.size > 3145728 && !isGif) {
2639
2642
  const options = { maxSizeMB: 3, useWebWorker: true }
2640
2643
  try {
2641
2644
  popInfo.add(PopType.INFO, $t('正在压缩图片 ……'))
@@ -3170,7 +3173,8 @@ async function handleInput(event: Event) {
3170
3173
  searchDebounceTimer.value = setTimeout(async () => {
3171
3174
  const results = await dbSearchMessages(
3172
3175
  authStore.loginInfo.uin,
3173
- chatStore.chatInfo.show.id,
3176
+ chatStore.chatInfo.show.channel_id
3177
+ ?? chatStore.chatInfo.show.id,
3174
3178
  value,
3175
3179
  )
3176
3180
  if (requestId !== searchRequestId.value || !details.value[3].open) return
@@ -14,7 +14,7 @@
14
14
  <div id="friend-list" :class="'friend-list' + (uiStore.openSideBar ? ' open' : '')">
15
15
  <div>
16
16
  <div class="base">
17
- <span>{{ $t('列表') }}</span>
17
+ <span>{{ $t('联系人列表') }}</span>
18
18
  <div style="flex: 1" />
19
19
  <font-awesome-icon :icon="['fas', 'rotate-right']" @click="reloadUser" />
20
20
  </div>
@@ -184,7 +184,7 @@
184
184
  import { reloadUsers } from '../function/utils/appUtil'
185
185
  import { Connector, flushPendingBotEvents, loadContactsFromCache, login as loginInfo } from '../function/connect'
186
186
  import { botKey, getActiveBot, getLogins, setActiveBot } from '../function/satori'
187
- import { normalizeGroupId, normalizeSessionId } from '../function/utils/sessionUtil'
187
+ import { normalizeSessionId } from '../function/utils/sessionUtil'
188
188
  import { avatarError } from '../function/utils/avatarUtil'
189
189
  import { backend } from '../runtime/backend'
190
190
  import { matchPinyin } from '../function/utils/pinyin'
@@ -253,9 +253,7 @@
253
253
  || '',
254
254
  )
255
255
  const groupId = String(item.group_id || '')
256
- const id = groupId
257
- ? `group:${normalizeGroupId(rawId || groupId)}`
258
- : `user:${rawId.replace(/^(?:private|direct):/i, '')}`
256
+ const id = `${groupId ? 'group' : 'user'}|${String(rawId || groupId || item.user_id || '')}`
259
257
  const key = [bot?.platform ?? '', bot?.selfId ?? '', id]
260
258
  .map((value) => encodeURIComponent(String(value)))
261
259
  .join(':')
@@ -665,12 +663,12 @@
665
663
  font-size: 0.9rem;
666
664
  }
667
665
 
668
- @media (max-width: 700px) {
666
+ @media (max-width: 800px) {
669
667
  .exp-header:not(.open) {
670
668
  display: none;
671
669
  }
672
670
  }
673
- @media (max-width: 500px) {
671
+ @media (max-width: 800px) {
674
672
  .exp-header > span {
675
673
  display: block !important;
676
674
  }
@@ -246,7 +246,7 @@ function userChannelId(): string {
246
246
  || props.chat.show.channelId
247
247
  || props.chat.info.user_info.channel_id
248
248
  || props.chat.info.user_info.channelId
249
- || `private:${props.chat.show.id}`,
249
+ || String(props.chat.show.id),
250
250
  )
251
251
  }
252
252
 
@@ -256,7 +256,7 @@ function groupChannelId(): string {
256
256
  || props.chat.show.channelId
257
257
  || props.chat.info.group_info.channel_id
258
258
  || props.chat.info.group_info.channelId
259
- || `group:${props.chat.show.id}`,
259
+ || String(props.chat.show.id),
260
260
  )
261
261
  }
262
262
 
@@ -10,7 +10,7 @@
10
10
  -->
11
11
 
12
12
  <template>
13
- <div class="friend-view">
13
+ <div class="friend-view" :class="{ 'empty-list': messageListEmpty }">
14
14
  <div class="friend-list-container">
15
15
  <div id="message-list"
16
16
  :class="'friend-list' +
@@ -18,24 +18,13 @@
18
18
  (showGroupAssist ? ' show' : '')">
19
19
  <div>
20
20
  <div class="base only">
21
- <span>{{ $t('消息') }}</span>
21
+ <span>{{ $t('消息列表') }}</span>
22
22
  <div style="flex: 1" />
23
23
  <font-awesome-icon
24
24
  :icon="['fas', 'clock-rotate-left']"
25
25
  @click="openHistory" />
26
26
  <font-awesome-icon :icon="['fas', 'trash-can']" @click="cleanList" />
27
27
  </div>
28
- <div class="small">
29
- <span>{{ $t('消息') }}</span>
30
- <div v-if="showGroupAssist"
31
- style="margin-right: -5px;margin-left: 5px;"
32
- @click="showGroupAssist = !showGroupAssist">
33
- <font-awesome-icon :icon="['fas', 'angle-left']" />
34
- </div>
35
- <div @click="openLeftBar">
36
- <font-awesome-icon :icon="['fas', 'bars-staggered']" />
37
- </div>
38
- </div>
39
28
  </div>
40
29
  <div id="message-list-body" class="robot-accordion-list">
41
30
  <div v-for="bot in satoriLogins" :key="'bot-' + botKey(bot.platform, bot.selfId)"
@@ -50,7 +39,7 @@
50
39
  </div>
51
40
  <div v-if="botKey(bot.platform, bot.selfId) === activeBotId" class="robot-accordion-content">
52
41
  <div v-if="!showGroupAssist &&
53
- !contactStore.systemNoticesList &&
42
+ !hasSystemNotices &&
54
43
  (!contactStore.groupAssistList || contactStore.groupAssistList.length === 0) &&
55
44
  contactStore.onMsgList.length === 0"
56
45
  class="empty-state">
@@ -63,8 +52,7 @@
63
52
  style="overflow-x: hidden">
64
53
  <!-- 系统信息 -->
65
54
  <FriendBody v-if="!showGroupAssist &&
66
- contactStore.systemNoticesList &&
67
- Object.keys(contactStore.systemNoticesList).length > 0"
55
+ hasSystemNotices"
68
56
  key="inMessage--10000"
69
57
  :select="chat.show.id === -10000"
70
58
  :menu="menu.select && menu.select.user_id === -10000"
@@ -127,15 +115,15 @@
127
115
  <a v-if="contactStore.newMsgCount > 0">{{ contactStore.newMsgCount }}</a>
128
116
  </div>
129
117
  <div class="small">
130
- <span style="cursor: pointer;">
131
- {{ $t('群收纳盒') }}
132
- <a v-if="contactStore.newMsgCount > 0">{{ contactStore.newMsgCount }}</a>
133
- </span>
134
118
  <div v-if="showGroupAssist"
135
119
  style="margin-right: -5px;margin-left: 5px;"
136
120
  @click="showGroupAssist = !showGroupAssist">
137
121
  <font-awesome-icon :icon="['fas', 'angle-left']" />
138
122
  </div>
123
+ <span style="cursor: pointer;">
124
+ {{ $t('群收纳盒') }}
125
+ <a v-if="contactStore.newMsgCount > 0">{{ contactStore.newMsgCount }}</a>
126
+ </span>
139
127
  <div @click="openLeftBar">
140
128
  <font-awesome-icon :icon="['fas', 'bars-staggered']" />
141
129
  </div>
@@ -380,6 +368,17 @@
380
368
  const menu = Menu.append
381
369
  const showMenu = ref(false)
382
370
  const showGroupAssist = ref(false)
371
+ const hasSystemNotices = computed(() => {
372
+ const value = contactStore.systemNoticesList
373
+ if (Array.isArray(value)) return value.length > 0
374
+ return Boolean(value && Object.keys(value).length > 0)
375
+ })
376
+ const messageListEmpty = computed(() => {
377
+ return !showGroupAssist.value &&
378
+ !hasSystemNotices.value &&
379
+ (!contactStore.groupAssistList || contactStore.groupAssistList.length === 0) &&
380
+ contactStore.onMsgList.length === 0
381
+ })
383
382
 
384
383
  onMounted(() => {
385
384
  library.add(faCheckToSlot, faThumbTack, faTrashCan, faGripLines, faBroom)
@@ -395,8 +394,11 @@
395
394
  function userClick(data: UserFriendElem & UserGroupElem) {
396
395
  const id = data.group_id || data.user_id
397
396
  if (id === undefined || id === null || String(id) === '' || String(id) === '0') return
397
+ const fromGroupAssist = showGroupAssist.value
398
398
  if (!trRead.value && id != props.chat.show.id) {
399
- if (uiStore.openSideBar) {
399
+ if (fromGroupAssist) {
400
+ uiStore.openSideBar = false
401
+ } else if (uiStore.openSideBar) {
400
402
  openLeftBar()
401
403
  }
402
404
  const back = {
@@ -895,16 +897,28 @@
895
897
  background: transparent !important;
896
898
  }
897
899
 
898
- @media (max-width: 700px) {
900
+ @media (max-width: 800px) {
899
901
  .friend-list-container {
900
902
  overflow: unset;
901
903
  }
904
+ .friend-view.empty-list .friend-list-container {
905
+ flex: 1;
906
+ min-width: 100%;
907
+ width: 100%;
908
+ }
909
+ .friend-view.empty-list #message-list {
910
+ flex: 1;
911
+ width: 100% !important;
912
+ }
913
+ .friend-view.empty-list .friend-list-space {
914
+ display: none !important;
915
+ }
902
916
  .menu {
903
917
  width: 140px !important;
904
918
  }
905
919
  }
906
920
 
907
- @media (max-width: 500px) {
921
+ @media (max-width: 800px) {
908
922
  .friend-list-container {
909
923
  overflow: hidden;
910
924
  }
@@ -966,7 +966,10 @@ import packageInfo from '../../../package.json'
966
966
  border-radius: 7px;
967
967
  }
968
968
  .shell-msg.revoke {
969
- display: none;
969
+ display: flex;
970
+ opacity: 1;
971
+ border: 2px solid var(--color-red);
972
+ background: rgba(255, 80, 80, 0.08);
970
973
  }
971
974
  .shell-msg.reply {
972
975
  background: var(--color-card-1);
@@ -52,12 +52,25 @@
52
52
  <span>{{ $t('将所有 WebUI 配置恢复为默认值') }}</span>
53
53
  </div>
54
54
  <button
55
- style="width: 100px; font-size: 0.8rem"
56
55
  class="ss-button"
56
+ style="width: 100px; font-size: 0.8rem; background: var(--color-red); border-color: var(--color-red); color: #fff"
57
57
  @click="resetDefaults">
58
58
  {{ $t('恢复') }}
59
59
  </button>
60
60
  </div>
61
+ <div class="opt-item">
62
+ <font-awesome-icon :icon="['fas', 'trash-can']" />
63
+ <div>
64
+ <span>{{ $t('删除数据库全部缓存') }}</span>
65
+ <span>{{ $t('清空媒体缓存、内容缓存和数据库历史记录') }}</span>
66
+ </div>
67
+ <button
68
+ style="width: 100px; font-size: 0.8rem; background: var(--color-red); border-color: var(--color-red); color: #fff"
69
+ class="ss-button"
70
+ @click="deleteAllCache">
71
+ {{ $t('删除') }}
72
+ </button>
73
+ </div>
61
74
  </div>
62
75
  </div>
63
76
  </template>
@@ -77,7 +90,7 @@ import packageInfo from '../../../package.json'
77
90
  get,
78
91
  getRaw,
79
92
  } from '../../function/option'
80
- import { Connector } from '../../function/connect'
93
+ import { clearAllCache, Connector } from '../../function/connect'
81
94
  import { PopInfo, PopType } from '../../function/base'
82
95
  import { isDebugMode } from '../../function/debug'
83
96
  import { dispatch } from '../../function/msg'
@@ -151,6 +164,36 @@ import packageInfo from '../../../package.json'
151
164
  uiStore.popBoxList.push(popInfo)
152
165
  }
153
166
 
167
+ function deleteAllCache() {
168
+ const popInfo = {
169
+ title: $t('删除数据库全部缓存'),
170
+ html: `<span>${$t('确认要删除全部缓存吗?删除后媒体图片、消息内容和数据库历史记录都会被清空。')}</span>`,
171
+ button: [
172
+ {
173
+ text: $t('确认'),
174
+ fun: async () => {
175
+ uiStore.popBoxList.shift()
176
+ const ok = await clearAllCache()
177
+ if (ok) {
178
+ new PopInfo().add(PopType.INFO, $t('缓存已全部删除'))
179
+ location.reload()
180
+ } else {
181
+ new PopInfo().add(PopType.ERR, $t('删除缓存失败'))
182
+ }
183
+ },
184
+ },
185
+ {
186
+ text: $t('取消'),
187
+ master: true,
188
+ fun: () => {
189
+ uiStore.popBoxList.shift()
190
+ },
191
+ },
192
+ ],
193
+ }
194
+ uiStore.popBoxList.push(popInfo)
195
+ }
196
+
154
197
  function sendTestWs(event: KeyboardEvent) {
155
198
  // 发送测试 WS 消息
156
199
  if (event.keyCode === 13 && ws_text.value !== '') {
@@ -0,0 +1,58 @@
1
+ import { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ import { ContactCacheItem, MessageRecord, PinnedState, SelfMessageRecord } from './types';
4
+ import { PluginLogger } from './logger';
5
+ export declare class ChatDatabase {
6
+ private ctx;
7
+ private config;
8
+ private logger;
9
+ private db;
10
+ private opened;
11
+ constructor(ctx: Context, config: Config, logger: PluginLogger);
12
+ initialize(): Promise<void>;
13
+ dispose(): Promise<void>;
14
+ clearAll(): Promise<void>;
15
+ appendMessage(record: MessageRecord): Promise<void>;
16
+ upsertSelfMessage(record: SelfMessageRecord): Promise<void>;
17
+ listSelfMessages(platform: string, selfId: string, channelId: string, limit?: number): Promise<SelfMessageRecord[]>;
18
+ listSelfMessagesBefore(platform: string, selfId: string, channelId: string, beforeTime: number, limit?: number): Promise<SelfMessageRecord[]>;
19
+ updateSelfMessageByMessageId(platform: string, selfId: string, _channelId: string, messageId: string, patch: Partial<SelfMessageRecord>): Promise<boolean>;
20
+ updateMessageRevoked(platform: string, selfId: string, channelId: string, messageId: string, patch: {
21
+ revoked: boolean;
22
+ revokedAt: number;
23
+ }): Promise<boolean>;
24
+ findSelfForwardContent(platform: string, selfId: string, channelId: string, id: string): Promise<unknown[] | null>;
25
+ private removeSelfMessageByMessageId;
26
+ private parseSelfMessage;
27
+ listMessages(platform: string, selfId: string, channelId: string, limit?: number): Promise<MessageRecord[]>;
28
+ listMessagesBefore(platform: string, selfId: string, channelId: string, beforeTime: number, limit?: number): Promise<MessageRecord[]>;
29
+ clearChannel(platform: string, selfId: string, channelId: string): Promise<void>;
30
+ getPinned(): Promise<PinnedState>;
31
+ setPinned(state: PinnedState): Promise<void>;
32
+ getMeta(key: string): Promise<unknown>;
33
+ setMeta(key: string, value: unknown): Promise<void>;
34
+ recordMedia(url: string, filePath: string, channelId?: string): Promise<void>;
35
+ getMediaPath(url: string): Promise<string | undefined>;
36
+ getAllMedia(): Promise<Array<{
37
+ filePath: string;
38
+ channelId: string;
39
+ }>>;
40
+ removeMediaByPath(filePath: string): Promise<void>;
41
+ getContacts(platform: string, selfId: string, type: string): Promise<ContactCacheItem[]>;
42
+ getContact(platform: string, selfId: string, type: string, id: string): Promise<ContactCacheItem | null>;
43
+ setContacts(platform: string, selfId: string, type: string, contacts: ContactCacheItem[]): Promise<void>;
44
+ appendContact(platform: string, selfId: string, type: string, contact: ContactCacheItem): Promise<void>;
45
+ getContactsLegacy(platform: string, selfId: string, type: string): Promise<ContactCacheItem[]>;
46
+ getGroupMembers(platform: string, selfId: string, groupId: string): Promise<ContactCacheItem[]>;
47
+ setGroupMembers(platform: string, selfId: string, groupId: string, members: ContactCacheItem[]): Promise<void>;
48
+ getGroupMember(platform: string, selfId: string, groupId: string, userId: string): Promise<ContactCacheItem | null>;
49
+ appendGroupMember(platform: string, selfId: string, groupId: string, member: ContactCacheItem): Promise<void>;
50
+ getAllContacts(): Promise<Array<{
51
+ platform: string;
52
+ selfId: string;
53
+ type: string;
54
+ contacts: ContactCacheItem[];
55
+ }>>;
56
+ private trimMessages;
57
+ private trimSelfMessages;
58
+ }