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,461 @@
1
+ <!--
2
+ * @FileDescription: 表情面板模板
3
+ * @Author: Stapxs
4
+ * @Date: missing
5
+ * @Version: 1.0
6
+ -->
7
+
8
+ <template>
9
+ <div class="ss-card face-pan">
10
+ <BcTab>
11
+ <div icon="fa-solid fa-face-laugh-squint">
12
+ <div class="system-face-bar">
13
+ <template v-if="recentEmojisList.length > 0">
14
+ <div class="title">
15
+ <span>{{ $t('最近使用') }}</span>
16
+ </div>
17
+ <div class="face">
18
+ <template
19
+ v-for="num in recentEmojisList"
20
+ :key="num">
21
+ <div>
22
+ <EmojiFace
23
+ :emoji="Emoji.get(num)"
24
+ @click="addBaseFace(num)" />
25
+ </div>
26
+ </template>
27
+ </div>
28
+ </template>
29
+ <div class="title">
30
+ <span>{{ $t('小黄脸表情') }}</span>
31
+ </div>
32
+ <div class="face">
33
+ <template v-for="num in Emoji.normalList" :key="num">
34
+ <div>
35
+ <EmojiFace
36
+ :emoji="Emoji.get(num)"
37
+ @click="addBaseFace(num)" />
38
+ </div>
39
+ </template>
40
+ </div>
41
+ <div class="title">
42
+ <span>{{ $t('emoji 表情') }}</span>
43
+ </div>
44
+ <div class="face">
45
+ <div
46
+ v-for="num in Emoji.emojiList"
47
+ :key="num">
48
+ <EmojiFace
49
+ :emoji="Emoji.get(num)"
50
+ @click="addBaseFace(num)" />
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ <div icon="fa-solid fa-heart">
56
+ <div class="system-face-bar custom-face-bar" @scroll="stickersScroll">
57
+ <template v-if="recentCustomFacesList.length > 0">
58
+ <div class="title">
59
+ <span>{{ $t('最近使用') }}</span>
60
+ </div>
61
+ <div class="face">
62
+ <span
63
+ v-for="(url, num) in recentCustomFacesList"
64
+ :key="num"
65
+ v-tooltip="customFaceTooltip(url)">
66
+ <img
67
+ loading="lazy"
68
+ :src="url"
69
+ :alt="'[' + $t('动画表情') + ']'"
70
+ @click="addImgFace(url)">
71
+ </span>
72
+ </div>
73
+ </template>
74
+ <div class="title">
75
+ <span>{{ $t('收藏的表情') }}</span>
76
+ <font-awesome-icon
77
+ :icon="['fas', 'fa-rotate-right']"
78
+ @click="reloadRoamingStamp" />
79
+ </div>
80
+ <div class="face">
81
+ <div v-if="stickerStore.stickerCache && stickerStore.stickerCache.length <= 0"
82
+ class="ss-card">
83
+ <font-awesome-icon :icon="['fas', 'face-dizzy']" />
84
+ <span>{{ $t('一无所有') }}</span>
85
+ </div>
86
+ <template v-else-if="stickerStore.stickerCache && stickerStore.stickerCache.length > 0">
87
+ <span v-for="(url, index) in stickerStore.stickerCache" :key="'stickers-' + index">
88
+ <img
89
+ v-show="url != 'end'"
90
+ v-tooltip="customFaceTooltip(url)"
91
+ loading="lazy"
92
+ :src="url"
93
+ :alt="'[' + $t('动画表情') + ']'"
94
+ @click="addImgFace(url)">
95
+ </span>
96
+ </template>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ <div v-if="backend.isDesktop()" icon="fa-solid fa-folder-open">
101
+ <div class="system-face-bar custom-face-bar">
102
+ <template v-if="recentLocalFacesList.length > 0">
103
+ <div class="title">
104
+ <span>{{ $t('最近使用') }}</span>
105
+ </div>
106
+ <div class="face">
107
+ <span v-for="(emoji, index) in recentLocalFacesList" :key="index">
108
+ <img
109
+ v-tooltip="customFaceTooltip(emoji.url)"
110
+ loading="lazy"
111
+ :src="emoji.url"
112
+ :alt="'[' + $t('动画表情') + ']'"
113
+ @click="addLocalEmoji(emoji)">
114
+ </span>
115
+ </div>
116
+ </template>
117
+ <div class="title">
118
+ <span>{{ $t('本地表情') }}</span>
119
+ <font-awesome-icon
120
+ :icon="['fas', 'fa-folder-plus']"
121
+ :title="$t('选择文件夹')"
122
+ @click="selectLocalEmojiFolder" />
123
+ <font-awesome-icon
124
+ v-if="settingsStore.sysConfig.local_emoji_folder"
125
+ :icon="['fas', 'fa-rotate-right']"
126
+ :title="$t('重新加载')"
127
+ @click="reloadLocalEmojis" />
128
+ </div>
129
+ <div class="face">
130
+ <div v-if="!settingsStore.sysConfig.local_emoji_folder"
131
+ class="ss-card">
132
+ <font-awesome-icon :icon="['fas', 'folder-open']" />
133
+ <span>{{ $t('选择文件夹') }}</span>
134
+ </div>
135
+ <div v-else-if="settingsStore.sysConfig.local_emoji_folder && localEmojis.length <= 0"
136
+ class="ss-card">
137
+ <font-awesome-icon :icon="['fas', 'face-dizzy']" />
138
+ <span>{{ $t('暂无图片') }}</span>
139
+ </div>
140
+ <template v-else-if="settingsStore.sysConfig.local_emoji_folder && localEmojis.length > 0">
141
+ <span v-for="(emoji, index) in localEmojis" :key="index">
142
+ <img
143
+ v-tooltip="customFaceTooltip(emoji.url)"
144
+ loading="lazy"
145
+ :src="emoji.url"
146
+ :alt="'[' + $t('动画表情') + ']'"
147
+ @click="addLocalEmoji(emoji)">
148
+ </span>
149
+ </template>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </BcTab>
154
+ </div>
155
+ </template>
156
+
157
+ <script setup lang="ts">
158
+ import {
159
+ MsgItemElem,
160
+ SQCodeElem,
161
+ } from '../function/elements/information'
162
+ import { computed, ComputedRef, Ref, ShallowRef, shallowRef } from 'vue'
163
+ import { Connector } from '../function/connect'
164
+ import { backend } from '../runtime/backend'
165
+ import Option from '../function/option'
166
+ import { PopInfo, PopType } from '../function/base'
167
+ import BcTab from 'vue3-bcui/packages/bc-tab'
168
+ import Emoji from '../function/model/emoji'
169
+ import EmojiFace from './EmojiFace.vue'
170
+ import { VueCompData } from '../function/elements/vueComp'
171
+ import CustomFaceTooltip from './tooltip/CustomFaceTooltip.vue'
172
+ import { useLocalStorage, vTooltip } from '../function/utils/appUtil'
173
+ import app from '../main'
174
+ import { useStickerStore } from '../state/sticker'
175
+ import { useSettingsStore } from '../state/settings'
176
+ import { useAuthStore } from '../state/auth'
177
+
178
+ const { recordList: recentEmojisId, showList: recentEmojisList } =
179
+ getRecentEmojiRecord<number>('recent-emojis-id')
180
+ const { recordList: recentCustomFacesId, showList: recentCustomFacesList } =
181
+ getRecentEmojiRecord<string>('recent-custom-faces-id')
182
+ const { recordList: recentLocalFacesId, showList: _recentLocalFacesList } =
183
+ getRecentEmojiRecord<string>('recent-local-faces-id')
184
+
185
+ const recentLocalFacesList = computed(()=>{
186
+ const list: LocalEmoji[] = []
187
+ for (const path of _recentLocalFacesList.value) {
188
+ const emoji = localEmojis.value.find(e => e.path === path)
189
+ if (!emoji) continue
190
+ list.push(emoji)
191
+ }
192
+ return list
193
+ })
194
+
195
+ interface LocalEmoji {
196
+ name: string
197
+ path: string
198
+ url: string
199
+ }
200
+
201
+ const popInfo = new PopInfo()
202
+ const stickerStore = useStickerStore()
203
+ const settingsStore = useSettingsStore()
204
+ const authStore = useAuthStore()
205
+
206
+ const stickerPage = shallowRef(1)
207
+ const localEmojis = shallowRef<LocalEmoji[]>([])
208
+
209
+ const emit = defineEmits<{
210
+ addSpecialMsg: [data: SQCodeElem],
211
+ sendMsg: [echo?: string]
212
+ }>()
213
+
214
+ // 加载漫游表情
215
+ if (
216
+ stickerStore.stickerCache && stickerStore.stickerCache.length == 0 &&
217
+ authStore.jsonMap.roaming_stamp
218
+ ) {
219
+ reloadRoamingStamp()
220
+ }
221
+ // 加载本地表情
222
+ if (backend.isDesktop() && settingsStore.sysConfig.local_emoji_folder) {
223
+ reloadLocalEmojis()
224
+ }
225
+
226
+ function addSpecialMsg(json: MsgItemElem, addText: boolean) {
227
+ emit('addSpecialMsg', {
228
+ addText: addText,
229
+ msgObj: json,
230
+ })
231
+ }
232
+ function addBaseFace(id: number) {
233
+ recordRecentEmoji(recentEmojisId, id)
234
+ if (id < 5000)
235
+ addSpecialMsg({ type: 'face', id: id }, true)
236
+ else
237
+ addSpecialMsg({ type: 'text', text: Emoji.get(id)!.value }, true)
238
+ }
239
+
240
+ //#region == 漫游表情相关函数 ===========
241
+ function reloadRoamingStamp() {
242
+ stickerStore.stickerCache = undefined
243
+ if (authStore.jsonMap.roaming_stamp.pagerType == 'full') {
244
+ // 全量分页,返回所有内容
245
+ Connector.send(
246
+ authStore.jsonMap.roaming_stamp.name,
247
+ { count: 48 },
248
+ 'getRoamingStamp_48',
249
+ )
250
+ } else {
251
+ // 默认不分页,返回所有内容
252
+ Connector.send(
253
+ authStore.jsonMap.roaming_stamp.name,
254
+ {},
255
+ 'getRoamingStamp',
256
+ )
257
+ }
258
+ }
259
+ function stickersScroll(e: Event) {
260
+ const target = e.target as HTMLDivElement
261
+ // 如果滚到了底部
262
+ if (
263
+ target.scrollHeight - target.scrollTop <
264
+ target.clientHeight + 0.5
265
+ ) {
266
+ if (stickerStore.stickerCache) {
267
+ if (authStore.jsonMap.roaming_stamp.pagerType == 'full' &&
268
+ stickerStore.stickerCache[stickerStore.stickerCache.length - 1] != 'end') {
269
+ const count = 48 + 48 * stickerPage.value
270
+ // 全量分页,返回所有内容(napcat 行为)
271
+ Connector.send(
272
+ authStore.jsonMap.roaming_stamp.name,
273
+ { count: count },
274
+ 'getRoamingStamp_' + count,
275
+ )
276
+ stickerPage.value++
277
+ }
278
+ }
279
+ }
280
+ }
281
+ function addImgFace(url: string) {
282
+ recordRecentEmoji(recentCustomFacesId, url)
283
+ addSpecialMsg(
284
+ { type: 'image', file: url, subType: 1 },
285
+ true,
286
+ )
287
+ // 直接发送表情
288
+ if(settingsStore.sysConfig.send_face == true) {
289
+ emit('sendMsg')
290
+ }
291
+ }
292
+ //#endregion
293
+
294
+ //#region == 本地表情相关函数 ===========
295
+ /**
296
+ * 选择文件夹
297
+ */
298
+ async function selectLocalEmojiFolder() {
299
+ const { $t } = app.config.globalProperties
300
+ try {
301
+ // 调用后端选择文件夹
302
+ const folderPath = await backend.call(
303
+ undefined,
304
+ 'sys:selectFolder',
305
+ true
306
+ )
307
+
308
+ if (folderPath) {
309
+ // 保存文件夹路径
310
+ Option.save('local_emoji_folder', folderPath)
311
+ popInfo.add(PopType.INFO, $t('已设置本地表情文件夹'))
312
+ // 重新加载本地表情
313
+ reloadLocalEmojis()
314
+ }
315
+ } catch (error) {
316
+ popInfo.add(PopType.ERR, $t('选择文件夹失败'))
317
+ }
318
+ }
319
+
320
+ /**
321
+ * 重新加载本地表情
322
+ */
323
+ async function reloadLocalEmojis() {
324
+ try {
325
+ const folderPath = settingsStore.sysConfig.local_emoji_folder
326
+ if (!folderPath) {
327
+ localEmojis.value = []
328
+ return
329
+ }
330
+
331
+ // 调用后端读取文件夹中的图片
332
+ const images = await backend.call(
333
+ undefined,
334
+ 'sys:getLocalEmojis',
335
+ true,
336
+ folderPath
337
+ )
338
+
339
+ if (images && Array.isArray(images)) {
340
+ // 对于 Tauri,需要使用 convertFileSrc 转换文件路径
341
+ if (backend.type === 'tauri') {
342
+ const { convertFileSrc } = await import('@tauri-apps/api/core')
343
+ localEmojis.value = images.map((img: any) => ({
344
+ name: img.name,
345
+ path: img.path,
346
+ url: convertFileSrc(img.path),
347
+ }))
348
+ } else {
349
+ localEmojis.value = images.map((img: any) => ({
350
+ name: img.name,
351
+ path: img.path,
352
+ url: img.url,
353
+ }))
354
+ }
355
+ } else {
356
+ localEmojis.value = []
357
+ }
358
+ } catch (error) {
359
+ localEmojis.value = []
360
+ }
361
+ }
362
+
363
+ /**
364
+ * 添加本地表情到消息
365
+ */
366
+ async function addLocalEmoji(emoji: LocalEmoji) {
367
+ try {
368
+ // 读取文件为 base64
369
+ const base64String = await backend.call(
370
+ undefined,
371
+ 'sys:readFileAsBase64',
372
+ true,
373
+ emoji.path
374
+ )
375
+
376
+ recordRecentEmoji(recentLocalFacesId, emoji.path)
377
+
378
+ // 发送 base64 格式的图片
379
+ addSpecialMsg(
380
+ { type: 'image', file: 'base64://' + base64String, subType: 1 },
381
+ true,
382
+ )
383
+ // 如果设置了直接发送表情
384
+ if(settingsStore.sysConfig.send_face == true) {
385
+ emit('sendMsg')
386
+ }
387
+ } catch (error) {
388
+ const { $t } = app.config.globalProperties
389
+ popInfo.add(PopType.ERR, $t('添加本地表情失败'))
390
+ }
391
+ }
392
+ //#endregion
393
+
394
+ //#region == 最近表情相关函数 ===========
395
+ function getRecentEmojiRecord<T>(storeId: string): {
396
+ recordList: Ref<T[]>
397
+ showList: ComputedRef<T[]>
398
+ } {
399
+ const recordList = useLocalStorage<T[]>(storeId, [])
400
+ const showList = computed(() => {
401
+ if (settingsStore.sysConfig.record_recent_emoji === 'none') {
402
+ return []
403
+ } else if (settingsStore.sysConfig.record_recent_emoji === 'order') {
404
+ return recordList.value.slice(0, 30)
405
+ } else {
406
+ const timesMap = new Map<T, number>()
407
+ for (const id of recordList.value) {
408
+ timesMap.set(id, (timesMap.get(id) || 0) + 1)
409
+ }
410
+ return Array.from(timesMap.entries())
411
+ .sort((a, b) => b[1] - a[1])
412
+ .map((entry) => entry[0])
413
+ .slice(0, 30)
414
+ }
415
+ })
416
+
417
+ return {
418
+ recordList,
419
+ showList,
420
+ }
421
+ }
422
+
423
+ function recordRecentEmoji<T>(recordList: ShallowRef<T[]>, id: T) {
424
+ if (settingsStore.sysConfig.record_recent_emoji === 'none') return
425
+ let limit: number
426
+ switch (settingsStore.sysConfig.record_recent_emoji) {
427
+ case 'order':
428
+ limit = 30
429
+ break
430
+ case '100times':
431
+ limit = 100
432
+ break
433
+ case '500times':
434
+ limit = 500
435
+ break
436
+ default:
437
+ throw new Error('Invalid recent emoji record setting')
438
+ }
439
+ const list = recordList.value
440
+ if (settingsStore.sysConfig.record_recent_emoji === 'order') {
441
+ const index = list.indexOf(id)
442
+ if (index !== -1) {
443
+ list.splice(index, 1)
444
+ }
445
+ }
446
+ list.unshift(id)
447
+ if (list.length > limit) {
448
+ list.pop()
449
+ }
450
+ recordList.value = list
451
+ }
452
+ //#endregion
453
+
454
+ function customFaceTooltip(url: string): VueCompData<typeof CustomFaceTooltip> {
455
+ return {
456
+ comp: CustomFaceTooltip,
457
+ model: undefined,
458
+ props: { url }
459
+ }
460
+ }
461
+ </script>
@@ -0,0 +1,129 @@
1
+ <!--
2
+ * @FileDescription: 群文件列表项模板
3
+ * @Author: Stapxs
4
+ * @Date: missing
5
+ * @Version: 1.0
6
+ -->
7
+
8
+ <template>
9
+ <div :class="(item.folder_id ? ' folder' : '') + (item.items && item.items.length > 0 ? ' open' : '')"
10
+ @click="loadFileDir(item)">
11
+ <font-awesome-icon v-if="item.folder_id" :icon="['fas', 'folder']" />
12
+ <font-awesome-icon v-else :icon="['fas', 'file']" />
13
+ <div class="main">
14
+ <span>{{ toHtml(item.folder_name ?? item.file_name) }}</span>
15
+ <div>
16
+ <span>{{ toHtml(item.creater_name ?? item.uploader_name) }}</span>
17
+ <span>{{
18
+ (item.create_time || item.upload_time) ? Intl.DateTimeFormat(trueLang, {
19
+ year: 'numeric',
20
+ month: 'short',
21
+ day: 'numeric',
22
+ }).format(new Date((item.create_time ?? item.upload_time) * 1000)) : '-'
23
+ }}</span>
24
+ <span v-if="!item.dead_time && item.dead_time">{{
25
+ item.dead_time - item.create_time / 86400 - 1 + $t('天后')
26
+ }}</span>
27
+ <span v-if="item.folder_id">{{
28
+ $t('共 {num} 个文件', { num: item.count })
29
+ }}</span>
30
+ <span v-else>{{ getSize(item.size) }}</span>
31
+ </div>
32
+ </div>
33
+ <template v-if="item.file_id">
34
+ <div class="download"
35
+ @click="getFile(item)">
36
+ <font-awesome-icon :icon="['fas', 'angle-down']" />
37
+ </div>
38
+ </template>
39
+ <div v-show="item.show_items !== false && item.items !== undefined"
40
+ :class="(item.items !== undefined ? 'sub_file ' : '') + 'group-files'">
41
+ <div v-for="sub_item in item.items"
42
+ :key="'sub_file-' + sub_item.file_id">
43
+ <FileBody :chat="chat"
44
+ :item="(sub_item as GroupFileElem & GroupFileFolderElem)"
45
+ :parent="item.folder_id" />
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </template>
50
+
51
+ <script setup lang="ts">
52
+ import { i18n } from '../main'
53
+
54
+ import {
55
+ getTrueLang,
56
+ escape2Html,
57
+ getSizeFromBytes,
58
+ } from '../function/utils/systemUtil'
59
+ import {
60
+ GroupFileElem,
61
+ GroupFileFolderElem
62
+ } from '../function/elements/information'
63
+ import { Connector } from '../function/connect'
64
+ import { useAuthStore } from '../state/auth'
65
+ import { useChatStore } from '../state/chat'
66
+
67
+ defineOptions({ name: 'FileBody' })
68
+
69
+ const authStore = useAuthStore()
70
+ const chatStore = useChatStore()
71
+ const $t = i18n.global.t
72
+
73
+ defineProps({
74
+ item: {
75
+ type: Object as () => GroupFileElem & GroupFileFolderElem,
76
+ required: true,
77
+ },
78
+ chat: {
79
+ type: Object,
80
+ required: true,
81
+ },
82
+ parent: {
83
+ type: String,
84
+ required: false,
85
+ default: undefined,
86
+ },
87
+ })
88
+
89
+ const trueLang = getTrueLang()
90
+ const getSize = getSizeFromBytes
91
+ const toHtml = escape2Html
92
+
93
+ /**
94
+ * 下载文件(获取文件下载地址并下载)
95
+ */
96
+ function getFile(item: GroupFileElem) {
97
+ const name = authStore.jsonMap.file_download?.name
98
+ if(name) {
99
+ Connector.send(
100
+ name,
101
+ {
102
+ group_id: chatStore.chatInfo.show.id,
103
+ file_id: item.file_id,
104
+ },
105
+ 'downloadGroupFile_' + item.file_id + '_' + btoa(encodeURIComponent(item.file_name)),
106
+ )
107
+ }
108
+ }
109
+
110
+ /**
111
+ * 加载子文件夹
112
+ */
113
+ function loadFileDir(item: GroupFileElem & GroupFileFolderElem) {
114
+ const id = item.folder_id
115
+
116
+ const name = authStore.jsonMap.group_folder_files?.name
117
+ if(item.items !== undefined) {
118
+ item.show_items = !item.show_items
119
+ return
120
+ }
121
+
122
+ if (id && name) {
123
+ Connector.send(name, {
124
+ folder_id: id,
125
+ group_id: chatStore.chatInfo.show.id,
126
+ }, 'getGroupDirFiles_' + id)
127
+ }
128
+ }
129
+ </script>