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.
- package/client/web/dist/assets/Chat-B5Jdrz_2.js +28 -0
- package/client/web/dist/assets/{Chat-C-rmzMIw.css → Chat-DTEsebnY.css} +1 -1
- package/client/web/dist/assets/{MsgBody-h4C1nnBQ.js → MsgBody-tPnKSZOs.js} +1 -1
- 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
- package/client/web/dist/assets/{append_darwin-CqBNU62J.css → append_darwin-Cql-dV6d.css} +1 -1
- package/client/web/dist/assets/{append_full_vibrancy-j0D2LM9m.css → append_full_vibrancy-ih3loy1O.css} +1 -1
- package/client/web/dist/assets/{append_linux-uhxeBqeC.css → append_linux-B3LvR8KB.css} +1 -1
- package/client/web/dist/assets/{append_new-407Lo5_V.css → append_new-DfhN_NX9.css} +1 -1
- package/client/web/dist/assets/{append_vibrancy-6FHctkOY.css → append_vibrancy-D3pVsmAa.css} +1 -1
- package/client/web/dist/assets/{append_win32-srmD-78y.css → append_win32-Dh9JlmlE.css} +1 -1
- package/client/web/dist/assets/index-B71pPwae.css +1 -0
- package/client/web/dist/assets/{index-CdTmWcO4.js → index-CSGfOsfr.js} +97 -76
- package/client/web/dist/index.html +2 -2
- package/client/web/src/App.vue +2 -2
- package/client/web/src/assets/css/append/append_darwin.css +2 -2
- package/client/web/src/assets/css/append/append_full_vibrancy.css +2 -2
- package/client/web/src/assets/css/append/append_linux.css +2 -2
- package/client/web/src/assets/css/append/append_new.css +2 -2
- package/client/web/src/assets/css/append/append_vibrancy.css +1 -1
- package/client/web/src/assets/css/append/append_win32.css +2 -2
- package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +1 -1
- package/client/web/src/assets/css/chat.css +4 -3
- package/client/web/src/assets/css/msg.css +7 -3
- package/client/web/src/assets/css/options.css +2 -2
- package/client/web/src/assets/css/view.css +14 -3
- package/client/web/src/assets/l10n/zh-CN.po +21 -0
- package/client/web/src/components/AboutPan.vue +5 -3
- package/client/web/src/components/DepPan.vue +1 -1
- package/client/web/src/components/MsgBody.vue +0 -3
- package/client/web/src/components/ThemeColorPickerPan.vue +1 -1
- package/client/web/src/components/UmamiInfoPan.vue +1 -1
- package/client/web/src/components/WelPan.vue +1 -1
- package/client/web/src/function/connect.ts +232 -72
- package/client/web/src/function/elements/information.ts +1 -0
- package/client/web/src/function/msg.ts +43 -24
- package/client/web/src/function/satori-model.ts +47 -15
- package/client/web/src/function/satori.ts +2 -1
- package/client/web/src/function/utils/appUtil.ts +3 -11
- package/client/web/src/function/utils/localHistoryUtil.ts +36 -12
- package/client/web/src/function/utils/msgUtil.ts +32 -21
- package/client/web/src/function/utils/sessionUtil.ts +20 -18
- package/client/web/src/pages/Chat.vue +47 -43
- package/client/web/src/pages/Friends.vue +5 -7
- package/client/web/src/pages/Info.vue +2 -2
- package/client/web/src/pages/Messages.vue +37 -23
- package/client/web/src/pages/chat-view/ChatTerminal.vue +4 -1
- package/client/web/src/pages/options/OptDev.vue +45 -2
- package/lib/database.d.ts +58 -0
- package/lib/index.js +220 -68
- package/lib/media.d.ts +24 -0
- package/lib/recorder.d.ts +21 -0
- package/lib/self-message.d.ts +27 -0
- package/lib/types.d.ts +6 -0
- package/lib/web.d.ts +7 -0
- package/package.json +1 -1
- package/src/cache.ts +1 -5
- package/src/database.ts +52 -8
- package/src/index.ts +4 -4
- package/src/media.ts +97 -0
- package/src/recorder.ts +28 -19
- package/src/self-message.ts +68 -19
- package/src/types.ts +6 -0
- package/src/web.ts +49 -39
- package/client/web/dist/assets/Chat-Bo5JdcNg.js +0 -28
- 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
|
-
?
|
|
760
|
-
:
|
|
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
|
-
|
|
1209
|
+
channelId,
|
|
1226
1210
|
firstMsgTime,
|
|
1227
1211
|
20,
|
|
1228
1212
|
)
|
|
1229
1213
|
} else {
|
|
1230
1214
|
localMsgs = await dbGetBefore(
|
|
1231
1215
|
authStore.loginInfo.uin,
|
|
1232
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
-
|
|
2157
|
-
|
|
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
|
-
|
|
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.
|
|
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('
|
|
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 {
|
|
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:
|
|
666
|
+
@media (max-width: 800px) {
|
|
669
667
|
.exp-header:not(.open) {
|
|
670
668
|
display: none;
|
|
671
669
|
}
|
|
672
670
|
}
|
|
673
|
-
@media (max-width:
|
|
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
|
-
||
|
|
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
|
-
||
|
|
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('
|
|
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
|
-
!
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
+
}
|