koishi-plugin-chat-patch 5.5.1 → 5.6.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/vue/index.vue +8 -1
- package/client/web/dist/assets/{Chat-DTEsebnY.css → Chat-BXVWj5Bd.css} +1 -1
- package/client/web/dist/assets/{Chat-B5Jdrz_2.js → Chat-m4-U5uHa.js} +4 -4
- package/client/web/dist/assets/{MsgBody-tPnKSZOs.js → MsgBody-CzrxyiFO.js} +1 -1
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-BBF1uxm6.js +67 -0
- package/client/web/dist/assets/{index-CSGfOsfr.js → index-EJ2CcODr.js} +70 -76
- package/client/web/dist/assets/index-X9hFOAza.css +1 -0
- package/client/web/dist/index.html +2 -2
- package/client/web/src/App.vue +7 -0
- package/client/web/src/assets/css/chat.css +6 -4
- package/client/web/src/assets/l10n/zh-CN.po +0 -6
- package/client/web/src/components/History.vue +27 -0
- package/client/web/src/components/MsgBody.vue +18 -9
- package/client/web/src/function/connect.ts +208 -46
- package/client/web/src/function/msg.ts +7 -5
- package/client/web/src/function/option.ts +1 -1
- package/client/web/src/function/satori.ts +64 -0
- package/client/web/src/pages/Chat.vue +0 -4
- package/client/web/src/pages/Friends.vue +7 -9
- package/client/web/src/pages/Messages.vue +2 -2
- package/client/web/src/pages/options/OptDev.vue +1 -25
- package/client/web/src/pages/options/OptFunction.vue +23 -0
- package/client/web/tsconfig.tsbuildinfo +1 -1
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/lib/bootstrap.d.ts +6 -0
- package/lib/database.d.ts +5 -2
- package/lib/gateway.d.ts +46 -0
- package/lib/index.js +1468 -131
- package/lib/recorder.d.ts +3 -5
- package/lib/satori.d.ts +3 -0
- package/lib/types.d.ts +17 -0
- package/package.json +4 -1
- package/src/bootstrap.ts +5 -10
- package/src/database.ts +745 -662
- package/src/gateway.ts +259 -0
- package/src/index.ts +63 -53
- package/src/recorder.ts +97 -77
- package/src/satori.ts +19 -0
- package/src/server.d.ts +26 -26
- package/src/types.ts +19 -0
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-ClDybRo_.js +0 -67
- package/client/web/dist/assets/index-B71pPwae.css +0 -1
|
@@ -4,7 +4,7 @@ import { reactive } from 'vue'
|
|
|
4
4
|
import { dispatch, msgPreprocess } from './msg'
|
|
5
5
|
import {
|
|
6
6
|
botKey,
|
|
7
|
-
|
|
7
|
+
connectBackend,
|
|
8
8
|
getActiveBot,
|
|
9
9
|
getBlockedPlatforms,
|
|
10
10
|
getBootstrap,
|
|
@@ -995,30 +995,34 @@ function onSatoriReady(logins: Array<{ platform: string; selfId: string; name: s
|
|
|
995
995
|
}
|
|
996
996
|
const first = visibleLogins[0]
|
|
997
997
|
if (!first) return
|
|
998
|
+
const current = getActiveBot()
|
|
999
|
+
const selected = (current && visibleLogins.find((item) => {
|
|
1000
|
+
return item.platform === current.platform && item.selfId === current.selfId
|
|
1001
|
+
})) ?? first
|
|
998
1002
|
|
|
999
|
-
setActiveBot(
|
|
1003
|
+
setActiveBot(selected.platform, selected.selfId)
|
|
1000
1004
|
setJsonMap()
|
|
1001
|
-
login.uin =
|
|
1002
|
-
login.nickname =
|
|
1003
|
-
login.platform =
|
|
1005
|
+
login.uin = selected.selfId
|
|
1006
|
+
login.nickname = selected.name
|
|
1007
|
+
login.platform = selected.platform
|
|
1004
1008
|
login.satoriLogins = visibleLogins
|
|
1005
|
-
login.selectedSatoriBot = botKey(
|
|
1009
|
+
login.selectedSatoriBot = botKey(selected.platform, selected.selfId)
|
|
1006
1010
|
authStore.loginInfo = {
|
|
1007
|
-
uin:
|
|
1008
|
-
user_id:
|
|
1009
|
-
nickname:
|
|
1010
|
-
platform:
|
|
1011
|
-
avatar:
|
|
1011
|
+
uin: selected.selfId,
|
|
1012
|
+
user_id: selected.selfId,
|
|
1013
|
+
nickname: selected.name,
|
|
1014
|
+
platform: selected.platform,
|
|
1015
|
+
avatar: selected.avatar,
|
|
1012
1016
|
satoriLogins: visibleLogins,
|
|
1013
|
-
selectedSatoriBot: botKey(
|
|
1017
|
+
selectedSatoriBot: botKey(selected.platform, selected.selfId),
|
|
1014
1018
|
}
|
|
1015
1019
|
authStore.botInfo = {
|
|
1016
1020
|
app_name: 'Satori',
|
|
1017
1021
|
app_version: '1.0',
|
|
1018
|
-
platform:
|
|
1022
|
+
platform: selected.platform,
|
|
1019
1023
|
}
|
|
1020
|
-
saveConnectionToHistory(login.address, login.token,
|
|
1021
|
-
flushPendingBotEvents(
|
|
1024
|
+
saveConnectionToHistory(login.address, login.token, selected.selfId, selected.name)
|
|
1025
|
+
flushPendingBotEvents(selected.platform, selected.selfId)
|
|
1022
1026
|
void loadContactsFromCache()
|
|
1023
1027
|
}
|
|
1024
1028
|
|
|
@@ -1622,9 +1626,18 @@ async function appendContactCache(
|
|
|
1622
1626
|
function buildFriendItem(raw: unknown, data: unknown): Record<string, unknown> {
|
|
1623
1627
|
const root = getObject(data)
|
|
1624
1628
|
const user = getObject(root.user) || getObject(root)
|
|
1625
|
-
const
|
|
1629
|
+
const rawItem = getObject(raw)
|
|
1630
|
+
const name = getString(
|
|
1631
|
+
user.name
|
|
1632
|
+
?? user.nick
|
|
1633
|
+
?? user.username
|
|
1634
|
+
?? rawItem.name
|
|
1635
|
+
?? rawItem.nickname
|
|
1636
|
+
?? rawItem.remark
|
|
1637
|
+
?? '',
|
|
1638
|
+
)
|
|
1626
1639
|
const avatar = hasUsableAvatar(user.avatar) ? getString(user.avatar) : ''
|
|
1627
|
-
const item: Record<string, unknown> = { ...
|
|
1640
|
+
const item: Record<string, unknown> = { ...rawItem }
|
|
1628
1641
|
if (!item.channel_id && item.channelId) item.channel_id = item.channelId
|
|
1629
1642
|
if (!item.guild_id && item.guildId) item.guild_id = item.guildId
|
|
1630
1643
|
if (getString(item.guild_id) || getString(item.guildId)) item._groupMember = true
|
|
@@ -1698,7 +1711,101 @@ function buildGroupItem(
|
|
|
1698
1711
|
return item
|
|
1699
1712
|
}
|
|
1700
1713
|
|
|
1701
|
-
//
|
|
1714
|
+
// 刷新联系人时只替换平台返回的 id/name/avatar,保留消息 session 抄录字段
|
|
1715
|
+
function applyFriendIdentity(raw: unknown, data: unknown): Record<string, unknown> {
|
|
1716
|
+
const cached = getObject(raw)
|
|
1717
|
+
const item: Record<string, unknown> = JSON.parse(JSON.stringify(cached)) as Record<string, unknown>
|
|
1718
|
+
const rawObj = getObject(item.raw) || cached
|
|
1719
|
+
const root = getObject(data)
|
|
1720
|
+
const user = getObject(root.user) || root
|
|
1721
|
+
const id = getString(user.id)
|
|
1722
|
+
|| getString(item.id)
|
|
1723
|
+
|| getString(rawObj.user_id)
|
|
1724
|
+
|| getString(rawObj.id)
|
|
1725
|
+
|| ''
|
|
1726
|
+
const name = getString(user.name)
|
|
1727
|
+
|| getString(user.nick)
|
|
1728
|
+
|| getString(user.nickname)
|
|
1729
|
+
|| getString(item.name)
|
|
1730
|
+
|| getString(rawObj.name)
|
|
1731
|
+
|| getString(rawObj.nickname)
|
|
1732
|
+
|| getString(rawObj.remark)
|
|
1733
|
+
|| id
|
|
1734
|
+
const avatar = hasUsableAvatar(user.avatar)
|
|
1735
|
+
? getString(user.avatar)
|
|
1736
|
+
: hasUsableAvatar(item.avatar)
|
|
1737
|
+
? getString(item.avatar)
|
|
1738
|
+
: hasUsableAvatar(rawObj.avatar)
|
|
1739
|
+
? getString(rawObj.avatar)
|
|
1740
|
+
: ''
|
|
1741
|
+
item.id = id
|
|
1742
|
+
item.name = name
|
|
1743
|
+
if (avatar) item.avatar = avatar
|
|
1744
|
+
else if (item.avatar && !hasUsableAvatar(item.avatar)) delete item.avatar
|
|
1745
|
+
|
|
1746
|
+
const nextRaw: Record<string, unknown> = { ...rawObj }
|
|
1747
|
+
nextRaw.id = id
|
|
1748
|
+
nextRaw.user_id = id
|
|
1749
|
+
if (name) nextRaw.name = name
|
|
1750
|
+
if (avatar) nextRaw.avatar = avatar
|
|
1751
|
+
item.raw = nextRaw
|
|
1752
|
+
return item
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// 刷新群组时只替换平台返回的 id/name/avatar,保留频道/群 ID 等 session 字段
|
|
1756
|
+
function applyGroupIdentity(
|
|
1757
|
+
raw: unknown,
|
|
1758
|
+
data: unknown,
|
|
1759
|
+
platform: string,
|
|
1760
|
+
): Record<string, unknown> {
|
|
1761
|
+
const cached = getObject(raw)
|
|
1762
|
+
const item: Record<string, unknown> = JSON.parse(JSON.stringify(cached)) as Record<string, unknown>
|
|
1763
|
+
const rawObj = getObject(item.raw) || cached
|
|
1764
|
+
const root = getObject(data)
|
|
1765
|
+
const channel = getObject(root.channel) || root
|
|
1766
|
+
const guild = getObject(root.guild)
|
|
1767
|
+
const id = normalizeGroupId(
|
|
1768
|
+
getString(guild.id)
|
|
1769
|
+
|| getString(channel.id)
|
|
1770
|
+
|| getString(item.id)
|
|
1771
|
+
|| getString(rawObj.group_id)
|
|
1772
|
+
|| getString(rawObj.id)
|
|
1773
|
+
|| getString(rawObj.guild_id)
|
|
1774
|
+
|| '',
|
|
1775
|
+
)
|
|
1776
|
+
const name = getString(guild.name)
|
|
1777
|
+
|| getString(channel.name)
|
|
1778
|
+
|| getString(item.name)
|
|
1779
|
+
|| getString(rawObj.group_name)
|
|
1780
|
+
|| getString(rawObj.name)
|
|
1781
|
+
|| id
|
|
1782
|
+
const avatar = hasUsableAvatar(guild.avatar)
|
|
1783
|
+
? getString(guild.avatar)
|
|
1784
|
+
: hasUsableAvatar(channel.avatar)
|
|
1785
|
+
? getString(channel.avatar)
|
|
1786
|
+
: hasUsableAvatar(item.avatar)
|
|
1787
|
+
? getString(item.avatar)
|
|
1788
|
+
: hasUsableAvatar(rawObj.avatar)
|
|
1789
|
+
? getString(rawObj.avatar)
|
|
1790
|
+
: buildQqGroupAvatar(platform, id)
|
|
1791
|
+
item.id = id
|
|
1792
|
+
item.name = name
|
|
1793
|
+
if (avatar) item.avatar = avatar
|
|
1794
|
+
else if (item.avatar && !hasUsableAvatar(item.avatar)) delete item.avatar
|
|
1795
|
+
|
|
1796
|
+
const nextRaw: Record<string, unknown> = { ...rawObj }
|
|
1797
|
+
nextRaw.id = id
|
|
1798
|
+
nextRaw.group_id = id
|
|
1799
|
+
if (name) {
|
|
1800
|
+
nextRaw.name = name
|
|
1801
|
+
nextRaw.group_name = name
|
|
1802
|
+
}
|
|
1803
|
+
if (avatar) nextRaw.avatar = avatar
|
|
1804
|
+
item.raw = nextRaw
|
|
1805
|
+
return item
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
// 刷新群组时逐个请求 channel.get,并把结果写回缓存和界面
|
|
1702
1809
|
async function fetchGroupProfiles(
|
|
1703
1810
|
active: { platform: string; selfId: string },
|
|
1704
1811
|
groups: unknown[],
|
|
@@ -1713,30 +1820,32 @@ async function fetchGroupProfiles(
|
|
|
1713
1820
|
const rawObj = getObject(raw)
|
|
1714
1821
|
const guildId = getString(rawObj.guild_id) || getString(rawObj.guildId) || id
|
|
1715
1822
|
const channelId = getString(rawObj.channel_id) || getString(rawObj.channelId) || id
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
withTimeout(
|
|
1722
|
-
request('channel.get', { channel_id: channelId, guild_id: guildId }, active).catch(() => null),
|
|
1723
|
-
5000,
|
|
1724
|
-
),
|
|
1725
|
-
])
|
|
1726
|
-
const item = buildGroupItem(raw, { guild: guildData, channel: channelData }, active.platform)
|
|
1823
|
+
const channelData = await withTimeout(
|
|
1824
|
+
request('channel.get', { channel_id: channelId, guild_id: guildId }, active).catch(() => null),
|
|
1825
|
+
5000,
|
|
1826
|
+
)
|
|
1827
|
+
const item = applyGroupIdentity(raw, channelData ?? {}, active.platform)
|
|
1727
1828
|
processedItems.push(item)
|
|
1829
|
+
const itemRaw = getObject(item.raw) ?? item
|
|
1830
|
+
identityInfoCache.set(identityCacheKey('group', active.platform, active.selfId, id), {
|
|
1831
|
+
name: getString(item.name),
|
|
1832
|
+
avatar: hasUsableAvatar(item.avatar) ? getString(item.avatar) : '',
|
|
1833
|
+
raw: itemRaw,
|
|
1834
|
+
})
|
|
1728
1835
|
|
|
1729
1836
|
if (updateUi && contactStore) {
|
|
1730
1837
|
const existing = contactStore.userList.find((contact) => {
|
|
1731
1838
|
return String(contact.group_id) === id
|
|
1732
1839
|
})
|
|
1733
1840
|
if (existing) {
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1841
|
+
if (getString(itemRaw.group_name) || getString(itemRaw.name)) {
|
|
1842
|
+
existing.group_name = getString(itemRaw.group_name) || getString(itemRaw.name)
|
|
1843
|
+
}
|
|
1844
|
+
if (hasUsableAvatar(item.avatar)) existing.avatar = getString(item.avatar)
|
|
1736
1845
|
else if (existing.avatar && !hasUsableAvatar(existing.avatar)) delete existing.avatar
|
|
1737
1846
|
contactStore.userList = [...contactStore.userList]
|
|
1738
1847
|
} else {
|
|
1739
|
-
dispatch({ retcode: 0, data: [
|
|
1848
|
+
dispatch({ retcode: 0, data: [itemRaw] }, 'getGroupList')
|
|
1740
1849
|
}
|
|
1741
1850
|
}
|
|
1742
1851
|
|
|
@@ -1772,8 +1881,47 @@ async function cacheBotContacts(_bot: { platform: string; selfId: string }) {
|
|
|
1772
1881
|
}
|
|
1773
1882
|
|
|
1774
1883
|
export async function refreshAllBots() {
|
|
1775
|
-
useContactStore()
|
|
1776
|
-
|
|
1884
|
+
const contactStore = useContactStore()
|
|
1885
|
+
try {
|
|
1886
|
+
const result = await requestAllBotsCache()
|
|
1887
|
+
const bots = Array.isArray(getObject(result).bots) ? getObject(result).bots as unknown[] : []
|
|
1888
|
+
for (const rawBot of bots) {
|
|
1889
|
+
const bot = getObject(rawBot)
|
|
1890
|
+
const platform = getString(bot.platform)
|
|
1891
|
+
const selfId = getString(bot.selfId)
|
|
1892
|
+
if (!platform || !selfId) continue
|
|
1893
|
+
const active = { platform, selfId }
|
|
1894
|
+
try {
|
|
1895
|
+
const groups = Array.isArray(bot.groups) ? bot.groups as unknown[] : []
|
|
1896
|
+
const friends = Array.isArray(bot.friends) ? bot.friends as unknown[] : []
|
|
1897
|
+
const groupItems = await fetchGroupProfiles(active, groups, false)
|
|
1898
|
+
const friendItems = await fetchFriendProfiles(active, friends, false)
|
|
1899
|
+
const groupRaws = groupItems.map((item) => getObject(item).raw ?? item)
|
|
1900
|
+
const friendRaws = friendItems.map((item) => cachedFriendRaw(getObject(item), item))
|
|
1901
|
+
const userList = [...groupRaws, ...friendRaws] as unknown as (UserFriendElem & UserGroupElem)[]
|
|
1902
|
+
const key = botKey(platform, selfId)
|
|
1903
|
+
const state = contactStore.botStates.get(key)
|
|
1904
|
+
contactStore.botStates.set(key, {
|
|
1905
|
+
userList,
|
|
1906
|
+
baseList: state?.baseList ?? [],
|
|
1907
|
+
onMsgList: state?.onMsgList ?? [],
|
|
1908
|
+
})
|
|
1909
|
+
if (isActiveBot(active)) {
|
|
1910
|
+
contactStore.userList = userList
|
|
1911
|
+
if (groupRaws.length > 0) {
|
|
1912
|
+
dispatch({ retcode: 0, data: groupRaws }, 'getGroupList')
|
|
1913
|
+
}
|
|
1914
|
+
if (friendRaws.length > 0) {
|
|
1915
|
+
dispatch({ retcode: 0, data: friendRaws }, 'getFriendList')
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
} catch (error: unknown) {
|
|
1919
|
+
logger.add(LogType.ERR, `刷新机器人 ${platform}/${selfId} 联系人失败: ${String(error)}`)
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
} catch (error: unknown) {
|
|
1923
|
+
logger.add(LogType.ERR, `刷新联系人失败: ${String(error)}`)
|
|
1924
|
+
}
|
|
1777
1925
|
}
|
|
1778
1926
|
|
|
1779
1927
|
async function fetchFriendProfiles(
|
|
@@ -1792,10 +1940,10 @@ async function fetchFriendProfiles(
|
|
|
1792
1940
|
let data: unknown = {}
|
|
1793
1941
|
if (!userGetBlocked) {
|
|
1794
1942
|
try {
|
|
1795
|
-
data = await
|
|
1796
|
-
request('user.get', { user_id: id }, active),
|
|
1797
|
-
|
|
1798
|
-
|
|
1943
|
+
data = await withTimeout(
|
|
1944
|
+
request('user.get', { user_id: id }, active).catch(() => null),
|
|
1945
|
+
5000,
|
|
1946
|
+
) ?? {}
|
|
1799
1947
|
} catch (error: unknown) {
|
|
1800
1948
|
const message = error instanceof Error ? error.message : String(error)
|
|
1801
1949
|
if (/is not a function|Satori API 返回 500/i.test(message)) {
|
|
@@ -1814,21 +1962,28 @@ async function fetchFriendProfiles(
|
|
|
1814
1962
|
}
|
|
1815
1963
|
}
|
|
1816
1964
|
}
|
|
1817
|
-
const item =
|
|
1965
|
+
const item = applyFriendIdentity(raw, data)
|
|
1818
1966
|
processedItems.push(item)
|
|
1967
|
+
const itemRaw = getObject(item.raw) ?? item
|
|
1968
|
+
identityInfoCache.set(identityCacheKey('user', active.platform, active.selfId, id), {
|
|
1969
|
+
name: getString(item.name),
|
|
1970
|
+
avatar: hasUsableAvatar(item.avatar) ? getString(item.avatar) : '',
|
|
1971
|
+
raw: itemRaw,
|
|
1972
|
+
})
|
|
1819
1973
|
if (updateUi && contactStore) {
|
|
1820
1974
|
const existing = contactStore.userList.find((contact) => {
|
|
1821
1975
|
return String(contact.user_id) === id
|
|
1822
1976
|
})
|
|
1823
1977
|
if (existing) {
|
|
1824
|
-
|
|
1825
|
-
if (
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1978
|
+
const displayName = getString(item.name)
|
|
1979
|
+
if (displayName) {
|
|
1980
|
+
existing.nickname = displayName
|
|
1981
|
+
existing.remark = displayName
|
|
1982
|
+
}
|
|
1983
|
+
if (hasUsableAvatar(item.avatar)) existing.avatar = getString(item.avatar)
|
|
1829
1984
|
contactStore.userList = [...contactStore.userList]
|
|
1830
1985
|
} else {
|
|
1831
|
-
dispatch({ retcode: 0, data: [item] }, 'getFriendList')
|
|
1986
|
+
dispatch({ retcode: 0, data: [cachedFriendRaw(item, item)] }, 'getFriendList')
|
|
1832
1987
|
contactStore.friendLoadedCount += 1
|
|
1833
1988
|
}
|
|
1834
1989
|
}
|
|
@@ -2090,12 +2245,17 @@ export async function loadContactsFromCache() {
|
|
|
2090
2245
|
function startSatori() {
|
|
2091
2246
|
disposeConnection?.()
|
|
2092
2247
|
login.creating = true
|
|
2093
|
-
disposeConnection =
|
|
2248
|
+
disposeConnection = connectBackend(onSatoriEvent, onSatoriReady, (online) => {
|
|
2094
2249
|
login.status = online
|
|
2095
2250
|
login.creating = !online
|
|
2096
2251
|
})
|
|
2097
2252
|
}
|
|
2098
2253
|
|
|
2254
|
+
// Satori 部分操作只返回纯文本成功标识(例如 OK),不需要进入 OneBot 风格事件分发
|
|
2255
|
+
function isPlainSuccessText(data: unknown): boolean {
|
|
2256
|
+
return typeof data === 'string' && !data.trim().startsWith('{') && !data.trim().startsWith('[')
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2099
2259
|
export class Connector {
|
|
2100
2260
|
static create(address: string, token: string, _wss?: boolean) {
|
|
2101
2261
|
login.address = address || 'Satori'
|
|
@@ -2172,6 +2332,7 @@ export class Connector {
|
|
|
2172
2332
|
getString(mapped.params.channel_id) || getString(value.channel_id),
|
|
2173
2333
|
)
|
|
2174
2334
|
.then((result) => {
|
|
2335
|
+
if (isPlainSuccessText(result.data)) return
|
|
2175
2336
|
const response = satoriResponseToOneBot(action, result.data, active.platform)
|
|
2176
2337
|
response.channel_id = result.channelId
|
|
2177
2338
|
response.channelId = result.channelId
|
|
@@ -2189,6 +2350,7 @@ export class Connector {
|
|
|
2189
2350
|
}
|
|
2190
2351
|
void request(mapped.method, mapped.params, active)
|
|
2191
2352
|
.then((data) => {
|
|
2353
|
+
if (isPlainSuccessText(data)) return
|
|
2192
2354
|
const response = satoriResponseToOneBot(action, data, active.platform)
|
|
2193
2355
|
dispatch(response, echo)
|
|
2194
2356
|
})
|
|
@@ -2535,12 +2535,14 @@ function newMsg(_: string, data: any) {
|
|
|
2535
2535
|
|
|
2536
2536
|
const isTempGroupMessage = data.sub_type === 'group'
|
|
2537
2537
|
const groupNoticeType = settingsStore.sysConfig.group_notice_type
|
|
2538
|
+
const privateNoticeType = settingsStore.sysConfig.private_notice_type ?? 'none'
|
|
2538
2539
|
const hasForcedGroupInnerNotice = data.atme || data.atall || isImportant || isGroupNotice
|
|
2539
|
-
const allowGroupInnerNotice =
|
|
2540
|
-
groupNoticeType !== 'none' ||
|
|
2541
|
-
|
|
2542
|
-
const allowGroupSystemNotice =
|
|
2543
|
-
groupNoticeType === 'all'
|
|
2540
|
+
const allowGroupInnerNotice = isGroupMessage
|
|
2541
|
+
? groupNoticeType !== 'none' || hasForcedGroupInnerNotice
|
|
2542
|
+
: privateNoticeType !== 'none'
|
|
2543
|
+
const allowGroupSystemNotice = isGroupMessage
|
|
2544
|
+
? groupNoticeType === 'all'
|
|
2545
|
+
: privateNoticeType === 'all'
|
|
2544
2546
|
|
|
2545
2547
|
// 会话状态更新 ============================================
|
|
2546
2548
|
const sessionId = isTempGroupMessage ? sender : id
|
|
@@ -100,6 +100,7 @@ export const optDefault: { [key: string]: any } = {
|
|
|
100
100
|
msg_taill: '',
|
|
101
101
|
quick_send: 'default',
|
|
102
102
|
group_notice_type: 'none',
|
|
103
|
+
private_notice_type: 'none',
|
|
103
104
|
send_face: false,
|
|
104
105
|
send_key: 'none',
|
|
105
106
|
close_ga: false,
|
|
@@ -113,7 +114,6 @@ export const optDefault: { [key: string]: any } = {
|
|
|
113
114
|
// Dev
|
|
114
115
|
msg_type: 2,
|
|
115
116
|
log_level: 'err',
|
|
116
|
-
debug_msg: false,
|
|
117
117
|
custom_css: '',
|
|
118
118
|
// Glagame
|
|
119
119
|
openai_api: '',
|
|
@@ -4,6 +4,7 @@ export interface SatoriBootstrap {
|
|
|
4
4
|
endpoint: string
|
|
5
5
|
token: string
|
|
6
6
|
basePath: string
|
|
7
|
+
logins?: SatoriLogin[]
|
|
7
8
|
blockedPlatforms: Array<{
|
|
8
9
|
platformName: string
|
|
9
10
|
exactMatch: boolean
|
|
@@ -115,10 +116,16 @@ function receiveBootstrap(data: Record<string, unknown>) {
|
|
|
115
116
|
endpoint: getString(payload.endpoint) || '/satori',
|
|
116
117
|
token: getString(payload.token),
|
|
117
118
|
basePath: getString(payload.basePath) || '/chat-patch',
|
|
119
|
+
logins: Array.isArray(payload.logins)
|
|
120
|
+
? payload.logins as SatoriLogin[]
|
|
121
|
+
: [],
|
|
118
122
|
blockedPlatforms: Array.isArray(payload.blockedPlatforms)
|
|
119
123
|
? payload.blockedPlatforms as SatoriBootstrap['blockedPlatforms']
|
|
120
124
|
: [],
|
|
121
125
|
}
|
|
126
|
+
if (Array.isArray(payload.logins)) {
|
|
127
|
+
logins = payload.logins as SatoriLogin[]
|
|
128
|
+
}
|
|
122
129
|
window.clearTimeout(bootstrapTimeout)
|
|
123
130
|
resolveBootstrapCallback?.(bootstrap)
|
|
124
131
|
resolveBootstrapCallback = null
|
|
@@ -225,6 +232,63 @@ export function handleConsoleResponse(data: Record<string, unknown>) {
|
|
|
225
232
|
}
|
|
226
233
|
}
|
|
227
234
|
|
|
235
|
+
export function connectBackend(
|
|
236
|
+
onEvent: (event: SatoriEvent) => void,
|
|
237
|
+
onReady: (logins: SatoriLogin[]) => void,
|
|
238
|
+
onStatus: (online: boolean) => void,
|
|
239
|
+
): () => void {
|
|
240
|
+
let disposed = false
|
|
241
|
+
|
|
242
|
+
const handleMessage = (event: MessageEvent) => {
|
|
243
|
+
const data = getObject(event.data)
|
|
244
|
+
if (getString(data.source) !== 'chat-patch-event') return
|
|
245
|
+
const payload = getObject(data.payload)
|
|
246
|
+
const kind = getString(payload.kind)
|
|
247
|
+
if (kind === 'ready') {
|
|
248
|
+
const next = Array.isArray(payload.logins) ? payload.logins as SatoriLogin[] : []
|
|
249
|
+
logins = next
|
|
250
|
+
onReady(next)
|
|
251
|
+
onStatus(true)
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
if (kind === 'status') {
|
|
255
|
+
onStatus(payload.online === true)
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
if (kind !== 'event') return
|
|
259
|
+
const raw = getObject(payload.event)
|
|
260
|
+
sequence = Number(raw.sn ?? sequence)
|
|
261
|
+
localStorage.setItem('chat-patch:sn', String(sequence))
|
|
262
|
+
onEvent({
|
|
263
|
+
type: getString(raw.type),
|
|
264
|
+
platform: getString(raw.platform),
|
|
265
|
+
selfId: getString(raw.selfId),
|
|
266
|
+
timestamp: Number(raw.timestamp ?? Date.now()),
|
|
267
|
+
sn: sequence,
|
|
268
|
+
body: getObject(raw.body),
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
window.addEventListener('message', handleMessage)
|
|
273
|
+
|
|
274
|
+
void resolveBootstrap().then((info) => {
|
|
275
|
+
if (disposed) return
|
|
276
|
+
const initial = info.logins ?? []
|
|
277
|
+
if (initial.length) {
|
|
278
|
+
logins = initial
|
|
279
|
+
onReady(initial)
|
|
280
|
+
onStatus(true)
|
|
281
|
+
}
|
|
282
|
+
}).catch(() => {
|
|
283
|
+
if (!disposed) onStatus(false)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
return () => {
|
|
287
|
+
disposed = true
|
|
288
|
+
window.removeEventListener('message', handleMessage)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
228
292
|
export function connect(
|
|
229
293
|
onEvent: (event: SatoriEvent) => void,
|
|
230
294
|
onReady: (logins: SatoriLogin[]) => void,
|
|
@@ -498,10 +498,6 @@
|
|
|
498
498
|
<div><font-awesome-icon :icon="['fas', 'at']" /></div>
|
|
499
499
|
<a>{{ $t('提及') }}</a>
|
|
500
500
|
</div>
|
|
501
|
-
<div v-show="tags.menuDisplay.poke" @click="sendPoke(selectedMsg ? selectedMsg.sender.user_id : undefined)">
|
|
502
|
-
<div><font-awesome-icon :icon="['fas', 'fa-hand-point-up']" /></div>
|
|
503
|
-
<a>{{ $t('戳一戳') }}</a>
|
|
504
|
-
</div>
|
|
505
501
|
<div v-show="tags.menuDisplay.remove" @click="removeUser">
|
|
506
502
|
<div><font-awesome-icon :icon="['fas', 'trash-can']" /></div>
|
|
507
503
|
<a>{{ $t('移出群聊') }}</a>
|
|
@@ -282,8 +282,6 @@
|
|
|
282
282
|
function backToRobots() {
|
|
283
283
|
snapshotCurrentBot()
|
|
284
284
|
activeBotId.value = ''
|
|
285
|
-
chatStore.messageList = []
|
|
286
|
-
chatStore.chatInfo.show.id = 0
|
|
287
285
|
}
|
|
288
286
|
|
|
289
287
|
function selectRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
|
|
@@ -408,7 +406,7 @@
|
|
|
408
406
|
}
|
|
409
407
|
isSearch.value = false
|
|
410
408
|
searchInfo.value = ''
|
|
411
|
-
contactStore.showList = []
|
|
409
|
+
contactStore.showList = []
|
|
412
410
|
|
|
413
411
|
const back = {
|
|
414
412
|
type: data.group_id ? 'group' : 'user',
|
|
@@ -449,19 +447,19 @@
|
|
|
449
447
|
isSearch.value = true
|
|
450
448
|
contactStore.showList = allContacts.value.filter(
|
|
451
449
|
(item: ContactWithBot) => {
|
|
452
|
-
const name = (
|
|
453
|
-
item.user_id? item.nickname + item.remark: item.group_name
|
|
454
|
-
).toLowerCase()
|
|
450
|
+
const name = String(getShowName(item) ?? '').toLowerCase()
|
|
455
451
|
if (name.includes(value)) return true
|
|
456
|
-
const id = item.user_id
|
|
457
|
-
if (id.
|
|
452
|
+
const id = String(item.user_id ?? item.group_id ?? '')
|
|
453
|
+
if (id.includes(value)) return true
|
|
454
|
+
const channelId = String(item.channel_id ?? item.channelId ?? '')
|
|
455
|
+
if (channelId && channelId.includes(value)) return true
|
|
458
456
|
if (item.py_name && matchPinyin(item.py_name, value)) return true
|
|
459
457
|
return false
|
|
460
458
|
},
|
|
461
459
|
)
|
|
462
460
|
} else {
|
|
463
461
|
isSearch.value = false
|
|
464
|
-
contactStore.showList = []
|
|
462
|
+
contactStore.showList = []
|
|
465
463
|
}
|
|
466
464
|
// macOS: 刷新 TouchBar
|
|
467
465
|
if(backend.isDesktop()) {
|
|
@@ -258,8 +258,6 @@
|
|
|
258
258
|
function backToRobots() {
|
|
259
259
|
snapshotCurrentBot()
|
|
260
260
|
activeBotId.value = ''
|
|
261
|
-
chatStore.messageList = []
|
|
262
|
-
chatStore.chatInfo.show.id = 0
|
|
263
261
|
}
|
|
264
262
|
|
|
265
263
|
function snapshotCurrentBot() {
|
|
@@ -348,6 +346,8 @@
|
|
|
348
346
|
}
|
|
349
347
|
|
|
350
348
|
function toggleRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
|
|
349
|
+
// 展开/折叠前清掉残留弹窗遮罩,避免点击被遮挡
|
|
350
|
+
uiStore.popBoxList = []
|
|
351
351
|
if (activeBotId.value === botKey(bot.platform, bot.selfId)) {
|
|
352
352
|
backToRobots()
|
|
353
353
|
} else {
|
|
@@ -28,23 +28,6 @@
|
|
|
28
28
|
</select>
|
|
29
29
|
</div>
|
|
30
30
|
</div>
|
|
31
|
-
<div class="opt-item">
|
|
32
|
-
<div :class="checkDefault('debug_msg')" />
|
|
33
|
-
<font-awesome-icon :icon="['fas', 'robot']" />
|
|
34
|
-
<div>
|
|
35
|
-
<label for="opt-dev-debug-msg">{{ $t('禁用消息渲染') }}</label>
|
|
36
|
-
<span>
|
|
37
|
-
<a style="cursor: pointer" @click="sendAbab">{{ $t('点击进行 CAPTCHA 验证') }}</a>
|
|
38
|
-
</span>
|
|
39
|
-
</div>
|
|
40
|
-
<label class="ss-switch">
|
|
41
|
-
<input id="opt-dev-debug-msg" v-model="settingsStore.sysConfig.debug_msg"
|
|
42
|
-
type="checkbox" name="debug_msg" @change="save">
|
|
43
|
-
<div>
|
|
44
|
-
<div />
|
|
45
|
-
</div>
|
|
46
|
-
</label>
|
|
47
|
-
</div>
|
|
48
31
|
<div class="opt-item">
|
|
49
32
|
<font-awesome-icon :icon="['fas', 'rotate-left']" />
|
|
50
33
|
<div>
|
|
@@ -55,7 +38,7 @@
|
|
|
55
38
|
class="ss-button"
|
|
56
39
|
style="width: 100px; font-size: 0.8rem; background: var(--color-red); border-color: var(--color-red); color: #fff"
|
|
57
40
|
@click="resetDefaults">
|
|
58
|
-
{{ $t('
|
|
41
|
+
{{ $t('重置') }}
|
|
59
42
|
</button>
|
|
60
43
|
</div>
|
|
61
44
|
<div class="opt-item">
|
|
@@ -234,13 +217,6 @@ import packageInfo from '../../../package.json'
|
|
|
234
217
|
})
|
|
235
218
|
}
|
|
236
219
|
|
|
237
|
-
function sendAbab() {
|
|
238
|
-
new PopInfo().add(
|
|
239
|
-
PopType.INFO,
|
|
240
|
-
$t('你不是人(逃'),
|
|
241
|
-
)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
220
|
function printRuntime() {
|
|
245
221
|
if(backend.isMobile()) {
|
|
246
222
|
const switcher = document.getElementById('__vconsole')?.getElementsByClassName('vc-switch')[0]
|
|
@@ -66,6 +66,29 @@
|
|
|
66
66
|
</select>
|
|
67
67
|
</div>
|
|
68
68
|
</div>
|
|
69
|
+
<div class="opt-item">
|
|
70
|
+
<div :class="checkDefault('private_notice_type')" />
|
|
71
|
+
<font-awesome-icon :icon="['fas', 'envelope']" />
|
|
72
|
+
<div>
|
|
73
|
+
<label for="opt-function-private-notice-type">{{ $t('私信消息通知方式') }}</label>
|
|
74
|
+
<span>{{ $t('默认不发起系统通知') }}</span>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="select-wrapper">
|
|
77
|
+
<select id="opt-function-private-notice-type"
|
|
78
|
+
v-model="settingsStore.sysConfig.private_notice_type"
|
|
79
|
+
name="private_notice_type" title="private_notice_type" @change="save">
|
|
80
|
+
<option value="none">
|
|
81
|
+
{{ $t('不通知(默认)') }}
|
|
82
|
+
</option>
|
|
83
|
+
<option value="inner">
|
|
84
|
+
{{ $t('仅应用内通知') }}
|
|
85
|
+
</option>
|
|
86
|
+
<option value="all">
|
|
87
|
+
{{ $t('应用内通知和系统通知') }}
|
|
88
|
+
</option>
|
|
89
|
+
</select>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
69
92
|
</div>
|
|
70
93
|
<div class="ss-card">
|
|
71
94
|
<header>{{ $t('聊天选项') }}</header>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/main.ts","./src/function/base.ts","./src/function/connect.ts","./src/function/favicon.ts","./src/function/input.ts","./src/function/msg.ts","./src/function/notify.ts","./src/function/option.ts","./src/function/satori-model.ts","./src/function/satori.ts","./src/function/sender.ts","./src/function/tooltip.ts","./src/function/elements/information.ts","./src/function/elements/system.ts","./src/function/elements/vuecomp.ts","./src/function/model/emoji.ts","./src/function/model/img.ts","./src/function/model/msg-body.ts","./src/function/utils/apputil.ts","./src/function/utils/avatarutil.ts","./src/function/utils/backgroundutil.ts","./src/function/utils/linkviewutil.ts","./src/function/utils/localhistoryutil.ts","./src/function/utils/msgutil.ts","./src/function/utils/pinyin.ts","./src/function/utils/recordutil.ts","./src/function/utils/sessionutil.ts","./src/function/utils/systemutil.ts","./src/runtime/backend.ts","./src/state/auth.ts","./src/state/chat.ts","./src/state/connection.ts","./src/state/contact.ts","./src/state/qzone.ts","./src/state/sessionhistory.ts","./src/state/settings.ts","./src/state/sticker.ts","./src/state/ui.ts","./env.d.ts"],"errors":true,"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/main.ts","./src/function/base.ts","./src/function/connect.ts","./src/function/debug.ts","./src/function/favicon.ts","./src/function/input.ts","./src/function/msg.ts","./src/function/notify.ts","./src/function/option.ts","./src/function/satori-model.ts","./src/function/satori.ts","./src/function/sender.ts","./src/function/tooltip.ts","./src/function/elements/information.ts","./src/function/elements/system.ts","./src/function/elements/vuecomp.ts","./src/function/model/emoji.ts","./src/function/model/img.ts","./src/function/model/msg-body.ts","./src/function/utils/apputil.ts","./src/function/utils/avatarutil.ts","./src/function/utils/backgroundutil.ts","./src/function/utils/linkviewutil.ts","./src/function/utils/localhistoryutil.ts","./src/function/utils/msgutil.ts","./src/function/utils/pinyin.ts","./src/function/utils/recordutil.ts","./src/function/utils/sessionutil.ts","./src/function/utils/systemutil.ts","./src/runtime/backend.ts","./src/state/auth.ts","./src/state/chat.ts","./src/state/connection.ts","./src/state/contact.ts","./src/state/qzone.ts","./src/state/sessionhistory.ts","./src/state/settings.ts","./src/state/sticker.ts","./src/state/ui.ts","./env.d.ts"],"errors":true,"version":"5.9.3"}
|