koishi-plugin-chat-patch 3.0.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/client/vue/index.vue +60 -634
  2. package/client/web/dist/assets/AppIcon-DIku6-h0.png +0 -0
  3. package/client/web/dist/assets/AppIconDark-BYymN71t.png +0 -0
  4. package/client/web/dist/assets/CapacitorAppIcon-CSZwNhvi.png +0 -0
  5. package/client/web/dist/assets/CapacitorAppIconDark-BMvMOzsg.png +0 -0
  6. package/client/web/dist/assets/Chat-CTdyeaX2.css +1 -0
  7. package/client/web/dist/assets/Chat-DkZvD7d8.js +28 -0
  8. package/client/web/dist/assets/MealHungryPan-Beos3lRI.js +1 -0
  9. package/client/web/dist/assets/MsgBody-aZ4_aija.js +1 -0
  10. package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-CPZjRLp6.js +67 -0
  11. package/client/web/dist/assets/NapcatAppIcon-C7VOAkW9.png +0 -0
  12. package/client/web/dist/assets/Vue-lEhHouxB.png +0 -0
  13. package/client/web/dist/assets/append_darwin-CqBNU62J.css +1 -0
  14. package/client/web/dist/assets/append_full_vibrancy-j0D2LM9m.css +1 -0
  15. package/client/web/dist/assets/append_linux-uhxeBqeC.css +1 -0
  16. package/client/web/dist/assets/append_linux_vibrancy-COiZq8MS.css +1 -0
  17. package/client/web/dist/assets/append_napcat-DV8CAyAd.css +1 -0
  18. package/client/web/dist/assets/append_new-407Lo5_V.css +1 -0
  19. package/client/web/dist/assets/append_vibrancy-6FHctkOY.css +1 -0
  20. package/client/web/dist/assets/append_win32-srmD-78y.css +1 -0
  21. package/client/web/dist/assets/cakes-CxTVKdnK.svg +189 -0
  22. package/client/web/dist/assets/core-DhEqZVGG.js +1 -0
  23. package/client/web/dist/assets/event-Cadp6m6J.js +1 -0
  24. package/client/web/dist/assets/index-CPTXiemn.js +4045 -0
  25. package/client/web/dist/assets/index-Cg_esKB0.js +1 -0
  26. package/client/web/dist/assets/index-Cln012sP.css +1 -0
  27. package/client/web/dist/assets//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223-CJKIKBn3.ttf +0 -0
  28. package/client/web/dist/assets//346/234/237/345/276/205-C90_OY60.png +0 -0
  29. package/client/web/dist/bcui/css/color-dark.css +35 -0
  30. package/client/web/dist/bcui/css/color-light.css +35 -0
  31. package/client/web/dist/bcui/css/style.css +468 -0
  32. package/client/web/dist/bcui/js/main.js +193 -0
  33. package/client/web/dist/css/append-dark.css +13 -0
  34. package/client/web/dist/css/append-light.css +13 -0
  35. package/client/web/dist/css/append-napcat-dark.css +14 -0
  36. package/client/web/dist/css/append-napcat-light.css +14 -0
  37. package/client/web/dist/favicon.ico +0 -0
  38. package/client/web/dist/img/icons/icon-for-fuck-apple.png +0 -0
  39. package/client/web/dist/img/icons/icon-maskable.png +0 -0
  40. package/client/web/dist/img/icons/icon.png +0 -0
  41. package/client/web/dist/img/icons/icon.svg +10 -0
  42. package/client/web/dist/index.html +22 -0
  43. package/client/web/dist/robots.txt +2 -0
  44. package/client/web/dist/sw.js +58 -0
  45. package/client/web/env.d.ts +56 -0
  46. package/client/web/index.html +21 -0
  47. package/client/web/package-lock.json +3419 -0
  48. package/client/web/package.json +62 -0
  49. package/client/web/public/bcui/css/color-dark.css +35 -0
  50. package/client/web/public/bcui/css/color-light.css +35 -0
  51. package/client/web/public/bcui/css/style.css +468 -0
  52. package/client/web/public/bcui/js/main.js +193 -0
  53. package/client/web/public/css/append-dark.css +13 -0
  54. package/client/web/public/css/append-light.css +13 -0
  55. package/client/web/public/css/append-napcat-dark.css +14 -0
  56. package/client/web/public/css/append-napcat-light.css +14 -0
  57. package/client/web/public/favicon.ico +0 -0
  58. package/client/web/public/img/icons/icon-for-fuck-apple.png +0 -0
  59. package/client/web/public/img/icons/icon-maskable.png +0 -0
  60. package/client/web/public/img/icons/icon.png +0 -0
  61. package/client/web/public/img/icons/icon.svg +10 -0
  62. package/client/web/public/robots.txt +2 -0
  63. package/client/web/public/sw.js +58 -0
  64. package/client/web/scripts/copy-bcui.mjs +17 -0
  65. package/client/web/src/App.vue +1127 -0
  66. package/client/web/src/assets/css/append/append_darwin.css +68 -0
  67. package/client/web/src/assets/css/append/append_full_vibrancy.css +290 -0
  68. package/client/web/src/assets/css/append/append_linux.css +125 -0
  69. package/client/web/src/assets/css/append/append_linux_vibrancy.css +22 -0
  70. package/client/web/src/assets/css/append/append_napcat.css +35 -0
  71. package/client/web/src/assets/css/append/append_new.css +843 -0
  72. package/client/web/src/assets/css/append/append_vibrancy.css +113 -0
  73. package/client/web/src/assets/css/append/append_win32.css +109 -0
  74. package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +349 -0
  75. package/client/web/src/assets/css/append/mobile/append_mobile_vertical.css +96 -0
  76. package/client/web/src/assets/css/chat.css +2104 -0
  77. package/client/web/src/assets/css/msg.css +941 -0
  78. package/client/web/src/assets/css/options.css +811 -0
  79. package/client/web/src/assets/css/sys_notice.css +62 -0
  80. package/client/web/src/assets/css/view.css +2105 -0
  81. package/client/web/src/assets/font//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223.ttf +0 -0
  82. package/client/web/src/assets/img/Vue.png +0 -0
  83. package/client/web/src/assets/img/cakes.svg +189 -0
  84. package/client/web/src/assets/img/icons/AppIcon.png +0 -0
  85. package/client/web/src/assets/img/icons/AppIconDark.png +0 -0
  86. package/client/web/src/assets/img/icons/CapacitorAppIcon.png +0 -0
  87. package/client/web/src/assets/img/icons/CapacitorAppIconDark.png +0 -0
  88. package/client/web/src/assets/img/icons/NapcatAppIcon.png +0 -0
  89. package/client/web/src/assets/img/icons/NapcatAppIconDark.png +0 -0
  90. package/client/web/src/assets/img/icons/exit.png +0 -0
  91. package/client/web/src/assets/img/icons/pen.png +0 -0
  92. package/client/web/src/assets/img/stars.svg +89 -0
  93. package/client/web/src/assets/img//346/234/237/345/276/205.png +0 -0
  94. package/client/web/src/assets/l10n/_About I10n.md +35 -0
  95. package/client/web/src/assets/l10n/_l10nconfig.json +7 -0
  96. package/client/web/src/assets/l10n/zh-CN.po +1941 -0
  97. package/client/web/src/assets/logo.png +0 -0
  98. package/client/web/src/assets/pathMap/LLOneBot.yaml +2 -0
  99. package/client/web/src/assets/pathMap/Lagrange.OneBot.yaml +180 -0
  100. package/client/web/src/assets/pathMap/NapCat.Onebot.yaml +224 -0
  101. package/client/web/src/assets/pathMap/SnowLuma.yaml +80 -0
  102. package/client/web/src/assets/qed.txt +1 -0
  103. package/client/web/src/components/AboutPan.vue +197 -0
  104. package/client/web/src/components/BulletinBody.vue +129 -0
  105. package/client/web/src/components/DepPan.vue +310 -0
  106. package/client/web/src/components/EmojiFace.vue +32 -0
  107. package/client/web/src/components/FacePan.vue +461 -0
  108. package/client/web/src/components/FileBody.vue +129 -0
  109. package/client/web/src/components/FileManager.vue +532 -0
  110. package/client/web/src/components/FriendBody.vue +54 -0
  111. package/client/web/src/components/GlobalSessionSearchBar.vue +301 -0
  112. package/client/web/src/components/History.vue +49 -0
  113. package/client/web/src/components/LazyLottie.vue +82 -0
  114. package/client/web/src/components/MergePan.vue +127 -0
  115. package/client/web/src/components/MsgBody.vue +1478 -0
  116. package/client/web/src/components/MusicPlayer.vue +549 -0
  117. package/client/web/src/components/NoticeBody.vue +168 -0
  118. package/client/web/src/components/QzonePermissionPan.vue +150 -0
  119. package/client/web/src/components/RawMsgRenderPreviewPan.vue +190 -0
  120. package/client/web/src/components/ThemeColorPickerPan.vue +420 -0
  121. package/client/web/src/components/TinySessionBody.vue +51 -0
  122. package/client/web/src/components/UmamiInfoPan.vue +1549 -0
  123. package/client/web/src/components/UpdatePan.vue +263 -0
  124. package/client/web/src/components/ViewerCom.vue +1360 -0
  125. package/client/web/src/components/VoiceMsg.vue +626 -0
  126. package/client/web/src/components/WelPan.vue +894 -0
  127. package/client/web/src/components/msg-body/.gitkeep +0 -0
  128. package/client/web/src/components/msg-component/JsonSegComp.vue +138 -0
  129. package/client/web/src/components/msg-component/XmlSegComp.vue +132 -0
  130. package/client/web/src/components/msg-component/jsonComp/AutoReply.vue +97 -0
  131. package/client/web/src/components/msg-component/jsonComp/Contact.lua.vue +129 -0
  132. package/client/web/src/components/msg-component/jsonComp/Feed.lua.vue +94 -0
  133. package/client/web/src/components/msg-component/jsonComp/Forum.vue +84 -0
  134. package/client/web/src/components/msg-component/jsonComp/Mannounce.vue +111 -0
  135. package/client/web/src/components/msg-component/jsonComp/Map.vue +52 -0
  136. package/client/web/src/components/msg-component/jsonComp/Miniapp.lua.vue +53 -0
  137. package/client/web/src/components/msg-component/jsonComp/Miniapp.vue +69 -0
  138. package/client/web/src/components/msg-component/jsonComp/Music.lua.vue +135 -0
  139. package/client/web/src/components/msg-component/jsonComp/Tuwen.lua.vue +56 -0
  140. package/client/web/src/components/notice-component/.gitkeep +0 -0
  141. package/client/web/src/components/notice-component/MealHungryPan.vue +119 -0
  142. package/client/web/src/components/tooltip/CustomFaceTooltip.vue +22 -0
  143. package/client/web/src/components/tooltip/Tooltip.vue +50 -0
  144. package/client/web/src/components/tooltip/Tooltips.vue +14 -0
  145. package/client/web/src/components/tooltip/UserInfoTooltip.vue +69 -0
  146. package/client/web/src/function/base.ts +238 -0
  147. package/client/web/src/function/connect.ts +2042 -0
  148. package/client/web/src/function/debug.ts +10 -0
  149. package/client/web/src/function/elements/information.ts +141 -0
  150. package/client/web/src/function/elements/system.ts +101 -0
  151. package/client/web/src/function/elements/vueComp.ts +62 -0
  152. package/client/web/src/function/favicon.ts +76 -0
  153. package/client/web/src/function/input.ts +69 -0
  154. package/client/web/src/function/model/emoji.ts +127 -0
  155. package/client/web/src/function/model/img.ts +150 -0
  156. package/client/web/src/function/model/msg-body.ts +51 -0
  157. package/client/web/src/function/msg.ts +2674 -0
  158. package/client/web/src/function/notify.ts +225 -0
  159. package/client/web/src/function/option.ts +749 -0
  160. package/client/web/src/function/satori-model.ts +818 -0
  161. package/client/web/src/function/satori.ts +325 -0
  162. package/client/web/src/function/sender.ts +178 -0
  163. package/client/web/src/function/tooltip.ts +49 -0
  164. package/client/web/src/function/utils/appUtil.ts +2288 -0
  165. package/client/web/src/function/utils/avatarUtil.ts +31 -0
  166. package/client/web/src/function/utils/backgroundUtil.ts +110 -0
  167. package/client/web/src/function/utils/linkViewUtil.ts +101 -0
  168. package/client/web/src/function/utils/localHistoryUtil.ts +517 -0
  169. package/client/web/src/function/utils/msgUtil.ts +1242 -0
  170. package/client/web/src/function/utils/pinyin.ts +141 -0
  171. package/client/web/src/function/utils/recordUtil.ts +187 -0
  172. package/client/web/src/function/utils/sessionUtil.ts +114 -0
  173. package/client/web/src/function/utils/systemUtil.ts +664 -0
  174. package/client/web/src/main.ts +91 -0
  175. package/client/web/src/pages/Chat.vue +3453 -0
  176. package/client/web/src/pages/Friends.vue +636 -0
  177. package/client/web/src/pages/Info.vue +717 -0
  178. package/client/web/src/pages/Messages.vue +875 -0
  179. package/client/web/src/pages/Options.vue +82 -0
  180. package/client/web/src/pages/Qzone.vue +1178 -0
  181. package/client/web/src/pages/chat-view/ChatDanmaku.vue +759 -0
  182. package/client/web/src/pages/chat-view/ChatGlagame.vue +642 -0
  183. package/client/web/src/pages/chat-view/ChatTerminal.vue +1044 -0
  184. package/client/web/src/pages/chat-view/SystemNotice.vue +171 -0
  185. package/client/web/src/pages/options/OptAccount.vue +107 -0
  186. package/client/web/src/pages/options/OptAddon.vue +185 -0
  187. package/client/web/src/pages/options/OptDev.vue +704 -0
  188. package/client/web/src/pages/options/OptFunction.vue +403 -0
  189. package/client/web/src/pages/options/OptInfo.vue +165 -0
  190. package/client/web/src/pages/options/OptView.vue +846 -0
  191. package/client/web/src/runtime/backend.ts +310 -0
  192. package/client/web/src/state/auth.ts +14 -0
  193. package/client/web/src/state/chat.ts +36 -0
  194. package/client/web/src/state/connection.ts +20 -0
  195. package/client/web/src/state/contact.ts +37 -0
  196. package/client/web/src/state/qzone.ts +18 -0
  197. package/client/web/src/state/sessionHistory.ts +25 -0
  198. package/client/web/src/state/settings.ts +18 -0
  199. package/client/web/src/state/sticker.ts +10 -0
  200. package/client/web/src/state/ui.ts +56 -0
  201. package/client/web/tsconfig.json +27 -0
  202. package/client/web/tsconfig.tsbuildinfo +1 -0
  203. package/client/web/vite.config.ts +33 -0
  204. package/dist/index.js +1 -12
  205. package/dist/style.css +1 -1
  206. package/lib/index.js +2070 -2077
  207. package/package.json +15 -2
  208. package/readme.md +0 -22
  209. package/src/bootstrap.ts +71 -0
  210. package/src/cache.ts +319 -0
  211. package/src/config.ts +23 -35
  212. package/src/database.ts +650 -0
  213. package/src/index.ts +27 -59
  214. package/src/media.ts +302 -0
  215. package/src/recorder.ts +175 -0
  216. package/src/self-message.ts +456 -0
  217. package/src/server.d.ts +26 -0
  218. package/src/types.ts +108 -48
  219. package/src/web.ts +712 -0
  220. package/client/vue/chat-logic.ts +0 -683
  221. package/client/vue/composables/useChatActions.ts +0 -61
  222. package/client/vue/composables/useChatData.ts +0 -185
  223. package/client/vue/composables/useImageCache.ts +0 -281
  224. package/client/vue/composables/useVideoCache.ts +0 -125
  225. package/client/vue/types.ts +0 -72
  226. package/lib/api-handlers.d.ts +0 -25
  227. package/lib/config.d.ts +0 -14
  228. package/lib/file-manager.d.ts +0 -124
  229. package/lib/index.d.ts +0 -17
  230. package/lib/logger.d.ts +0 -9
  231. package/lib/message-handler.d.ts +0 -35
  232. package/lib/types.d.ts +0 -57
  233. package/lib/utils.d.ts +0 -18
  234. package/src/api-handlers.ts +0 -646
  235. package/src/file-manager.ts +0 -1436
  236. package/src/message-handler.ts +0 -507
  237. package/src/utils.ts +0 -189
