koishi-plugin-chat-patch 5.0.3 → 5.3.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.
- package/client/web/dist/assets/Chat-B448YOeN.js +28 -0
- package/client/web/dist/assets/{MsgBody-LNGNGtE3.js → MsgBody-DDacjWJ9.js} +1 -1
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-B1dWyCB0.js +67 -0
- package/client/web/dist/assets/{index-CwyyQN13.js → index-BlLut5xn.js} +121 -129
- package/client/web/dist/assets/index-fW_zcub3.css +1 -0
- package/client/web/dist/assets/pinyin-Dsq98249.js +157657 -0
- package/client/web/dist/index.html +2 -2
- package/client/web/dist/notice_local.json +1 -0
- package/client/web/package-lock.json +49 -0
- package/client/web/package.json +1 -0
- package/client/web/public/notice_local.json +1 -0
- package/client/web/src/components/EmojiFace.vue +0 -6
- package/client/web/src/components/FacePan.vue +0 -12
- package/client/web/src/components/MsgBody.vue +3 -4
- package/client/web/src/components/SettingsTab.vue +133 -0
- package/client/web/src/function/connect.ts +42 -21
- package/client/web/src/function/model/emoji.ts +7 -67
- package/client/web/src/function/msg.ts +74 -23
- package/client/web/src/function/satori-model.ts +4 -3
- package/client/web/src/function/utils/appUtil.ts +1 -4
- package/client/web/src/function/utils/msgUtil.ts +121 -87
- package/client/web/src/function/utils/pinyin.ts +25 -65
- package/client/web/src/function/utils/sessionUtil.ts +107 -9
- package/client/web/src/pages/Friends.vue +49 -13
- package/client/web/src/pages/Messages.vue +45 -14
- package/client/web/src/pages/Options.vue +4 -4
- package/client/web/src/pages/options/OptDev.vue +1 -14
- package/package.json +1 -1
- package/src/web.ts +712 -712
- package/client/web/dist/assets/Chat-CXjwWCiV.js +0 -28
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-BK5okBfM.js +0 -67
- package/client/web/dist/assets/index-BgOX_tNa.css +0 -1
|
@@ -5,30 +5,25 @@ export type PinYinData = {
|
|
|
5
5
|
short: string[]
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const PINYIN_SCRIPT_SRC = 'https://lib.stapxs.cn/modules/pinyin.min.js'
|
|
8
|
+
type PinyinModule = typeof import('pinyin')
|
|
11
9
|
|
|
10
|
+
let pinyinModule: PinyinModule | null = null
|
|
12
11
|
let pinyinLoadPromise: Promise<boolean> | null = null
|
|
13
12
|
|
|
14
13
|
function createEmptyPinyinData(): PinYinData {
|
|
15
14
|
return {
|
|
16
15
|
main: [],
|
|
17
|
-
short: []
|
|
16
|
+
short: [],
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
function hasPinyinLib() {
|
|
22
|
-
return typeof window !== 'undefined' && typeof window.pinyin !== 'undefined'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
function scheduleIdleTask(task: () => void) {
|
|
26
21
|
if (typeof window === 'undefined') return
|
|
27
22
|
|
|
28
23
|
const idleWindow = window as Window & {
|
|
29
24
|
requestIdleCallback?: (
|
|
30
25
|
callback: IdleRequestCallback,
|
|
31
|
-
options?: IdleRequestOptions
|
|
26
|
+
options?: IdleRequestOptions,
|
|
32
27
|
) => number
|
|
33
28
|
}
|
|
34
29
|
|
|
@@ -41,57 +36,23 @@ function scheduleIdleTask(task: () => void) {
|
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
export function isPinyinReady() {
|
|
44
|
-
return
|
|
39
|
+
return pinyinModule !== null
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
export function ensurePinyinLoaded(): Promise<boolean> {
|
|
48
|
-
if (
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
pinyinLoadPromise = null
|
|
62
|
-
}
|
|
63
|
-
resolve(success)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const handleLoad = () => {
|
|
67
|
-
if (script) {
|
|
68
|
-
script.dataset.loaded = 'true'
|
|
69
|
-
}
|
|
70
|
-
finish(hasPinyinLib())
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleError = () => {
|
|
74
|
-
if (isDebugMode()) console.warn('拼音库加载失败')
|
|
75
|
-
script?.remove()
|
|
76
|
-
finish(false)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (script?.dataset.loaded === 'true') {
|
|
80
|
-
finish(hasPinyinLib())
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!script) {
|
|
85
|
-
script = document.createElement('script')
|
|
86
|
-
script.src = PINYIN_SCRIPT_SRC
|
|
87
|
-
script.async = true
|
|
88
|
-
script.dataset.ssqqPinyinLib = 'true'
|
|
89
|
-
document.body.appendChild(script)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
script.addEventListener('load', handleLoad, { once: true })
|
|
93
|
-
script.addEventListener('error', handleError, { once: true })
|
|
94
|
-
})
|
|
43
|
+
if (pinyinModule) return Promise.resolve(true)
|
|
44
|
+
if (pinyinLoadPromise) return pinyinLoadPromise
|
|
45
|
+
|
|
46
|
+
pinyinLoadPromise = import('pinyin')
|
|
47
|
+
.then((mod) => {
|
|
48
|
+
pinyinModule = mod
|
|
49
|
+
return true
|
|
50
|
+
})
|
|
51
|
+
.catch((error: unknown) => {
|
|
52
|
+
if (isDebugMode()) console.warn('本地拼音库加载失败:', error)
|
|
53
|
+
pinyinLoadPromise = null
|
|
54
|
+
return false
|
|
55
|
+
})
|
|
95
56
|
|
|
96
57
|
return pinyinLoadPromise
|
|
97
58
|
}
|
|
@@ -103,22 +64,21 @@ export function preloadPinyin() {
|
|
|
103
64
|
}
|
|
104
65
|
|
|
105
66
|
export function getPinyin(name: string): PinYinData {
|
|
106
|
-
if (!
|
|
67
|
+
if (!pinyinModule) return createEmptyPinyinData()
|
|
107
68
|
|
|
108
69
|
try {
|
|
109
|
-
const pinyinLib =
|
|
110
|
-
if (!pinyinLib) return createEmptyPinyinData()
|
|
70
|
+
const pinyinLib = pinyinModule.pinyin
|
|
111
71
|
return {
|
|
112
|
-
main: pinyinLib
|
|
72
|
+
main: pinyinLib(name, {
|
|
113
73
|
heteronym: true,
|
|
114
74
|
compact: true,
|
|
115
75
|
style: 'normal',
|
|
116
|
-
}).map((item
|
|
117
|
-
short: pinyinLib
|
|
76
|
+
}).map((item) => item.join('').toLowerCase()),
|
|
77
|
+
short: pinyinLib(name, {
|
|
118
78
|
heteronym: true,
|
|
119
79
|
compact: true,
|
|
120
80
|
style: 'first_letter',
|
|
121
|
-
}).map((item
|
|
81
|
+
}).map((item) => item.join('').toLowerCase()),
|
|
122
82
|
}
|
|
123
83
|
} catch (error) {
|
|
124
84
|
if (isDebugMode()) console.warn('拼音转换失败:', error)
|
|
@@ -128,7 +88,7 @@ export function getPinyin(name: string): PinYinData {
|
|
|
128
88
|
|
|
129
89
|
export function matchPinyin(
|
|
130
90
|
pinyinData: PinYinData,
|
|
131
|
-
matchStr: string
|
|
91
|
+
matchStr: string,
|
|
132
92
|
): boolean {
|
|
133
93
|
const str = matchStr.toLowerCase()
|
|
134
94
|
for (const py of pinyinData.main) {
|
|
@@ -1,19 +1,76 @@
|
|
|
1
1
|
import type { Session } from '../elements/information'
|
|
2
2
|
|
|
3
|
+
export function normalizeGroupId(value: string): string {
|
|
4
|
+
const raw = value.replace(/^(?:group|room|chat|channel|guild):/i, '').trim()
|
|
5
|
+
const wrapped = raw.match(/^\[_?([\s\S]+?)_?\]$/)
|
|
6
|
+
return wrapped ? wrapped[1] : raw || value
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
export function normalizeSessionId(value: number | string): string {
|
|
4
10
|
return String(value)
|
|
5
11
|
}
|
|
6
12
|
|
|
7
13
|
export function getSessionId(item: Session): number | string {
|
|
14
|
+
const channelId = item.channel_id ?? item.channelId
|
|
15
|
+
if (channelId !== undefined && channelId !== null && String(channelId) !== '') {
|
|
16
|
+
return channelId
|
|
17
|
+
}
|
|
8
18
|
return item.user_id ?? item.group_id ?? 0
|
|
9
19
|
}
|
|
10
20
|
|
|
21
|
+
function getLegacySessionId(item: Session): number | string | undefined {
|
|
22
|
+
return item.user_id ?? item.group_id
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getSessionAliases(item: Session): string[] {
|
|
26
|
+
const rawAliases: Array<number | string | undefined> = [
|
|
27
|
+
getSessionId(item),
|
|
28
|
+
getLegacySessionId(item),
|
|
29
|
+
]
|
|
30
|
+
if (item.group_id !== undefined && item.group_id !== null) {
|
|
31
|
+
rawAliases.push(normalizeGroupId(String(item.group_id)))
|
|
32
|
+
}
|
|
33
|
+
if (item.user_id !== undefined && item.user_id !== null) {
|
|
34
|
+
rawAliases.push(String(item.user_id).replace(/^(?:private|direct):/i, ''))
|
|
35
|
+
}
|
|
36
|
+
const aliases = rawAliases.filter((value): value is number | string => {
|
|
37
|
+
const text = String(value ?? '')
|
|
38
|
+
return text !== '' && text !== '0'
|
|
39
|
+
})
|
|
40
|
+
return [...new Set(aliases.map((value) => normalizeSessionId(value)))]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getSessionDedupKey(item: Session): string {
|
|
44
|
+
const channelId = String(item.channel_id ?? item.channelId ?? '')
|
|
45
|
+
const groupId = String(item.group_id ?? '')
|
|
46
|
+
const userId = String(item.user_id ?? '')
|
|
47
|
+
if (groupId) return `group:${normalizeGroupId(channelId || groupId)}`
|
|
48
|
+
if (userId) return `user:${userId.replace(/^(?:private|direct):/i, '')}`
|
|
49
|
+
return /^(?:private|direct):/i.test(channelId)
|
|
50
|
+
? `user:${channelId.replace(/^(?:private|direct):/i, '')}`
|
|
51
|
+
: `group:${normalizeGroupId(channelId)}`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function setSessionContact(
|
|
55
|
+
map: Map<number | string, Session>,
|
|
56
|
+
item: Session,
|
|
57
|
+
) {
|
|
58
|
+
for (const alias of getSessionAliases(item)) {
|
|
59
|
+
map.set(alias, item)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
11
63
|
export function findSessionContact(
|
|
12
64
|
contacts: Session[],
|
|
13
65
|
sessionId: number | string,
|
|
14
66
|
) {
|
|
67
|
+
const target = normalizeSessionId(sessionId)
|
|
15
68
|
return contacts.find((item) => {
|
|
16
|
-
return
|
|
69
|
+
return getSessionAliases(item).some((alias) => alias === target)
|
|
70
|
+
|| (
|
|
71
|
+
Boolean(item.group_id) &&
|
|
72
|
+
normalizeGroupId(String(item.group_id)) === normalizeGroupId(target)
|
|
73
|
+
)
|
|
17
74
|
})
|
|
18
75
|
}
|
|
19
76
|
|
|
@@ -76,6 +133,28 @@ function copyDefinedSessionState<K extends SessionStateKey>(
|
|
|
76
133
|
) {
|
|
77
134
|
const value = currentSession[key]
|
|
78
135
|
if (value !== undefined) {
|
|
136
|
+
const current = contact[key]
|
|
137
|
+
if (
|
|
138
|
+
key === 'time' &&
|
|
139
|
+
typeof current === 'number' &&
|
|
140
|
+
typeof value === 'number' &&
|
|
141
|
+
current > value
|
|
142
|
+
) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
contact[key] = value
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function copyMissingIdentity<K extends keyof Session>(
|
|
150
|
+
contact: Session,
|
|
151
|
+
currentSession: Session,
|
|
152
|
+
key: K,
|
|
153
|
+
) {
|
|
154
|
+
const value = currentSession[key]
|
|
155
|
+
if (value === undefined || value === null || String(value) === '') return
|
|
156
|
+
const current = contact[key]
|
|
157
|
+
if (current === undefined || current === null || String(current) === '') {
|
|
79
158
|
contact[key] = value
|
|
80
159
|
}
|
|
81
160
|
}
|
|
@@ -84,6 +163,21 @@ export function mergeSessionState(
|
|
|
84
163
|
contact: Session,
|
|
85
164
|
currentSession: Session,
|
|
86
165
|
) {
|
|
166
|
+
const identityKeys = [
|
|
167
|
+
'channel_id',
|
|
168
|
+
'channelId',
|
|
169
|
+
'guild_id',
|
|
170
|
+
'guildId',
|
|
171
|
+
'group_id',
|
|
172
|
+
'user_id',
|
|
173
|
+
'group_name',
|
|
174
|
+
'nickname',
|
|
175
|
+
'remark',
|
|
176
|
+
'avatar',
|
|
177
|
+
] as const
|
|
178
|
+
identityKeys.forEach((key) =>
|
|
179
|
+
copyMissingIdentity(contact, currentSession, key),
|
|
180
|
+
)
|
|
87
181
|
SESSION_STATE_KEYS.forEach((key) =>
|
|
88
182
|
copyDefinedSessionState(contact, currentSession, key),
|
|
89
183
|
)
|
|
@@ -100,14 +194,18 @@ export function mergeEarlySessionContacts(
|
|
|
100
194
|
) {
|
|
101
195
|
let didMerge = false
|
|
102
196
|
contacts.forEach((contact) => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
197
|
+
for (const [key, currentSession] of sessions.entries()) {
|
|
198
|
+
if (currentSession === contact) continue
|
|
199
|
+
if (
|
|
200
|
+
findSessionContact([currentSession], getSessionId(contact))
|
|
201
|
+
|| getSessionDedupKey(contact) === getSessionDedupKey(currentSession)
|
|
202
|
+
) {
|
|
203
|
+
sessions.set(
|
|
204
|
+
key,
|
|
205
|
+
mergeSessionState(contact, currentSession),
|
|
206
|
+
)
|
|
207
|
+
didMerge = true
|
|
208
|
+
}
|
|
111
209
|
}
|
|
112
210
|
})
|
|
113
211
|
return didMerge
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
{{ $t('空') }}
|
|
51
51
|
</div>
|
|
52
52
|
<FriendBody v-for="item in contactStore.showList"
|
|
53
|
-
:key="'search-' + item.
|
|
53
|
+
:key="'search-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
54
54
|
:data="item"
|
|
55
55
|
from="friend"
|
|
56
56
|
@click="userClick(item, $event)" />
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
return ( get.class_id == info.class_id )
|
|
101
101
|
},
|
|
102
102
|
)"
|
|
103
|
-
:key=" 'fb-' + (item.
|
|
103
|
+
:key=" 'fb-' + (item.channel_id || item.channelId || item.user_id || item.group_id) "
|
|
104
104
|
:data="item" from="friend"
|
|
105
105
|
@click="userClick(item, $event)" />
|
|
106
106
|
</div>
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
return get.class_id == undefined
|
|
126
126
|
},
|
|
127
127
|
)"
|
|
128
|
-
:key="'fb-' + (item.
|
|
128
|
+
:key="'fb-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
129
129
|
:data="item"
|
|
130
130
|
from="friend"
|
|
131
131
|
@click="userClick(item, $event)" />
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
</template>
|
|
135
135
|
<template v-else>
|
|
136
136
|
<FriendBody v-for="item in contactStore.userList"
|
|
137
|
-
:key="'fb-' + (item.
|
|
137
|
+
:key="'fb-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
138
138
|
:data="item"
|
|
139
139
|
from="friend"
|
|
140
140
|
@click="userClick(item, $event)" />
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
<div v-else class="list">
|
|
145
145
|
<div>
|
|
146
146
|
<FriendBody v-for="item in contactStore.showList"
|
|
147
|
-
:key="'fb-' + (item.
|
|
147
|
+
:key="'fb-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
148
148
|
:data="item" from="friend"
|
|
149
149
|
@click="userClick(item, $event)" />
|
|
150
150
|
</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 { getActiveBot, getLogins, setActiveBot } from '../function/satori'
|
|
187
|
-
import { normalizeSessionId } from '../function/utils/sessionUtil'
|
|
187
|
+
import { normalizeGroupId, 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'
|
|
@@ -240,7 +240,17 @@
|
|
|
240
240
|
bot?: ContactWithBot['_bot'],
|
|
241
241
|
) => {
|
|
242
242
|
for (const item of items) {
|
|
243
|
-
const
|
|
243
|
+
const rawId = String(
|
|
244
|
+
item.channel_id
|
|
245
|
+
|| item.channelId
|
|
246
|
+
|| item.user_id
|
|
247
|
+
|| item.group_id
|
|
248
|
+
|| '',
|
|
249
|
+
)
|
|
250
|
+
const groupId = String(item.group_id || '')
|
|
251
|
+
const id = groupId
|
|
252
|
+
? `group:${normalizeGroupId(rawId || groupId)}`
|
|
253
|
+
: `user:${rawId.replace(/^(?:private|direct):/i, '')}`
|
|
244
254
|
const key = [bot?.platform ?? '', bot?.selfId ?? '', id]
|
|
245
255
|
.map((value) => encodeURIComponent(String(value)))
|
|
246
256
|
.join(':')
|
|
@@ -295,8 +305,25 @@
|
|
|
295
305
|
if (saved) {
|
|
296
306
|
contactStore.userList = saved.userList
|
|
297
307
|
contactStore.baseOnMsgList.clear()
|
|
298
|
-
for (const [
|
|
299
|
-
|
|
308
|
+
for (const [, value] of saved.baseList) {
|
|
309
|
+
const id = String(value.channel_id || value.channelId || value.user_id || value.group_id || '')
|
|
310
|
+
if (id && id !== '0') {
|
|
311
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(id), value)
|
|
312
|
+
const legacyId = String(value.user_id || value.group_id || '')
|
|
313
|
+
if (legacyId && legacyId !== id) {
|
|
314
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), value)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const item of saved.onMsgList) {
|
|
319
|
+
const id = String(item.channel_id || item.channelId || item.user_id || item.group_id || '')
|
|
320
|
+
if (id && id !== '0') {
|
|
321
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(id), item)
|
|
322
|
+
const legacyId = String(item.user_id || item.group_id || '')
|
|
323
|
+
if (legacyId && legacyId !== id) {
|
|
324
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), item)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
300
327
|
}
|
|
301
328
|
contactStore.onMsgList = saved.onMsgList
|
|
302
329
|
flushPendingBotEvents(bot.platform, bot.selfId)
|
|
@@ -380,18 +407,27 @@
|
|
|
380
407
|
contactStore.showList = [] as any[]
|
|
381
408
|
|
|
382
409
|
const back = {
|
|
383
|
-
type: data.
|
|
384
|
-
id: data.
|
|
410
|
+
type: data.group_id ? 'group' : 'user',
|
|
411
|
+
id: data.group_id || data.user_id,
|
|
385
412
|
name: getShowName(data),
|
|
386
413
|
avatar: data.avatar || '/img/icons/icon.svg',
|
|
387
414
|
jump: sender.dataset.jump,
|
|
388
|
-
channel_id: data.channel_id,
|
|
415
|
+
channel_id: data.channel_id || data.channelId,
|
|
389
416
|
guild_id: data.guild_id,
|
|
390
417
|
} as BaseChatInfoElem
|
|
391
418
|
if (back.id === undefined || back.id === null || String(back.id) === '' || String(back.id) === '0') return
|
|
392
419
|
// 更新聊天框
|
|
393
420
|
emit('userClick', back)
|
|
394
|
-
|
|
421
|
+
const sessionId = String(
|
|
422
|
+
data.channel_id
|
|
423
|
+
|| data.channelId
|
|
424
|
+
|| data.user_id
|
|
425
|
+
|| data.group_id
|
|
426
|
+
|| '',
|
|
427
|
+
)
|
|
428
|
+
if (sessionId && sessionId !== '0') {
|
|
429
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(sessionId), data)
|
|
430
|
+
}
|
|
395
431
|
// 获取历史消息
|
|
396
432
|
if(!uiStore.nowGetHistory) {
|
|
397
433
|
emit('loadHistory', back)
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
<!-- 其他消息 -->
|
|
99
99
|
<FriendBody
|
|
100
100
|
v-for="item in contactStore.onMsgList"
|
|
101
|
-
:key="'inMessage-' + (item.
|
|
101
|
+
:key="'inMessage-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
102
102
|
:select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
|
|
103
103
|
:menu="menu.select && menu.select == item"
|
|
104
104
|
:data="item"
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
<!-- 其他消息 -->
|
|
151
151
|
<FriendBody
|
|
152
152
|
v-for="item in contactStore.groupAssistList"
|
|
153
|
-
:key="'inMessage-' + (item.
|
|
153
|
+
:key="'inMessage-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
154
154
|
:select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
|
|
155
155
|
:menu="menu.select && menu.select == item"
|
|
156
156
|
:data="item"
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
import { refreshFavicon } from '../function/favicon'
|
|
233
233
|
import { backend } from '../runtime/backend'
|
|
234
234
|
import History from '../components/History.vue'
|
|
235
|
-
import { normalizeSessionId } from '../function/utils/sessionUtil'
|
|
235
|
+
import { findSessionContact, normalizeSessionId } from '../function/utils/sessionUtil'
|
|
236
236
|
import { avatarError } from '../function/utils/avatarUtil'
|
|
237
237
|
import { useUIStore } from '../state/ui'
|
|
238
238
|
import { useAuthStore } from '../state/auth'
|
|
@@ -283,16 +283,27 @@
|
|
|
283
283
|
const restored = contactStore.botStates.get(bot.selfId)
|
|
284
284
|
if (!restored) return
|
|
285
285
|
contactStore.baseOnMsgList.clear()
|
|
286
|
-
for (const [
|
|
287
|
-
|
|
286
|
+
for (const [, value] of restored.baseList) {
|
|
287
|
+
const id = String(value.channel_id || value.channelId || value.user_id || value.group_id || '')
|
|
288
|
+
if (id && id !== '0') {
|
|
289
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(id), value)
|
|
290
|
+
const legacyId = String(value.user_id || value.group_id || '')
|
|
291
|
+
if (legacyId && legacyId !== id) {
|
|
292
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), value)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
288
295
|
}
|
|
289
296
|
for (const item of restored.onMsgList) {
|
|
290
|
-
const id = String(item.user_id
|
|
297
|
+
const id = String(item.channel_id || item.channelId || item.user_id || item.group_id || '')
|
|
291
298
|
if (!id || id === '0') continue
|
|
292
299
|
contactStore.baseOnMsgList.set(
|
|
293
300
|
normalizeSessionId(id),
|
|
294
301
|
item as UserFriendElem & UserGroupElem,
|
|
295
302
|
)
|
|
303
|
+
const legacyId = String(item.user_id || item.group_id || '')
|
|
304
|
+
if (legacyId && legacyId !== id) {
|
|
305
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), item as UserFriendElem & UserGroupElem)
|
|
306
|
+
}
|
|
296
307
|
}
|
|
297
308
|
contactStore.onMsgList = restored.onMsgList
|
|
298
309
|
}
|
|
@@ -376,7 +387,7 @@
|
|
|
376
387
|
* @param data 联系人对象
|
|
377
388
|
*/
|
|
378
389
|
function userClick(data: UserFriendElem & UserGroupElem) {
|
|
379
|
-
const id = data.
|
|
390
|
+
const id = data.group_id || data.user_id
|
|
380
391
|
if (id === undefined || id === null || String(id) === '' || String(id) === '0') return
|
|
381
392
|
if (!trRead.value && id != props.chat.show.id) {
|
|
382
393
|
if (uiStore.openSideBar) {
|
|
@@ -385,11 +396,11 @@
|
|
|
385
396
|
const back = {
|
|
386
397
|
// 临时会话标志
|
|
387
398
|
temp: data.group_name == '' ? data.group_id : undefined,
|
|
388
|
-
type: data.
|
|
399
|
+
type: data.group_id ? 'group' : 'user',
|
|
389
400
|
id: id,
|
|
390
401
|
name: getShowName(data.group_name || data.nickname, data.remark),
|
|
391
402
|
avatar: data.avatar || '/img/icons/icon.svg',
|
|
392
|
-
channel_id: data.channel_id
|
|
403
|
+
channel_id: data.channel_id || data.channelId,
|
|
393
404
|
guild_id: data.guild_id ?? data.guildId,
|
|
394
405
|
}
|
|
395
406
|
if (props.chat.id != back.id) {
|
|
@@ -401,14 +412,18 @@
|
|
|
401
412
|
}
|
|
402
413
|
}
|
|
403
414
|
// 清除新消息标记
|
|
404
|
-
const
|
|
415
|
+
const sessionKey = data.channel_id || data.channelId || id
|
|
416
|
+
const item = contactStore.baseOnMsgList.get(normalizeSessionId(sessionKey))
|
|
417
|
+
?? contactStore.baseOnMsgList.get(normalizeSessionId(id))
|
|
418
|
+
?? findSessionContact(Array.from(contactStore.baseOnMsgList.values()), id)
|
|
405
419
|
if(item) {
|
|
406
420
|
if(item.new_msg) {
|
|
407
421
|
item.new_msg = false
|
|
408
422
|
contactStore.newMsgCount--
|
|
409
423
|
}
|
|
410
424
|
item.highlight = undefined
|
|
411
|
-
contactStore.baseOnMsgList.set(normalizeSessionId(
|
|
425
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(sessionKey), item)
|
|
426
|
+
updateBaseOnMsgList()
|
|
412
427
|
// 关闭所有通知
|
|
413
428
|
new Notify().closeAll((item.group_id ?? item.user_id).toString())
|
|
414
429
|
}
|
|
@@ -472,14 +487,18 @@
|
|
|
472
487
|
*/
|
|
473
488
|
function readMsg(data: UserFriendElem & UserGroupElem) {
|
|
474
489
|
const id = data.group_id ? data.group_id : data.user_id
|
|
475
|
-
const
|
|
490
|
+
const sessionKey = data.channel_id || data.channelId || id
|
|
491
|
+
const item = contactStore.baseOnMsgList.get(normalizeSessionId(sessionKey))
|
|
492
|
+
?? contactStore.baseOnMsgList.get(normalizeSessionId(id))
|
|
493
|
+
?? findSessionContact(Array.from(contactStore.baseOnMsgList.values()), id)
|
|
476
494
|
if(item) {
|
|
477
495
|
if(item.new_msg) {
|
|
478
496
|
item.new_msg = false
|
|
479
497
|
contactStore.newMsgCount--
|
|
480
498
|
}
|
|
481
499
|
item.highlight = undefined
|
|
482
|
-
contactStore.baseOnMsgList.set(normalizeSessionId(
|
|
500
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(sessionKey), item)
|
|
501
|
+
updateBaseOnMsgList()
|
|
483
502
|
}
|
|
484
503
|
// pop
|
|
485
504
|
new PopInfo().add(
|
|
@@ -514,7 +533,16 @@
|
|
|
514
533
|
)
|
|
515
534
|
if (topList.indexOf(id) >= 0) {
|
|
516
535
|
item.always_top = true
|
|
517
|
-
|
|
536
|
+
const sessionId = String(
|
|
537
|
+
item.channel_id
|
|
538
|
+
?? item.channelId
|
|
539
|
+
?? item.user_id
|
|
540
|
+
?? item.group_id
|
|
541
|
+
?? '',
|
|
542
|
+
)
|
|
543
|
+
if (sessionId && sessionId !== '0') {
|
|
544
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(sessionId), item)
|
|
545
|
+
}
|
|
518
546
|
}
|
|
519
547
|
})
|
|
520
548
|
}
|
|
@@ -554,7 +582,10 @@
|
|
|
554
582
|
break
|
|
555
583
|
case 'remove': {
|
|
556
584
|
const id = item.user_id ? item.user_id : item.group_id
|
|
585
|
+
const sessionId = String(item.channel_id || item.channelId || id || '')
|
|
557
586
|
contactStore.baseOnMsgList.delete(normalizeSessionId(id))
|
|
587
|
+
contactStore.baseOnMsgList.delete(normalizeSessionId(sessionId))
|
|
588
|
+
updateBaseOnMsgList()
|
|
558
589
|
refreshFavicon()
|
|
559
590
|
break
|
|
560
591
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<!-- 保留占位元素,避免设置页右侧布局被原有左侧选择器样式影响 -->
|
|
12
12
|
<div class="opt-side-placeholder" style="display: none" />
|
|
13
13
|
<div>
|
|
14
|
-
<
|
|
14
|
+
<SettingsTab v-show="show" class="opt-tab">
|
|
15
15
|
<div :name="$t('账号')">
|
|
16
16
|
<OptAccount :config="config" />
|
|
17
17
|
</div>
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
<div v-if="showAbout" :name="$t('关于')">
|
|
28
28
|
<AboutPan class="opt-about" show-u-i />
|
|
29
29
|
</div>
|
|
30
|
-
</
|
|
30
|
+
</SettingsTab>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<script setup lang="ts">
|
|
36
|
-
import { ref, watch, onMounted
|
|
36
|
+
import { ref, watch, onMounted } from 'vue'
|
|
37
37
|
|
|
38
38
|
import { i18n } from '../main'
|
|
39
39
|
import { useSettingsStore } from '../state/settings'
|
|
40
40
|
|
|
41
|
-
import
|
|
41
|
+
import SettingsTab from '../components/SettingsTab.vue'
|
|
42
42
|
import OptAccount from './options/OptAccount.vue'
|
|
43
43
|
import OptView from './options/OptView.vue'
|
|
44
44
|
import OptDev from './options/OptDev.vue'
|
|
@@ -315,20 +315,7 @@ import packageInfo from '../../../package.json'
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
info += 'Network Info:\n'
|
|
318
|
-
|
|
319
|
-
['Github ', 'https://api.github.com'],
|
|
320
|
-
['SSQQ API ', 'https://api.stapxs.cn'],
|
|
321
|
-
]
|
|
322
|
-
for (const item of testList) {
|
|
323
|
-
const start = new Date().getTime()
|
|
324
|
-
try {
|
|
325
|
-
await fetch(item[1], { method: 'GET' })
|
|
326
|
-
const end = new Date().getTime()
|
|
327
|
-
info += ` ${item[0]} -> ${end - start} ms\n`
|
|
328
|
-
} catch (e) {
|
|
329
|
-
info += ` ${item[0]} -> failed\n`
|
|
330
|
-
}
|
|
331
|
-
}
|
|
318
|
+
info += ' local only\n'
|
|
332
319
|
info += '```'
|
|
333
320
|
// 构建 popBox 内容
|
|
334
321
|
const popInfo = {
|
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": "5.0
|
|
4
|
+
"version": "5.3.0",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build:web": "npm --prefix client/web run build",
|
|
7
7
|
"prepack": "npm run build:web",
|