koishi-plugin-chat-patch 5.3.1 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/client/web/dist/assets/Chat-Clqxn7CB.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-C0TKsXhC.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-CCdBwlN_.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-BA37EQGa.js} +96 -75
  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 +42 -23
  36. package/client/web/src/function/satori-model.ts +27 -13
  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 -22
  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
@@ -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,6 +394,10 @@
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
+ // 从群收纳盒进入群时先收起收纳盒,避免头部切换导致返回标记闪烁
398
+ if (showGroupAssist.value) {
399
+ showGroupAssist.value = false
400
+ }
398
401
  if (!trRead.value && id != props.chat.show.id) {
399
402
  if (uiStore.openSideBar) {
400
403
  openLeftBar()
@@ -895,16 +898,28 @@
895
898
  background: transparent !important;
896
899
  }
897
900
 
898
- @media (max-width: 700px) {
901
+ @media (max-width: 800px) {
899
902
  .friend-list-container {
900
903
  overflow: unset;
901
904
  }
905
+ .friend-view.empty-list .friend-list-container {
906
+ flex: 1;
907
+ min-width: 100%;
908
+ width: 100%;
909
+ }
910
+ .friend-view.empty-list #message-list {
911
+ flex: 1;
912
+ width: 100% !important;
913
+ }
914
+ .friend-view.empty-list .friend-list-space {
915
+ display: none !important;
916
+ }
902
917
  .menu {
903
918
  width: 140px !important;
904
919
  }
905
920
  }
906
921
 
907
- @media (max-width: 500px) {
922
+ @media (max-width: 800px) {
908
923
  .friend-list-container {
909
924
  overflow: hidden;
910
925
  }
@@ -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
+ }