@@ -0,0 +1,1044 @@
1
+ <!--
2
+ * @FileDescription: 聊天面板页面(命令行样式)
3
+ * @Author: Stapxs
4
+ * @Date: 2023/01/11
5
+ * @Version: 1.0 - 初始版本
6
+ * @Description: 这是个命令行样式的聊天面板,摸鱼专用.gif
7
+ -->
8
+
9
+ <!--
10
+ 追加备注
11
+ 此界面主题不支持以下功能:
12
+ - 图片预览器,这玩意虽然说是全局的,但是太突兀了(无端)
13
+ -->
14
+
15
+ <template>
16
+ <div
17
+ id="chat-pan"
18
+ :class="'chat-pan' + (uiStore.openSideBar ? ' open' : '') + (['linux', 'win32'].includes(backend.platform ?? '') ? ' withBar' : '') ">
19
+ <span v-if="tags.fullscreen" class="shell-pan-title">admin@{{ endpointHost }}:/Volumes/Contacts/{{ chatStore.chatInfo.show.id }}</span>
20
+ <div id="shell-pan" class="shell-pan">
21
+ <div>
22
+ <template
23
+ v-for="(msgItem, index) in chatStore.messageList"
24
+ :key="msgItem.message_id">
25
+ <div
26
+ v-if="msgItem.post_type == 'message'
27
+ || msgItem.post_type == 'message_sent'"
28
+ :class="
29
+ 'shell-msg' +
30
+ (msgItem.revoke ? ' revoke' : '') +
31
+ (tags.replyId == msgItem.message_id ? ' reply' : '')
32
+ "
33
+ style="cursor: pointer">
34
+ <span
35
+ :class="
36
+ 'sname s' +
37
+ msgItem.sender.role +
38
+ (authStore.loginInfo.uin == msgItem.sender.user_id
39
+ ? ' smine'
40
+ : '')
41
+ "
42
+ @click="copy(msgItem.sender.user_id)">
43
+ {{
44
+ msgItem.sender.card
45
+ ? msgItem.sender.card
46
+ : msgItem.sender.nickname
47
+ }}{{ hasReply(msg) ?? ''
48
+ }}{{
49
+ msgItem.sub_type == 'friend'
50
+ ? authStore.loginInfo.uin ==
51
+ msgItem.sender.user_id
52
+ ? authStore.loginInfo.nickname
53
+ : chatStore.chatInfo.show.name
54
+ : ''
55
+ }}{{ msgItem.sender.user_id == 0 ? '' : ': ' }}
56
+ </span>
57
+ <span
58
+ class="smsg"
59
+ @click="copy(msgItem.message_id)">{{
60
+ getMsgRawTxt(msgItem)
61
+ }}</span>
62
+ <br>
63
+ </div>
64
+ <div v-else-if="msgItem.post_type == 'notice'">
65
+ <span
66
+ v-if="msgItem.sub_type == 'recall'"
67
+ style="color: yellow">::
68
+ <span style="color: yellow; opacity: 0.7">{{
69
+ getRecallName(msgItem.operator_id)
70
+ }}</span>
71
+ recalled a message.</span>
72
+ </div>
73
+ <div v-else-if="msgItem.commandLine">
74
+ <div
75
+ v-if="index == 2"
76
+ class="line-head">
77
+ <div>
78
+ <span>
79
+ <font-awesome-icon
80
+ :icon="['fas', 'folder-open']" />
81
+ {{ chatStore.chatInfo.show.name }}
82
+ </span>
83
+ <span style="color: var(--color-main-0)">
84
+ <font-awesome-icon
85
+ :icon="['fas', 'plug']" />
86
+ {{ endpointName }}
87
+ </span>
88
+ </div>
89
+ <div style="flex: 1" />
90
+ <div>
91
+ <span style="color: var(--color-main-1)">
92
+ {{ packageInfo.version
93
+ }}<font-awesome-icon
94
+ :icon="['fas', 'code-branch']" />
95
+ </span>
96
+ <span>
97
+ {{ msgItem.time.time
98
+ }}<font-awesome-icon
99
+ :icon="['fas', 'clock']" />
100
+ </span>
101
+ </div>
102
+ </div>
103
+ <a class="command-start">• </a>
104
+ <span>{{ msgItem.str }}</span>
105
+ </div>
106
+ <div v-else-if="msgItem.commandOut">
107
+ <div
108
+ v-if="msgItem.html"
109
+ v-html="msgItem.html" />
110
+ <span v-else :style="{ 'color': msgItem.color }">
111
+ {{ msgItem.str }}
112
+ </span>
113
+ </div>
114
+ </template>
115
+ </div>
116
+ <div class="shell-input">
117
+ <div class="line-head">
118
+ <div>
119
+ <span>
120
+ <font-awesome-icon
121
+ :icon="['fas', 'folder-open']" />
122
+ {{ chatStore.chatInfo.show.name }}
123
+ {{ tags.replyName ? ' -> ' + tags.replyName : '' }}
124
+ </span>
125
+ <span style="color: var(--color-main-0)">
126
+ <font-awesome-icon :icon="['fas', 'plug']" />{{
127
+ endpointName
128
+ }}
129
+ </span>
130
+ </div>
131
+ <div style="flex: 1" />
132
+ <div>
133
+ <span
134
+ v-if="tags.newMsg > 0"
135
+ style="color: var(--color-main-2)">
136
+ {{ tags.newMsg
137
+ }}<font-awesome-icon :icon="['fas', 'envelope']" />
138
+ </span>
139
+ <span style="color: var(--color-main-1)">
140
+ {{ packageInfo.version
141
+ }}<font-awesome-icon
142
+ :icon="['fas', 'code-branch']" />
143
+ </span>
144
+ <span>
145
+ {{ timeShow
146
+ }}<font-awesome-icon :icon="['fas', 'clock']" />
147
+ </span>
148
+ </div>
149
+ </div>
150
+ <a class="command-start">• </a>
151
+ <label for="shell-msg-input" class="sr-only">{{ $t('命令行消息输入框') }}</label>
152
+ <input
153
+ id="shell-msg-input"
154
+ v-model="msg"
155
+ @keyup="sendMsg"
156
+ @paste="addImg">
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </template>
161
+
162
+ <script lang="ts" setup>
163
+ import app, { i18n, uptime } from '../../main'
164
+ import SendUtil from '../../function/sender'
165
+ import packageInfo from '../../../package.json'
166
+
167
+ import { computed, nextTick, ref, watch, onMounted, onUnmounted, markRaw } from 'vue'
168
+ import { Connector, login as loginInfo } from '../../function/connect'
169
+ import { getTrueLang } from '../../function/utils/systemUtil'
170
+ import {
171
+ MsgItemElem,
172
+ SQCodeElem,
173
+ UserFriendElem,
174
+ UserGroupElem,
175
+ } from '../../function/elements/information'
176
+ import {
177
+ Logger,
178
+ LogType,
179
+ PopInfo,
180
+ popList,
181
+ PopType,
182
+ } from '../../function/base'
183
+ import { sendMsgRaw, getMsgRawTxt, getShowName } from '../../function/utils/msgUtil'
184
+ import { backend } from '../../runtime/backend'
185
+ import { useUIStore } from '../../state/ui'
186
+ import { useAuthStore } from '../../state/auth'
187
+ import { useContactStore } from '../../state/contact'
188
+ import { useChatStore } from '../../state/chat'
189
+
190
+ defineOptions({ name: 'ChatShell' })
191
+
192
+ const uiStore = useUIStore()
193
+ const authStore = useAuthStore()
194
+ const contactStore = useContactStore()
195
+ const chatStore = useChatStore()
196
+ const $t = i18n.global.t
197
+ const endpointName = computed(() => loginInfo.address || '/satori')
198
+ const endpointHost = computed(() => {
199
+ try {
200
+ return new URL(endpointName.value, window.location.origin).hostname
201
+ } catch {
202
+ return window.location.hostname
203
+ }
204
+ })
205
+
206
+ const { chat, list } = defineProps<{
207
+ chat: any
208
+ list: any
209
+ mumberInfo: any
210
+ }>()
211
+
212
+ // --- data ---
213
+ const tags = ref({
214
+ fullscreen: false,
215
+ fistget: true,
216
+ cmdTags: {} as { [key: string]: any },
217
+ newMsg: 0,
218
+ replyName: null as string | null,
219
+ replyId: null as string | null,
220
+ })
221
+ const trueLang = getTrueLang()
222
+ const timeShow = ref('')
223
+ let timeSetter: ReturnType<typeof setInterval> | undefined = undefined
224
+ const msg = ref('')
225
+ const supportCmd = ref<{ [key: string]: any }>({})
226
+ const imgCache = ref<string[]>([])
227
+ const sendCache = ref<MsgItemElem[]>([])
228
+ const searchListCache = ref<(UserFriendElem & UserGroupElem)[]>([])
229
+
230
+ // --- watchers ---
231
+ watch(() => chat, () => {
232
+ tags.value.fistget = true
233
+ tags.value.cmdTags = {}
234
+ })
235
+
236
+ // --- methods ---
237
+ function hasReply(msg: any) {
238
+ if (msg.message) {
239
+ const repItem = msg.message.filter((item: any) => {
240
+ return item.type == 'reply'
241
+ })
242
+ if (repItem[0]) {
243
+ const repMsg = chatStore.messageList.filter(
244
+ (item) => {
245
+ return item.message_id == repItem[0].id
246
+ },
247
+ )
248
+ if (repMsg[0]) {
249
+ return (
250
+ '->' +
251
+ (repMsg[0].sender.card? repMsg[0].sender.card: repMsg[0].sender.nickname)
252
+ )
253
+ }
254
+ }
255
+ }
256
+ return null
257
+ }
258
+
259
+ /**
260
+ * 消息区滚动到指定位置
261
+ * @param where 位置(px)
262
+ * @param showAnimation 是否使用动画
263
+ */
264
+ function scrollTo(where: number | undefined, showAnimation = true) {
265
+ const pan = document.getElementById('shell-pan')
266
+ if (pan !== null && where) {
267
+ if (showAnimation === false) {
268
+ pan.style.scrollBehavior = 'unset'
269
+ } else {
270
+ pan.style.scrollBehavior = 'smooth'
271
+ }
272
+ pan.scrollTop = where
273
+ pan.style.scrollBehavior = 'smooth'
274
+ }
275
+ }
276
+
277
+ function scrollBottom(showAnimation = false) {
278
+ const pan = document.getElementById('shell-pan')
279
+ if (pan !== null) {
280
+ scrollTo(pan.scrollHeight + 40, showAnimation)
281
+ }
282
+ }
283
+
284
+ function updateList(_: number, oldLength: number) {
285
+ if (tags.value.fistget && oldLength == 0) {
286
+ tags.value.fistget = false
287
+ addCommandOutF(':: joining chat ..', 'yellow')
288
+ addCommandLineF(
289
+ 'screen ' + chatStore.chatInfo.show.id,
290
+ chatStore.chatInfo.show.type,
291
+ )
292
+ addCommandLineF('[screen is terminating]')
293
+ addCommandOutF(
294
+ '* Stapxs QQ Lite Shell requires "FiraCode Nerd Font" to display complete command line symbols, please ensure the device has installed this font.\n\n* Use the command "fullscreen" or return to the parent directory to exit the full screen mode.\n\n* 使用 "help" 命令查看所有可用命令。\n\n\n',
295
+ 'var(--color-font)',
296
+ )
297
+ addCommandOutF(
298
+ ` => 当前存在 ${contactStore.onMsgList.length} 个活跃会话\n\n`,
299
+ 'var(--color-font)',
300
+ )
301
+ addCommandOutF(
302
+ `Welcome to Koishi Satori Chat ${packageInfo.version} (Vue ${packageInfo.dependencies.vue}-${import.meta.env.DEV ? 'development' : 'production'})\n\n`,
303
+ 'var(--color-font)',
304
+ )
305
+ }
306
+ scrollBottom(true)
307
+ }
308
+
309
+ function showPop(newLength: number, oldLength: number) {
310
+ if (newLength > oldLength) {
311
+ const info = popList[popList.length - 1]
312
+ if (info.svg == PopType.ERR) {
313
+ addCommandOut('::' + info.text, 'red')
314
+ } else {
315
+ addCommandOut('::' + info.text, 'yellow')
316
+ }
317
+ }
318
+ }
319
+
320
+ function addCommandOut(
321
+ raw: string,
322
+ color = 'var(--color-font-2)',
323
+ html = undefined as unknown,
324
+ ) {
325
+ chatStore.messageList.push({
326
+ commandOut: true,
327
+ color: color,
328
+ str: raw,
329
+ html: html,
330
+ })
331
+ }
332
+
333
+ function addCommandOutF(
334
+ raw: string,
335
+ color = 'var(--color-font-2)',
336
+ html = undefined as unknown,
337
+ ) {
338
+ chatStore.messageList.unshift({
339
+ commandOut: true,
340
+ color: color,
341
+ str: raw,
342
+ html: html,
343
+ })
344
+ }
345
+
346
+ function addCommandLine(
347
+ str: string,
348
+ dir = chatStore.chatInfo.show.name,
349
+ appendData: { [key: string]: any } = {},
350
+ ) {
351
+ chatStore.messageList.push({
352
+ dir: dir,
353
+ commandLine: true,
354
+ str: str,
355
+ time: markRaw({
356
+ time: Intl.DateTimeFormat(getTrueLang(), {
357
+ hour: 'numeric',
358
+ minute: 'numeric',
359
+ second: 'numeric',
360
+ }).format(new Date()),
361
+ }),
362
+ data: appendData,
363
+ })
364
+ }
365
+
366
+ function addCommandLineF(str: string, dir = chatStore.chatInfo.show.name) {
367
+ chatStore.messageList.unshift({
368
+ dir: dir,
369
+ commandLine: true,
370
+ str: str,
371
+ time: markRaw({
372
+ time: Intl.DateTimeFormat(getTrueLang(), {
373
+ hour: 'numeric',
374
+ minute: 'numeric',
375
+ second: 'numeric',
376
+ }).format(new Date()),
377
+ }),
378
+ data: {},
379
+ })
380
+ }
381
+
382
+ function sendMsg(event: KeyboardEvent) {
383
+ // 执行指令
384
+ if (event.keyCode === 13) {
385
+ addCommandLine(
386
+ msg.value,
387
+ chatStore.chatInfo.show.name,
388
+ tags.value.cmdTags,
389
+ )
390
+ if (msg.value == '') return
391
+
392
+ // 检查是否是支持的指令
393
+ let currentMsg = msg.value
394
+ if (currentMsg[0] == '/') {
395
+ currentMsg =
396
+ 'ssqq send ' + currentMsg.substring(1, currentMsg.length)
397
+ }
398
+ const msgList = currentMsg.split(' ')
399
+ new Logger().add(
400
+ LogType.DEBUG,
401
+ 'CMD: ' + msgList.toString(),
402
+ )
403
+ if (msgList.length > 0 && supportCmd.value[msgList[0]]) {
404
+ supportCmd.value[msgList[0]].fun(currentMsg, msgList)
405
+ msg.value = ''
406
+ } else {
407
+ addCommandOut(
408
+ 'stsh: command not found, use the help command to view all available commands.',
409
+ 'red',
410
+ )
411
+ }
412
+ // 发送后处理
413
+ tags.value.cmdTags = {}
414
+ if (
415
+ sendCache.value.filter((item) => {
416
+ return item.type === 'reply'
417
+ }).length > 0
418
+ ) {
419
+ tags.value.cmdTags.reply = true
420
+ }
421
+ }
422
+ // 发送后等 DOM 更新再滚动,避免固定延迟
423
+ nextTick(() => {
424
+ scrollBottom()
425
+ requestAnimationFrame(() => scrollBottom())
426
+ })
427
+ }
428
+
429
+ function copy(str: string) {
430
+ const input = document.getElementById('msgInput')
431
+ if (input) {
432
+ msg.value = 'ssqq reply ' + str + ' '
433
+ input.focus()
434
+ }
435
+ app.config.globalProperties.$copyText(String(str)).then(
436
+ () => {
437
+ addCommandOut(
438
+ ':: Copy messageId successfully.',
439
+ 'gray',
440
+ )
441
+ },
442
+ () => {
443
+ addCommandOut(':: Copy messageId failed.', 'gray')
444
+ },
445
+ )
446
+ }
447
+
448
+ /**
449
+ * 添加特殊消息结构
450
+ * @param data obj
451
+ */
452
+ function addSpecialMsg(data: SQCodeElem) {
453
+ if (data !== undefined) {
454
+ const index = sendCache.value.length
455
+ sendCache.value.push(data.msgObj)
456
+ if (data.addText === true) {
457
+ const token = data.msgObj?.type === 'image' ? '[图片]' : '[SQ:' + index + ']'
458
+ if (data.addTop === true) {
459
+ msg.value = token + msg.value
460
+ } else {
461
+ msg.value += token
462
+ }
463
+ }
464
+ return index
465
+ }
466
+ return -1
467
+ }
468
+
469
+ function getRecallName(id: number) {
470
+ let backName = id.toString()
471
+ // 补全撤回者信息
472
+ if (chatStore.chatInfo.show.type === 'group') {
473
+ // 寻找群成员信息
474
+ if (chatStore.chatInfo.info.group_members !== undefined) {
475
+ const back =
476
+ chatStore.chatInfo.info.group_members.filter(
477
+ (item) => {
478
+ return item.user_id === Number(id)
479
+ },
480
+ )
481
+ if (back.length === 1) {
482
+ backName =
483
+ back[0].card === ''? back[0].nickname: back[0].card
484
+ }
485
+ }
486
+ } else {
487
+ backName = chatStore.chatInfo.show.name
488
+ }
489
+ return backName
490
+ }
491
+
492
+ function addImg(event: ClipboardEvent) {
493
+ // 判断粘贴类型
494
+ if (!(event.clipboardData && event.clipboardData.items)) {
495
+ return
496
+ }
497
+ for (
498
+ let i = 0, len = event.clipboardData.items.length;
499
+ i < len;
500
+ i++
501
+ ) {
502
+ const item = event.clipboardData.items[i]
503
+ if (item.kind === 'file') {
504
+ setImg(item.getAsFile())
505
+ // 阻止默认行为
506
+ event.preventDefault()
507
+ }
508
+ }
509
+ }
510
+
511
+ function setImg(blob: File | null) {
512
+ const popInfoLocal = new PopInfo()
513
+ if (
514
+ blob !== null &&
515
+ blob.type.indexOf('image/') >= 0 &&
516
+ blob.size !== 0
517
+ ) {
518
+ if (blob.size < 3145728) {
519
+ // 转换为 Base64
520
+ const reader = new FileReader()
521
+ reader.readAsDataURL(blob)
522
+ reader.onloadend = () => {
523
+ const base64data = reader.result as string
524
+ if (base64data !== null) {
525
+ // 记录图片信息
526
+ // 只要你内存够猛,随便 cache 图片,这边就不做限制了
527
+ imgCache.value.push(base64data)
528
+ }
529
+ }
530
+ } else {
531
+ popInfoLocal.add(PopType.INFO, $t('图片过大'))
532
+ }
533
+ }
534
+ }
535
+
536
+ // --- mounted ---
537
+ onMounted(() => {
538
+ supportCmd.value = {
539
+ help: {
540
+ info: 'Show All Command.',
541
+ fun: () => {
542
+ let back = ''
543
+ Object.keys(supportCmd.value).forEach((name) => {
544
+ if (name != '')
545
+ back +=
546
+ '<span style="color: var(--color-font-2);"><span style="width: 13ch;display: inline-block;">' +
547
+ name +
548
+ '</span>: ' +
549
+ supportCmd.value[name].info +
550
+ '</span><br>'
551
+ })
552
+ addCommandOut('', '', back)
553
+ },
554
+ },
555
+ ls: {
556
+ info: 'List all contacts in the current message queue.',
557
+ fun: () => {
558
+ searchListCache.value = [...contactStore.onMsgList.values()]
559
+ let str =
560
+ ' total ' + searchListCache.value.length + '\n'
561
+ let hasMsg = false
562
+ Array.from(contactStore.onMsgList).forEach((item, index) => {
563
+ if (item.new_msg == true) {
564
+ str += '• '
565
+ hasMsg = true
566
+ } else str += ' '
567
+ str += ('#' + index.toString()).padEnd(8, ' ')
568
+ str += (item.group_id ? item.group_id : item.user_id).toString().padEnd(20, ' ')
569
+ str += getShowName(item.group_name || item.nickname, item.remark)
570
+ str += '\n'
571
+ })
572
+ if (hasMsg)
573
+ addCommandOut(':: You have message.', 'yellow')
574
+ addCommandOut(str)
575
+ },
576
+ },
577
+ ssqq: {
578
+ info: 'Stapxs QQ Lite Base Command.',
579
+ fun: (raw: string, item: string[]) => {
580
+ switch (item[1]) {
581
+ // 发送消息
582
+ case 'send': {
583
+ const rawMsg = raw.substring(
584
+ raw.indexOf('send') + 5,
585
+ )
586
+ const parsedMsg = SendUtil.parseMsg(
587
+ rawMsg,
588
+ sendCache.value,
589
+ imgCache.value,
590
+ )
591
+ if (chat.show.temp) {
592
+ sendMsgRaw(
593
+ chat.show.id +
594
+ '/' +
595
+ chat.show.temp,
596
+ chat.show.type,
597
+ parsedMsg,
598
+ )
599
+ } else {
600
+ sendMsgRaw(
601
+ chat.show.id,
602
+ chat.show.type,
603
+ parsedMsg,
604
+ )
605
+ }
606
+ // 发送后处理
607
+ sendCache.value = []
608
+ imgCache.value = []
609
+
610
+ tags.value.replyName = null
611
+ tags.value.replyId = null
612
+ break
613
+ }
614
+ // 寻找联系人
615
+ case 'list': {
616
+ const value = item[2]
617
+ searchListCache.value =
618
+ contactStore.userList.filter(
619
+ (
620
+ item: UserFriendElem &
621
+ UserGroupElem,
622
+ ) => {
623
+ const name = (
624
+ item.user_id? item.nickname +
625
+ item.remark: item.group_name
626
+ ).toLowerCase()
627
+ const id = item.user_id? item.user_id: item.group_id
628
+ return (
629
+ name.indexOf(
630
+ value.toLowerCase(),
631
+ ) !== -1 ||
632
+ id.toString() === value
633
+ )
634
+ },
635
+ ) as (UserFriendElem & UserGroupElem)[]
636
+ let str =
637
+ ' total ' +
638
+ searchListCache.value.length +
639
+ '\n'
640
+ searchListCache.value.forEach((item, index) => {
641
+ str += ('#' + index.toString()).padEnd(8, ' ')
642
+ str += (item.group_id ? item.group_id : item.user_id).toString().padEnd(20, ' ')
643
+ str += getShowName(item.group_name || item.nickname, item.remark)
644
+ str += '\n'
645
+ })
646
+ addCommandOut(str)
647
+ break
648
+ }
649
+ // 回复消息
650
+ case 'reply': {
651
+ // 去除回复消息缓存
652
+ sendCache.value = sendCache.value.filter(
653
+ (item) => {
654
+ return item.type !== 'reply'
655
+ },
656
+ )
657
+ if (item[2] && item[2] != 'clear') {
658
+ // 根据 item[2] 寻找这条消息 的名字
659
+ const replyMsg = chatStore.messageList.filter(
660
+ (msg) => {
661
+ return msg.message_id == item[2]
662
+ },
663
+ )
664
+ tags.value.replyId = item[2]
665
+ if (replyMsg[0]) {
666
+ tags.value.replyName = replyMsg[0].sender.card? replyMsg[0].sender.card: replyMsg[0].sender.nickname
667
+ }
668
+ addSpecialMsg({
669
+ msgObj: { type: 'reply', id: item[2] },
670
+ addText: false,
671
+ addTop: true,
672
+ })
673
+ } else if (item[2] && item[2] == 'clear') {
674
+ sendCache.value = sendCache.value.filter(
675
+ (item) => {
676
+ return item.type !== 'reply'
677
+ },
678
+ )
679
+ tags.value.replyName = null
680
+ tags.value.replyId = null
681
+ }
682
+ if (item[3]) {
683
+ supportCmd.value['ssqq'].fun(
684
+ 'ssqq send ' + item[3],
685
+ ['ssqq', 'send', item[3]],
686
+ )
687
+ msg.value = ''
688
+ }
689
+ break
690
+ }
691
+ // 加载历史记录
692
+ case 'history': {
693
+ // 移除顶部的首次加载提示
694
+ if (chatStore.messageList[0].commandOut) {
695
+ chatStore.messageList.shift()
696
+ chatStore.messageList.shift()
697
+ chatStore.messageList.shift()
698
+ chatStore.messageList.shift()
699
+ }
700
+ // 加载历史消息
701
+ // 获取列表第一条消息 ID
702
+ const firstMsgId =
703
+ chatStore.messageList[0].message_id ?? 0
704
+ // 发起获取历史消息请求
705
+ const type = chatStore.chatInfo.show.type
706
+ const id = chatStore.chatInfo.show.id
707
+ let name
708
+ const fullPage =
709
+ authStore.jsonMap.message_list
710
+ ?.pagerType == 'full'
711
+ if (
712
+ authStore.jsonMap.message_list &&
713
+ type != 'group'
714
+ ) {
715
+ name =
716
+ authStore.jsonMap.message_list
717
+ .private_name
718
+ } else {
719
+ name = authStore.jsonMap.message_list.name
720
+ }
721
+ Connector.send(
722
+ name ?? 'get_chat_history',
723
+ {
724
+ group_id:
725
+ type == 'group' ? id : undefined,
726
+ user_id:
727
+ type != 'group' ? id : undefined,
728
+ message_id: firstMsgId,
729
+ count: fullPage? chatStore.messageList.length +
730
+ 20: 20,
731
+ },
732
+ 'getChatHistory',
733
+ )
734
+ break
735
+ }
736
+ default: {
737
+ addCommandOut(
738
+ 'usage: ssqq send [msg]: Send a message, you can directly use "/<Message>" to replace it, \n list [search]: Fuzzy search in the list of friends/groups, \n reply [msgId] <message>: Use the message id to reply to the message, Click the message to copy the id, \n history: Load more history.',
739
+ )
740
+ }
741
+ }
742
+ },
743
+ },
744
+ fullscreen: {
745
+ info: 'fullscreen chat view.',
746
+ fun: () => {
747
+ const pan = document.getElementById('chat-pan')
748
+ if (pan) {
749
+ if (!tags.value.fullscreen) {
750
+ tags.value.fullscreen = true
751
+ pan.classList.add('full')
752
+ } else {
753
+ tags.value.fullscreen = false
754
+ pan.classList.remove('full')
755
+ }
756
+ }
757
+ },
758
+ },
759
+ fastfetch: {
760
+ info: 'print system info.',
761
+ fun: () => {
762
+ const infoList = {
763
+ Application: 'Koishi Satori Chat',
764
+ Kernel: packageInfo.version + '-' + backend.type,
765
+ Shell: 'stsh Basic Shell 1.0',
766
+ Theme: 'ChatSHell',
767
+ Uptime:
768
+ Math.floor(
769
+ ((new Date().getTime() - uptime) / 1000) *
770
+ 100,
771
+ ) /
772
+ 100 +
773
+ ' s',
774
+ Resolution:
775
+ window.screen.width +
776
+ 'x' +
777
+ window.screen.height,
778
+ } as { [key: string]: string }
779
+ let info = ''
780
+ Object.keys(infoList).forEach((key) => {
781
+ info += `<span>${key}<span>: ${infoList[key]}</span></span>`
782
+ })
783
+ addCommandOut(
784
+ '',
785
+ '',
786
+ `<div class="shell-fastfetch"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;***&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*******************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;***************************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*******************************&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;**************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**************&nbsp;&nbsp;<br>&nbsp;&nbsp;*************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*************&nbsp;<br>&nbsp;**************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*************<br>&nbsp;*************,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*************<br>*************,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;************<br>&nbsp;************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;***********<br>&nbsp;***********,**&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*.***********<br>&nbsp;&nbsp;*************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*************&nbsp;<br>&nbsp;&nbsp;&nbsp;***********************************&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*******************************&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;***************************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*******************<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;***</span><div><span>${authStore.loginInfo.nickname}<span>@</span>ssqq-vue</span><a>-----------------</a>${info}<div><div style="background:black"></div><div style="background:red"></div><div style="background:green"></div><div style="background:yellow"></div><div style="background:blue"></div><div style="background:violet"></div></div></div></div>`,
787
+ )
788
+ },
789
+ },
790
+ clear: {
791
+ info: 'clear message list.',
792
+ fun: () => {
793
+ chatStore.messageList = []
794
+ // PS:让消息列表不是空的防止输出首次进入信息
795
+ addCommandOut('')
796
+ },
797
+ },
798
+ screen: {
799
+ info: 'Switch to a specified contact chat.',
800
+ fun: (_: string, itemInfo: string[]) => {
801
+ let id = '0'
802
+ if (
803
+ itemInfo.length == 1 &&
804
+ searchListCache.value.length == 1
805
+ ) {
806
+ id = (
807
+ searchListCache.value[0].user_id? searchListCache.value[0].user_id: searchListCache.value[0].group_id
808
+ ).toString()
809
+ } else {
810
+ id = itemInfo[1]
811
+ if (itemInfo[1] == '../') {
812
+ const pan = document.getElementById('chat-pan')
813
+ if (pan) {
814
+ tags.value.fullscreen = false
815
+ pan.classList.remove('full')
816
+ chatStore.chatInfo.show.id = 0
817
+ }
818
+ return
819
+ }
820
+ if (itemInfo[1].startsWith('#')) {
821
+ const index = Number(itemInfo[1].substring(1))
822
+ if (searchListCache.value[index]) {
823
+ id = (
824
+ searchListCache.value[index].user_id? searchListCache.value[index]
825
+ .user_id: searchListCache.value[index]
826
+ .group_id
827
+ ).toString()
828
+ } else {
829
+ addCommandOut(
830
+ ':: Search cache id does not exist',
831
+ 'red',
832
+ )
833
+ return
834
+ }
835
+ }
836
+ }
837
+ // 从缓存列表里寻找这个 ID
838
+ for (let i = 0; i < contactStore.userList.length; i++) {
839
+ const item = contactStore.userList[i]
840
+ const gid =
841
+ item.user_id !== undefined? item.user_id: item.group_id
842
+ if (String(gid) === id) {
843
+ // 检查显示列表里有没有它
844
+ if (!document.getElementById('user-' + id)) {
845
+ // 把它插入到显示列表
846
+ contactStore.baseOnMsgList?.set(id, item)
847
+ }
848
+ nextTick(() => {
849
+ const bodyNext = document.getElementById(
850
+ 'user-' + id,
851
+ )
852
+ if (bodyNext !== null) {
853
+ // 然后点一下它触发聊天框切换
854
+ bodyNext.click()
855
+ } else {
856
+ addCommandOut(
857
+ ':: No valid contacts found',
858
+ 'red',
859
+ )
860
+ }
861
+ })
862
+ return
863
+ }
864
+ }
865
+ addCommandOut(':: No valid contacts found', 'red')
866
+
867
+ tags.value.replyName = null
868
+ tags.value.replyId = null
869
+ },
870
+ },
871
+ }
872
+
873
+ watch(() => list.length, updateList)
874
+ watch(() => popList.length, showPop)
875
+ timeSetter = setInterval(() => {
876
+ timeShow.value = Intl.DateTimeFormat(trueLang, {
877
+ hour: 'numeric',
878
+ minute: 'numeric',
879
+ second: 'numeric',
880
+ }).format(new Date())
881
+ // 刷新新消息数
882
+ tags.value.newMsg = [...contactStore.onMsgList.values()].filter((item) => {
883
+ return item.new_msg == true
884
+ }).length
885
+ }, 1000)
886
+ const pan = document.getElementById('chat-pan')
887
+ if (pan) {
888
+ tags.value.fullscreen = true
889
+ pan.classList.add('full')
890
+ }
891
+ })
892
+
893
+ onUnmounted(() => {
894
+ if (timeSetter) {
895
+ clearInterval(timeSetter)
896
+ timeSetter = undefined
897
+ }
898
+ })
899
+ </script>
900
+
901
+ <style>
902
+ .shell-pan-title {
903
+ display: block;
904
+ height: 40px;
905
+ width: 100%;
906
+ text-align: center;
907
+ line-height: 40px;
908
+ font-weight: bold;
909
+ font-size: 0.8rem;
910
+ }
911
+ .shell-pan a,
912
+ .shell-pan span {
913
+ font-family: 'FiraCode Nerd Font', Helvetica, Arial,
914
+ Verdana, Tahoma, sans-serif;
915
+ color: var(--color-font);
916
+ white-space: pre-wrap;
917
+ }
918
+ .shell-pan a:hover {
919
+ color: var(--color-font);
920
+ }
921
+
922
+ .line-head {
923
+ margin: 5px 0;
924
+ color: var(--color-font);
925
+ font-size: 0.8rem;
926
+ display: flex;
927
+ justify-content: flex-end;
928
+ }
929
+ .line-head > div:first-child svg {
930
+ margin-right: 10px;
931
+ }
932
+ .line-head > div:last-child svg {
933
+ margin-left: 10px;
934
+ }
935
+ .line-head > div > span {
936
+ background: var(--color-card-1);
937
+ margin-left: 5px;
938
+ padding: 3px 10px;
939
+ }
940
+ .line-head > div > span:first-child {
941
+ border-radius: 10px 0 0 10px;
942
+ margin-left: 0;
943
+ }
944
+ .line-head > div:first-child > span:first-child {
945
+ background: var(--color-main);
946
+ color: var(--color-font-r);
947
+ }
948
+ .line-head > div > span:last-child {
949
+ border-radius: 0 10px 10px 0;
950
+ }
951
+ .command-start {
952
+ color: greenyellow;
953
+ }
954
+
955
+ .shell-pan {
956
+ padding: 0 20px;
957
+ pointer-events: all;
958
+ overflow-y: scroll;
959
+ overflow-x: hidden;
960
+ }
961
+ .shell-pan > a {
962
+ flex: 1;
963
+ }
964
+
965
+ .shell-msg {
966
+ border-radius: 7px;
967
+ }
968
+ .shell-msg.revoke {
969
+ display: none;
970
+ }
971
+ .shell-msg.reply {
972
+ background: var(--color-card-1);
973
+ }
974
+ .shell-msg > span.sname.sadmin {
975
+ color: var(--color-main-1);
976
+ }
977
+ .shell-msg > span.sname.sowner {
978
+ color: var(--color-main-4);
979
+ }
980
+ .shell-msg > span.sname.smine {
981
+ color: var(--color-main-0) !important;
982
+ }
983
+ .shell-msg > span.smsg {
984
+ color: var(--color-font-2);
985
+ }
986
+ .shell-msg img {
987
+ max-width: 50%;
988
+ opacity: 0;
989
+ }
990
+ .shell-msg pre {
991
+ font-family: 'FiraCode Nerd Font', Helvetica, Arial,
992
+ Verdana, Tahoma, sans-serif;
993
+ line-height: 7px;
994
+ font-size: 6px;
995
+ }
996
+
997
+ .shell-input {
998
+ margin-bottom: 40px;
999
+ }
1000
+ .shell-input > input {
1001
+ font-family: 'FiraCode Nerd Font', Helvetica, Arial,
1002
+ Verdana, Tahoma, sans-serif;
1003
+ caret-color: var(--color-main);
1004
+ width: calc(100% - 2rem);
1005
+ background: transparent;
1006
+ margin-top: -3px;
1007
+ border: 0;
1008
+ }
1009
+
1010
+ .shell-fastfetch {
1011
+ display: flex;
1012
+ flex-wrap: wrap;
1013
+ }
1014
+ .shell-fastfetch span {
1015
+ line-height: 1.2rem;
1016
+ }
1017
+ .shell-fastfetch > span {
1018
+ color: var(--color-main-0);
1019
+ margin-bottom: 20px;
1020
+ margin-right: 20px;
1021
+ letter-spacing: -1px;
1022
+ }
1023
+ .shell-fastfetch > div {
1024
+ flex-direction: column;
1025
+ display: flex;
1026
+ }
1027
+ .shell-fastfetch > div > a {
1028
+ font-family: unset;
1029
+ }
1030
+ .shell-fastfetch > div > span {
1031
+ color: var(--color-main);
1032
+ }
1033
+ .shell-fastfetch > div > span > span {
1034
+ color: var(--color-font);
1035
+ }
1036
+ .shell-fastfetch > div > div {
1037
+ margin-top: 1rem;
1038
+ display: flex;
1039
+ }
1040
+ .shell-fastfetch > div > div > div {
1041
+ height: 1.5rem;
1042
+ width: 2rem;
1043
+ }
1044
+ </style>