vue-chat-kit 0.1.1 → 0.1.3

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.
@@ -0,0 +1,1864 @@
1
+ import { ref as f, computed as re, nextTick as Ne, watch as yt, resolveComponent as ce, openBlock as r, createBlock as q, withCtx as b, createElementVNode as t, createElementBlock as v, createCommentVNode as I, createVNode as p, createTextVNode as ne, onMounted as _t, onUnmounted as bt, unref as u, Fragment as fe, renderList as me, normalizeClass as X, resolveDynamicComponent as Ct, toDisplayString as k, isRef as we, withModifiers as Je, withDirectives as kt, withKeys as wt, vModelText as Ut, normalizeStyle as xt } from "vue";
2
+ import { ChatDotRound as Ee, UserFilled as Qe, Bell as At, Setting as St, Search as Ke, Plus as Vt, MoreFilled as Ft, Document as Rt, Download as It, Folder as Ze, Picture as Lt, ChatLineRound as Tt, Camera as zt } from "@element-plus/icons-vue";
3
+ import We from "dayjs";
4
+ import { ElMessage as Y } from "element-plus";
5
+ class Dt {
6
+ constructor(e, s = {}) {
7
+ this.userId = e, this.wsUrl = s.wsUrl || "", this.socket = null, this.reconnectAttempts = 0, this.maxReconnectAttempts = s.maxReconnectAttempts || 5, this.reconnectDelay = s.reconnectDelay || 3e3, this.handlers = {
8
+ message: [],
9
+ open: [],
10
+ close: [],
11
+ error: []
12
+ }, this.isConnecting = !1, this.manualClose = !1;
13
+ }
14
+ /**
15
+ * 连接 WebSocket
16
+ */
17
+ connect() {
18
+ if (!(this.isConnecting || this.isConnected())) {
19
+ this.isConnecting = !0, this.manualClose = !1;
20
+ try {
21
+ this.socket = new WebSocket(this.wsUrl), this.socket.onopen = () => {
22
+ console.log("[VueChatKit] WebSocket 连接成功"), this.isConnecting = !1, this.reconnectAttempts = 0, this.emit("open");
23
+ }, this.socket.onmessage = (e) => {
24
+ try {
25
+ const s = e.data;
26
+ this.emit("message", s);
27
+ } catch (s) {
28
+ console.error("[VueChatKit] WebSocket 消息解析失败", s);
29
+ }
30
+ }, this.socket.onclose = (e) => {
31
+ console.log("[VueChatKit] WebSocket 连接关闭", e.code), this.isConnecting = !1, this.emit("close", e), !this.manualClose && e.code !== 1e3 && this.reconnect();
32
+ }, this.socket.onerror = (e) => {
33
+ console.error("[VueChatKit] WebSocket 连接错误", e), this.isConnecting = !1, this.emit("error", e);
34
+ };
35
+ } catch (e) {
36
+ console.error("[VueChatKit] WebSocket 创建连接失败", e), this.isConnecting = !1;
37
+ }
38
+ }
39
+ }
40
+ /**
41
+ * 发送消息
42
+ */
43
+ send(e, s, o = "text", F = "", T = "", z = 0) {
44
+ if (this.isConnected()) {
45
+ const w = JSON.stringify({
46
+ to: e,
47
+ msg: s,
48
+ type: o,
49
+ fileUrl: F,
50
+ fileName: T,
51
+ fileSize: z
52
+ });
53
+ return this.socket.send(w), !0;
54
+ }
55
+ return console.warn("[VueChatKit] WebSocket 连接未建立,无法发送消息"), !1;
56
+ }
57
+ /**
58
+ * 注册事件监听
59
+ */
60
+ on(e, s) {
61
+ this.handlers[e] && this.handlers[e].push(s);
62
+ }
63
+ /**
64
+ * 移除事件监听
65
+ */
66
+ off(e, s) {
67
+ if (this.handlers[e]) {
68
+ const o = this.handlers[e].indexOf(s);
69
+ o > -1 && this.handlers[e].splice(o, 1);
70
+ }
71
+ }
72
+ /**
73
+ * 触发事件
74
+ */
75
+ emit(e, ...s) {
76
+ this.handlers[e] && this.handlers[e].forEach((o) => o(...s));
77
+ }
78
+ /**
79
+ * 重连
80
+ */
81
+ reconnect() {
82
+ this.reconnectAttempts < this.maxReconnectAttempts ? (this.reconnectAttempts++, console.log(`[VueChatKit] 尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`), setTimeout(() => this.connect(), this.reconnectDelay)) : console.error("[VueChatKit] 重连次数已达上限");
83
+ }
84
+ /**
85
+ * 关闭连接
86
+ */
87
+ close() {
88
+ this.manualClose = !0, this.socket && (this.socket.close(), this.socket = null, this.handlers = {
89
+ message: [],
90
+ open: [],
91
+ close: [],
92
+ error: []
93
+ });
94
+ }
95
+ /**
96
+ * 检查连接状态
97
+ */
98
+ isConnected() {
99
+ return this.socket && this.socket.readyState === WebSocket.OPEN;
100
+ }
101
+ }
102
+ class Ue extends Error {
103
+ constructor(e, s, o, F) {
104
+ super(e), this.name = "RequestError", this.status = s || 0, this.code = o || 0, this.data = F;
105
+ }
106
+ }
107
+ class Mt {
108
+ constructor(e = {}) {
109
+ this.baseUrl = e.baseUrl || "", this.timeout = e.timeout || 1e4, this.headers = e.headers || {}, this.requestInterceptors = [], this.responseInterceptors = [], this.addRequestInterceptor((s) => (s.body instanceof FormData || (s.headers = {
110
+ "Content-Type": "application/json",
111
+ ...s.headers
112
+ }), s));
113
+ }
114
+ /**
115
+ * 添加请求拦截器
116
+ */
117
+ addRequestInterceptor(e) {
118
+ this.requestInterceptors.push(e);
119
+ }
120
+ /**
121
+ * 添加响应拦截器
122
+ */
123
+ addResponseInterceptor(e) {
124
+ this.responseInterceptors.push(e);
125
+ }
126
+ /**
127
+ * 超时控制
128
+ */
129
+ timeoutPromise(e) {
130
+ return new Promise((s, o) => {
131
+ setTimeout(() => {
132
+ o(new Ue("请求超时", 408, 408));
133
+ }, e);
134
+ });
135
+ }
136
+ /**
137
+ * 核心请求方法
138
+ */
139
+ async request(e, s = {}) {
140
+ const { method: o = "GET", headers: F = {}, body: T, params: z } = s;
141
+ let w = e.startsWith("http") ? e : `${this.baseUrl}${e}`, U = {
142
+ method: o,
143
+ headers: { ...this.headers, ...F },
144
+ body: T,
145
+ params: z
146
+ };
147
+ this.requestInterceptors.forEach((m) => {
148
+ U = m(U);
149
+ });
150
+ const V = {
151
+ method: U.method,
152
+ headers: U.headers,
153
+ credentials: "include"
154
+ };
155
+ if (U.body && o !== "GET" && (U.body instanceof FormData ? V.body = U.body : typeof U.body == "object" ? V.body = JSON.stringify(U.body) : V.body = U.body), U.params) {
156
+ const m = new URLSearchParams();
157
+ for (const C in U.params)
158
+ U.params[C] !== void 0 && U.params[C] !== null && U.params[C] !== "" && m.append(C, U.params[C]);
159
+ const _ = m.toString();
160
+ _ && (w += (w.includes("?") ? "&" : "?") + _);
161
+ }
162
+ try {
163
+ let _ = await Promise.race([
164
+ fetch(w, V),
165
+ this.timeoutPromise(this.timeout)
166
+ ]);
167
+ if (this.responseInterceptors.forEach((N) => {
168
+ _ = N(_);
169
+ }), !_.ok)
170
+ throw new Ue(
171
+ `HTTP ${_.status}: ${_.statusText}`,
172
+ _.status,
173
+ _.status
174
+ );
175
+ const C = _.headers.get("content-type");
176
+ let R;
177
+ return C && C.includes("application/json") ? R = await _.json() : R = await _.text(), R;
178
+ } catch (m) {
179
+ throw m instanceof Ue ? m : new Ue(
180
+ m instanceof Error ? m.message : "网络错误",
181
+ 0,
182
+ 0
183
+ );
184
+ }
185
+ }
186
+ // 便捷方法
187
+ get(e, s, o) {
188
+ return this.request(e, { ...o, method: "GET", params: s });
189
+ }
190
+ post(e, s, o) {
191
+ return this.request(e, { ...o, method: "POST", body: s });
192
+ }
193
+ put(e, s, o) {
194
+ return this.request(e, { ...o, method: "PUT", body: s });
195
+ }
196
+ delete(e, s) {
197
+ return this.request(e, { ...s, method: "DELETE" });
198
+ }
199
+ }
200
+ class Be {
201
+ constructor(e, s = null) {
202
+ this.config = e, this.endpoints = e.api.endpoints, this.customAdapter = e.api.adapter, s ? this.http = s : this.http = new Mt({
203
+ baseUrl: e.api.baseUrl,
204
+ headers: e.headers
205
+ });
206
+ }
207
+ /**
208
+ * 使用自定义适配器或默认实现
209
+ */
210
+ async _call(e, ...s) {
211
+ return this.customAdapter && typeof this.customAdapter[e] == "function" ? this.customAdapter[e](...s) : this[`_${e}`](...s);
212
+ }
213
+ // ========== 好友相关 ==========
214
+ /**
215
+ * 获取好友列表
216
+ */
217
+ async getFriends(e) {
218
+ return this._call("getFriends", e);
219
+ }
220
+ async _getFriends(e) {
221
+ return this.http.get(this.endpoints.getFriends, { currentUser: e });
222
+ }
223
+ /**
224
+ * 获取可添加的用户列表
225
+ */
226
+ async getAvailableUsers(e) {
227
+ return this._call("getAvailableUsers", e);
228
+ }
229
+ async _getAvailableUsers(e) {
230
+ return this.http.get(this.endpoints.getAvailableUsers, { currentUser: e });
231
+ }
232
+ /**
233
+ * 添加好友
234
+ */
235
+ async addFriend(e, s) {
236
+ return this._call("addFriend", e, s);
237
+ }
238
+ async _addFriend(e, s) {
239
+ return this.http.post(this.endpoints.addFriend, { currentUser: e, friendUser: s });
240
+ }
241
+ /**
242
+ * 获取好友申请列表
243
+ */
244
+ async getApplyList(e) {
245
+ return this._call("getApplyList", e);
246
+ }
247
+ async _getApplyList(e) {
248
+ return this.http.get(this.endpoints.getApplyList, { currentUser: e });
249
+ }
250
+ /**
251
+ * 同意好友申请
252
+ */
253
+ async agreeFriend(e, s) {
254
+ return this._call("agreeFriend", e, s);
255
+ }
256
+ async _agreeFriend(e, s) {
257
+ return this.http.post(this.endpoints.agreeFriend, { applyUser: e, friendUser: s });
258
+ }
259
+ /**
260
+ * 设置好友聊天状态
261
+ */
262
+ async setChatStatus(e, s, o = 1) {
263
+ return this._call("setChatStatus", e, s, o);
264
+ }
265
+ async _setChatStatus(e, s, o) {
266
+ return this.http.post(this.endpoints.setChatStatus, null, { params: { currentUser: e, friendUser: s, status: o } });
267
+ }
268
+ // ========== 消息相关 ==========
269
+ /**
270
+ * 获取聊天历史
271
+ */
272
+ async getHistory(e, s) {
273
+ return this._call("getHistory", e, s);
274
+ }
275
+ async _getHistory(e, s) {
276
+ return this.http.get(this.endpoints.getHistory, { fromUser: e, toUser: s });
277
+ }
278
+ /**
279
+ * 标记消息已读
280
+ */
281
+ async setRead(e, s) {
282
+ return this._call("setRead", e, s);
283
+ }
284
+ async _setRead(e, s) {
285
+ return this.http.post(this.endpoints.setRead, { currentUser: e, friendUser: s });
286
+ }
287
+ // ========== 文件相关 ==========
288
+ /**
289
+ * 上传文件
290
+ */
291
+ async uploadFile(e) {
292
+ return this._call("uploadFile", e);
293
+ }
294
+ async _uploadFile(e) {
295
+ const s = new FormData();
296
+ return s.append("file", e), this.http.post(this.endpoints.uploadFile, s);
297
+ }
298
+ // ========== 用户相关 ==========
299
+ /**
300
+ * 获取用户信息
301
+ */
302
+ async getUserInfo(e) {
303
+ return this._call("getUserInfo", e);
304
+ }
305
+ async _getUserInfo(e) {
306
+ return this.http.get(this.endpoints.getUserInfo, { username: e });
307
+ }
308
+ /**
309
+ * 更新用户信息
310
+ */
311
+ async updateUserInfo(e, s) {
312
+ return this._call("updateUserInfo", e, s);
313
+ }
314
+ async _updateUserInfo(e, s) {
315
+ return this.http.put(this.endpoints.updateUserInfo, { username: e, ...s });
316
+ }
317
+ /**
318
+ * 获取用户头像
319
+ */
320
+ async getUserAvatar(e) {
321
+ return this._call("getUserAvatar", e);
322
+ }
323
+ async _getUserAvatar(e) {
324
+ return this.http.get(this.endpoints.getUserAvatar, { username: e });
325
+ }
326
+ /**
327
+ * 上传头像
328
+ */
329
+ async uploadAvatar(e, s) {
330
+ return this._call("uploadAvatar", e, s);
331
+ }
332
+ async _uploadAvatar(e, s) {
333
+ const o = new FormData();
334
+ return o.append("file", e), o.append("username", s), this.http.post(this.endpoints.uploadAvatar, o);
335
+ }
336
+ }
337
+ const $t = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
338
+ __proto__: null,
339
+ ChatApi: Be,
340
+ default: Be
341
+ }, Symbol.toStringTag, { value: "Module" }));
342
+ function Et(y) {
343
+ const e = new Be(y);
344
+ let s = null;
345
+ const o = y.user.username, F = f(y.user.avatar || `https://api.dicebear.com/7.x/avataaars/svg?seed=${o}`), T = f({
346
+ username: o,
347
+ nickname: y.user.nickname || "",
348
+ email: y.user.email || "",
349
+ phone: y.user.phone || "",
350
+ bio: y.user.bio || ""
351
+ }), z = f(!1), w = f([]), U = f([]), V = f([]), m = f(""), _ = f(""), C = f(""), R = f(null), N = f(!1), G = f(""), J = f([]), Q = f(!1), le = f([]), te = f(!1), g = re(() => {
352
+ let a = U.value;
353
+ if (_.value) {
354
+ const i = _.value.toLowerCase();
355
+ a = a.filter(
356
+ (c) => {
357
+ var S;
358
+ return (S = c.username) == null ? void 0 : S.toLowerCase().includes(i);
359
+ }
360
+ );
361
+ }
362
+ return a.map((i) => ({
363
+ id: i.username,
364
+ name: i.username,
365
+ avatar: i.avatar || F.value,
366
+ online: i.online,
367
+ lastMsg: i.lastMsg || "暂无消息",
368
+ lastTime: i.lastTime,
369
+ unread: i.unReadNum || 0
370
+ }));
371
+ }), x = re(() => {
372
+ let a = w.value;
373
+ if (_.value) {
374
+ const i = _.value.toLowerCase();
375
+ a = a.filter(
376
+ (c) => {
377
+ var S;
378
+ return (S = c.username) == null ? void 0 : S.toLowerCase().includes(i);
379
+ }
380
+ );
381
+ }
382
+ return a.map((i) => ({
383
+ id: i.username,
384
+ name: i.username,
385
+ avatar: i.avatar || F.value,
386
+ online: i.online,
387
+ isChatting: i.isChatting
388
+ }));
389
+ }), A = re(() => G.value ? J.value.filter(
390
+ (a) => {
391
+ var i;
392
+ return (i = a.username) == null ? void 0 : i.toLowerCase().includes(G.value.toLowerCase());
393
+ }
394
+ ) : J.value), E = re(() => g.value.find((a) => a.id === m.value) || null), ie = re(() => V.value.map((a) => {
395
+ const i = a.type === "file" || a.fileUrl || a.fileName, c = a.fileName || a.msgContent;
396
+ return {
397
+ text: a.msgContent,
398
+ isSelf: a.sendUsername === o,
399
+ time: a.createTime,
400
+ sendUsername: a.sendUsername,
401
+ type: i ? "file" : "text",
402
+ fileType: ge(c) ? "image" : ye(c),
403
+ fileUrl: a.fileUrl || "",
404
+ fileName: c,
405
+ fileSize: a.fileSize || 0
406
+ };
407
+ })), P = (a) => We(a).format("HH:mm"), he = (a) => {
408
+ if (!a) return "";
409
+ const i = We(), c = We(a);
410
+ return i.isSame(c, "day") ? c.format("HH:mm") : i.diff(c, "day") === 1 ? "昨天" : i.diff(c, "day") < 7 ? ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][c.day()] : c.format("MM/DD");
411
+ }, ge = (a) => {
412
+ if (!a) return !1;
413
+ const i = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"], c = a.split(".").pop().toLowerCase();
414
+ return i.includes(c);
415
+ }, ye = (a) => {
416
+ if (!a) return "default";
417
+ const i = a.split(".").pop().toLowerCase();
418
+ return ["xls", "xlsx"].includes(i) ? "excel" : ["pdf"].includes(i) ? "pdf" : ["doc", "docx"].includes(i) ? "docx" : "default";
419
+ }, O = () => {
420
+ Ne(() => {
421
+ R.value && (R.value.scrollTop = R.value.scrollHeight);
422
+ });
423
+ }, K = async () => {
424
+ try {
425
+ const i = (await e.getFriends(o)).data || [];
426
+ w.value = i, U.value = i.filter((c) => c.isChatting === 1);
427
+ for (const c of U.value)
428
+ try {
429
+ const se = (await e.getHistory(o, c.username)).data || [];
430
+ c.unReadNum = se.filter(
431
+ (ee) => ee.isRead === 0 && ee.sendUsername === c.username
432
+ ).length;
433
+ } catch {
434
+ c.unReadNum = 0;
435
+ }
436
+ } catch (a) {
437
+ console.error("[VueChatKit] 获取好友列表失败", a);
438
+ }
439
+ }, oe = async (a) => {
440
+ try {
441
+ const i = await e.getHistory(o, a);
442
+ V.value = i.data || [], O();
443
+ } catch (i) {
444
+ console.error("[VueChatKit] 获取聊天历史失败", i);
445
+ }
446
+ }, He = async (a) => {
447
+ try {
448
+ await e.setRead(o, a), K();
449
+ } catch (i) {
450
+ console.error("[VueChatKit] 标记已读失败", i);
451
+ }
452
+ }, xe = async (a) => {
453
+ m.value = a.id, await oe(a.id), await He(a.id), O();
454
+ }, Ae = async (a, i = 1) => {
455
+ try {
456
+ return await e.setChatStatus(o, a, i), await K(), !0;
457
+ } catch (c) {
458
+ return console.error("[VueChatKit] 设置聊天状态失败", c), !1;
459
+ }
460
+ }, _e = () => {
461
+ if (!C.value.trim() || !m.value || !s) return;
462
+ if (s.send(m.value, C.value.trim(), "text")) {
463
+ const i = {
464
+ msgContent: C.value.trim(),
465
+ sendUsername: o,
466
+ receiveUsername: m.value,
467
+ createTime: /* @__PURE__ */ new Date(),
468
+ isRead: 0,
469
+ type: "text"
470
+ };
471
+ V.value.push(i), C.value = "", O(), setTimeout(() => {
472
+ oe(m.value), K();
473
+ }, 300);
474
+ }
475
+ }, be = async (a) => {
476
+ if (!m.value || !s) return !1;
477
+ try {
478
+ const i = await e.uploadFile(a);
479
+ if (i.code === 200 && i.data) {
480
+ const { fileUrl: c, fileName: S } = i.data;
481
+ if (s.send(
482
+ m.value,
483
+ S,
484
+ "file",
485
+ c,
486
+ S,
487
+ a.size
488
+ )) {
489
+ const ee = {
490
+ msgContent: S,
491
+ sendUsername: o,
492
+ receiveUsername: m.value,
493
+ createTime: /* @__PURE__ */ new Date(),
494
+ isRead: 0,
495
+ type: "file",
496
+ fileUrl: c,
497
+ fileName: S,
498
+ fileSize: a.size
499
+ };
500
+ return V.value.push(ee), O(), !0;
501
+ }
502
+ }
503
+ return !1;
504
+ } catch (i) {
505
+ return console.error("[VueChatKit] 发送文件失败", i), !1;
506
+ }
507
+ }, Ce = async (a, i) => {
508
+ if (!(!m.value || !s)) {
509
+ if (i && i.trim() && s.send(m.value, i.trim(), "text")) {
510
+ const S = {
511
+ msgContent: i.trim(),
512
+ sendUsername: o,
513
+ receiveUsername: m.value,
514
+ createTime: /* @__PURE__ */ new Date(),
515
+ isRead: 0,
516
+ type: "text"
517
+ };
518
+ V.value.push(S);
519
+ }
520
+ for (const c of a) {
521
+ const S = c.file || c;
522
+ await be(S);
523
+ }
524
+ setTimeout(() => {
525
+ oe(m.value), K();
526
+ }, 300);
527
+ }
528
+ }, Se = (a) => {
529
+ try {
530
+ try {
531
+ const c = JSON.parse(a);
532
+ if (c.to || c.msg)
533
+ return {
534
+ to: c.to,
535
+ content: c.msg,
536
+ type: c.type || "text",
537
+ fileUrl: c.fileUrl || "",
538
+ fileName: c.fileName || "",
539
+ fileSize: c.fileSize || 0
540
+ };
541
+ } catch {
542
+ }
543
+ const i = a.match(/^\[(.+?)\]:(.+)$/);
544
+ if (i)
545
+ return {
546
+ username: i[1],
547
+ content: i[2],
548
+ type: "text"
549
+ };
550
+ } catch (i) {
551
+ console.error("[VueChatKit] 解析消息失败", i);
552
+ }
553
+ return null;
554
+ }, Ve = (a) => {
555
+ if (a.includes("【状态变更】")) {
556
+ const c = /【状态变更】(.+?) 已(上线|下线)/, S = a.match(c);
557
+ if (S) {
558
+ const se = S[1], ee = S[2] === "上线", ve = w.value.find((B) => B.username === se);
559
+ ve && (ve.online = ee);
560
+ }
561
+ return;
562
+ }
563
+ const i = Se(a);
564
+ if (i) {
565
+ if (m.value) {
566
+ try {
567
+ let c = {
568
+ msgContent: i.content,
569
+ sendUsername: i.username || m.value,
570
+ receiveUsername: o,
571
+ createTime: /* @__PURE__ */ new Date(),
572
+ isRead: 0,
573
+ type: i.type || "text",
574
+ fileUrl: i.fileUrl || "",
575
+ fileName: i.fileName || "",
576
+ fileSize: i.fileSize || 0
577
+ };
578
+ V.value.push(c), O();
579
+ } catch (c) {
580
+ console.error("[VueChatKit] 添加临时消息失败", c);
581
+ }
582
+ oe(m.value);
583
+ }
584
+ K();
585
+ }
586
+ }, Fe = () => {
587
+ const a = `${y.api.websocketUrl}?userId=${o}`;
588
+ s = new Dt(o, {
589
+ wsUrl: a,
590
+ maxReconnectAttempts: y.websocket.maxReconnectAttempts,
591
+ reconnectDelay: y.websocket.reconnectDelay
592
+ }), s.on("message", Ve), s.connect();
593
+ }, Re = () => {
594
+ s && (s.close(), s = null);
595
+ }, Ie = async () => {
596
+ N.value = !0, G.value = "", await Le();
597
+ }, Le = async () => {
598
+ Q.value = !0;
599
+ try {
600
+ const a = await e.getAvailableUsers(o);
601
+ J.value = (a == null ? void 0 : a.data) || [];
602
+ } catch (a) {
603
+ console.error("[VueChatKit] 获取可用用户失败", a);
604
+ } finally {
605
+ Q.value = !1;
606
+ }
607
+ }, Te = async (a) => {
608
+ try {
609
+ await e.addFriend(o, a.username), await K(), N.value = !1;
610
+ } catch (i) {
611
+ console.error("[VueChatKit] 添加好友失败", i);
612
+ }
613
+ }, Z = async () => {
614
+ te.value = !0;
615
+ try {
616
+ const a = await e.getApplyList(o);
617
+ le.value = a.data || [];
618
+ } catch (a) {
619
+ console.error("[VueChatKit] 获取好友申请列表失败", a);
620
+ } finally {
621
+ te.value = !1;
622
+ }
623
+ }, de = async (a) => {
624
+ try {
625
+ await e.agreeFriend(a, o), await Z(), await K();
626
+ } catch (i) {
627
+ console.error("[VueChatKit] 同意好友申请失败", i);
628
+ }
629
+ }, D = async () => {
630
+ try {
631
+ const a = await e.getUserAvatar(o);
632
+ a.code === 200 && a.data && (F.value = a.data);
633
+ } catch (a) {
634
+ console.warn("[VueChatKit] 加载头像失败", a);
635
+ }
636
+ }, M = (a) => {
637
+ F.value = a;
638
+ }, ue = async () => {
639
+ z.value = !0;
640
+ try {
641
+ const a = await e.getUserInfo(o);
642
+ a.code === 200 && a.data && (T.value = {
643
+ ...T.value,
644
+ ...a.data
645
+ });
646
+ } catch (a) {
647
+ console.error("[VueChatKit] 获取用户信息失败", a);
648
+ } finally {
649
+ z.value = !1;
650
+ }
651
+ }, H = async (a) => {
652
+ try {
653
+ return (await e.updateUserInfo(o, a)).code === 200 ? (T.value = {
654
+ ...T.value,
655
+ ...a
656
+ }, !0) : !1;
657
+ } catch (i) {
658
+ return console.error("[VueChatKit] 更新用户信息失败", i), !1;
659
+ }
660
+ }, W = () => {
661
+ m.value = "", V.value = [], C.value = "", _.value = "";
662
+ };
663
+ return D(), {
664
+ // 状态
665
+ myUsername: o,
666
+ myAvatar: F,
667
+ userInfo: T,
668
+ loadingUserInfo: z,
669
+ friendList: w,
670
+ chatList: U,
671
+ filteredFriendList: x,
672
+ chatMsgList: V,
673
+ currentSelectName: m,
674
+ searchText: _,
675
+ inputText: C,
676
+ messagesContainer: R,
677
+ filteredUsers: g,
678
+ filteredAvailableUsers: A,
679
+ currentUser: E,
680
+ currentMessages: ie,
681
+ addFriendDialogVisible: N,
682
+ addFriendSearchText: G,
683
+ availableUsers: J,
684
+ loadingAvailableUsers: Q,
685
+ friendApplyList: le,
686
+ loadingFriendApply: te,
687
+ // 方法
688
+ formatTime: P,
689
+ formatLastTime: he,
690
+ scrollToBottom: O,
691
+ getFriendList: K,
692
+ getChatHistory: oe,
693
+ setFriendToChatStatus: Ae,
694
+ selectUser: xe,
695
+ sendMessage: _e,
696
+ sendFile: be,
697
+ sendFilesAndText: Ce,
698
+ initWebSocket: Fe,
699
+ closeWebSocket: Re,
700
+ reset: W,
701
+ openAddFriendDialog: Ie,
702
+ addFriend: Te,
703
+ loadFriendApplyList: Z,
704
+ agreeFriend: de,
705
+ updateMyAvatar: M,
706
+ getUserInfo: ue,
707
+ updateUserInfo: H
708
+ };
709
+ }
710
+ const et = (y, e) => {
711
+ const s = y.__vccOpts || y;
712
+ for (const [o, F] of e)
713
+ s[o] = F;
714
+ return s;
715
+ }, Kt = { class: "avatar-crop-container" }, Wt = ["src"], Bt = { class: "crop-overlay" }, Nt = { class: "crop-box" }, Ht = {
716
+ key: 0,
717
+ class: "crop-mask"
718
+ }, qt = { class: "zoom-controls" }, Pt = {
719
+ __name: "AvatarCrop",
720
+ props: {
721
+ modelValue: { type: Boolean, default: !1 },
722
+ src: { type: String, default: "" }
723
+ },
724
+ emits: ["update:modelValue", "confirm"],
725
+ setup(y, { emit: e }) {
726
+ const s = y, o = e, F = re({
727
+ get: () => s.modelValue,
728
+ set: (g) => o("update:modelValue", g)
729
+ }), T = f(""), z = f(null), w = f(null), U = f(null), V = f(1), m = f({ x: 0, y: 0 }), _ = f(!1), C = f({ x: 0, y: 0 }), R = f({ width: 0, height: 0 });
730
+ yt(() => s.src, (g) => {
731
+ g && (T.value = g, V.value = 1, m.value = { x: 0, y: 0 });
732
+ });
733
+ const N = () => {
734
+ Ne(() => {
735
+ if (z.value && w.value) {
736
+ const g = z.value, x = w.value, A = Math.min(x.clientWidth, x.clientHeight);
737
+ g.naturalWidth > g.naturalHeight ? (R.value.height = A, R.value.width = g.naturalWidth / g.naturalHeight * A) : (R.value.width = A, R.value.height = g.naturalHeight / g.naturalWidth * A), m.value = {
738
+ x: (A - R.value.width) / 2,
739
+ y: (A - R.value.height) / 2
740
+ };
741
+ }
742
+ });
743
+ }, G = (g) => {
744
+ _.value = !0;
745
+ const x = g.touches ? g.touches[0].clientX : g.clientX, A = g.touches ? g.touches[0].clientY : g.clientY;
746
+ C.value = { x: x - m.value.x, y: A - m.value.y }, document.addEventListener("mousemove", J), document.addEventListener("mouseup", Q), document.addEventListener("touchmove", J), document.addEventListener("touchend", Q);
747
+ }, J = (g) => {
748
+ if (!_.value) return;
749
+ const x = g.touches ? g.touches[0].clientX : g.clientX, A = g.touches ? g.touches[0].clientY : g.clientY;
750
+ m.value = {
751
+ x: x - C.value.x,
752
+ y: A - C.value.y
753
+ };
754
+ }, Q = () => {
755
+ _.value = !1, document.removeEventListener("mousemove", J), document.removeEventListener("mouseup", Q), document.removeEventListener("touchmove", J), document.removeEventListener("touchend", Q);
756
+ }, le = () => {
757
+ const g = document.createElement("canvas"), x = g.getContext("2d"), A = 200;
758
+ g.width = A, g.height = A;
759
+ const E = z.value, ie = U.value, P = w.value;
760
+ if (E && ie && P) {
761
+ const he = ie.getBoundingClientRect(), ge = P.getBoundingClientRect(), ye = (he.left - ge.left - m.value.x) / V.value, O = (he.top - ge.top - m.value.y) / V.value, K = he.width / V.value;
762
+ x.drawImage(
763
+ E,
764
+ ye * (E.naturalWidth / R.value.width),
765
+ O * (E.naturalHeight / R.value.height),
766
+ K * (E.naturalWidth / R.value.width),
767
+ K * (E.naturalHeight / R.value.height),
768
+ 0,
769
+ 0,
770
+ A,
771
+ A
772
+ ), g.toBlob((oe) => {
773
+ o("confirm", { file: oe, url: g.toDataURL("image/png") }), F.value = !1;
774
+ }, "image/png");
775
+ }
776
+ }, te = () => {
777
+ T.value = "", V.value = 1, m.value = { x: 0, y: 0 };
778
+ };
779
+ return (g, x) => {
780
+ const A = ce("el-slider"), E = ce("el-button"), ie = ce("el-dialog");
781
+ return r(), q(ie, {
782
+ modelValue: F.value,
783
+ "onUpdate:modelValue": x[2] || (x[2] = (P) => F.value = P),
784
+ title: "裁剪头像",
785
+ width: "500px",
786
+ "close-on-click-modal": !1,
787
+ onClosed: te
788
+ }, {
789
+ footer: b(() => [
790
+ p(E, {
791
+ onClick: x[1] || (x[1] = (P) => F.value = !1)
792
+ }, {
793
+ default: b(() => [...x[3] || (x[3] = [
794
+ ne("取消", -1)
795
+ ])]),
796
+ _: 1
797
+ }),
798
+ p(E, {
799
+ type: "primary",
800
+ onClick: le
801
+ }, {
802
+ default: b(() => [...x[4] || (x[4] = [
803
+ ne("确定", -1)
804
+ ])]),
805
+ _: 1
806
+ })
807
+ ]),
808
+ default: b(() => [
809
+ t("div", Kt, [
810
+ t("div", {
811
+ class: "crop-area",
812
+ ref_key: "cropAreaRef",
813
+ ref: w
814
+ }, [
815
+ t("img", {
816
+ src: T.value,
817
+ ref_key: "imageRef",
818
+ ref: z,
819
+ class: "crop-image",
820
+ onLoad: N,
821
+ onMousedown: G,
822
+ onTouchstart: G
823
+ }, null, 40, Wt),
824
+ t("div", Bt, [
825
+ t("div", Nt, [
826
+ t("div", {
827
+ class: "crop-border",
828
+ ref_key: "cropBoxRef",
829
+ ref: U
830
+ }, null, 512)
831
+ ])
832
+ ]),
833
+ _.value ? (r(), v("div", Ht)) : I("", !0)
834
+ ], 512),
835
+ t("div", qt, [
836
+ p(A, {
837
+ modelValue: V.value,
838
+ "onUpdate:modelValue": x[0] || (x[0] = (P) => V.value = P),
839
+ min: 0.5,
840
+ max: 3,
841
+ step: 0.1,
842
+ "show-tooltip": !1
843
+ }, null, 8, ["modelValue"])
844
+ ])
845
+ ])
846
+ ]),
847
+ _: 1
848
+ }, 8, ["modelValue"]);
849
+ };
850
+ }
851
+ }, Ot = /* @__PURE__ */ et(Pt, [["__scopeId", "data-v-4e4a992b"]]), jt = { class: "chat-container" }, Xt = { class: "sidebar-nav" }, Yt = ["src"], Gt = ["onClick"], Jt = {
852
+ key: 0,
853
+ class: "nav-badge"
854
+ }, Qt = { class: "content-panel" }, Zt = { class: "search-bar" }, es = { class: "content-scroll" }, ts = { key: 0 }, ss = ["onClick", "onContextmenu"], as = { class: "friend-avatar-wrapper" }, ns = ["src", "alt"], ls = {
855
+ key: 0,
856
+ class: "online-indicator"
857
+ }, is = { class: "friend-info" }, os = { class: "friend-header" }, rs = { class: "friend-name" }, cs = { class: "last-time" }, ds = { class: "friend-preview" }, us = { class: "last-msg" }, vs = {
858
+ key: 0,
859
+ class: "unread-badge"
860
+ }, ps = { key: 1 }, fs = { class: "add-friend-section" }, ms = { class: "add-friend-icon" }, hs = ["onClick"], gs = { class: "friend-avatar-wrapper" }, ys = ["src", "alt"], _s = { class: "friend-info" }, bs = { class: "friend-name" }, Cs = { key: 2 }, ks = { class: "request-info" }, ws = ["src", "alt"], Us = { class: "request-details" }, xs = { class: "request-username" }, As = { class: "chat-area" }, Ss = {
861
+ key: 0,
862
+ class: "friend-profile"
863
+ }, Vs = ["src", "alt"], Fs = { class: "profile-name" }, Rs = { class: "profile-status" }, Is = {
864
+ key: 1,
865
+ class: "chat-window"
866
+ }, Ls = { class: "chat-header" }, Ts = { class: "chat-title" }, zs = { class: "chat-name" }, Ds = { class: "chat-actions" }, Ms = { class: "message-avatar" }, $s = ["src"], Es = {
867
+ key: 0,
868
+ class: "sender-name"
869
+ }, Ks = { class: "message-bubble-wrapper" }, Ws = ["onClick"], Bs = ["src", "alt"], Ns = {
870
+ key: 0,
871
+ class: "image-size"
872
+ }, Hs = ["onClick"], qs = { class: "file-content" }, Ps = { class: "file-icon" }, Os = { class: "file-info" }, js = { class: "file-name" }, Xs = { class: "file-meta" }, Ys = { key: 0 }, Gs = { class: "input-area" }, Js = {
873
+ key: 0,
874
+ class: "pending-files"
875
+ }, Qs = {
876
+ key: 0,
877
+ class: "pending-image-wrapper"
878
+ }, Zs = ["src", "alt"], ea = ["onClick"], ta = {
879
+ key: 1,
880
+ class: "pending-file-wrapper"
881
+ }, sa = { class: "pending-file-name" }, aa = ["onClick"], na = {
882
+ key: 1,
883
+ class: "input-actions"
884
+ }, la = { class: "input-wrapper" }, ia = ["onKeydown"], oa = { class: "send-btn-wrapper" }, ra = {
885
+ key: 2,
886
+ class: "empty-state"
887
+ }, ca = { class: "empty-text" }, da = {
888
+ key: 0,
889
+ class: "detail-panel"
890
+ }, ua = { class: "detail-content" }, va = { class: "detail-profile" }, pa = ["src", "alt"], fa = { class: "detail-name" }, ma = { class: "search-users-wrapper" }, ha = { class: "search-users-input" }, ga = { class: "users-list-scroll" }, ya = { class: "available-user-info" }, _a = ["src", "alt"], ba = { class: "available-user-name" }, Ca = { class: "settings-container" }, ka = { class: "settings-avatar-section" }, wa = { class: "settings-avatar-wrapper" }, Ua = ["src"], xa = { class: "settings-user-display" }, Aa = { class: "settings-nickname" }, Sa = { class: "settings-username" }, Va = { class: "settings-form-section" }, Fa = { class: "settings-form-header" }, Ra = { class: "settings-form-title" }, Ia = { class: "settings-form" }, La = { class: "settings-form-item" }, Ta = {
891
+ key: 1,
892
+ class: "settings-form-value"
893
+ }, za = { class: "settings-form-item" }, Da = {
894
+ key: 1,
895
+ class: "settings-form-value"
896
+ }, Ma = { class: "settings-form-item" }, $a = {
897
+ key: 1,
898
+ class: "settings-form-value"
899
+ }, Ea = { class: "settings-form-item" }, Ka = {
900
+ key: 1,
901
+ class: "settings-form-value bio-value"
902
+ }, Wa = {
903
+ key: 0,
904
+ class: "settings-form-actions"
905
+ }, Ba = {
906
+ __name: "ChatWindow",
907
+ props: {
908
+ modelValue: { type: Boolean, default: !1 },
909
+ config: { type: Object, required: !0 },
910
+ width: { type: [String, Number], default: "1100px" }
911
+ },
912
+ emits: ["update:modelValue", "open", "close", "message", "send", "error"],
913
+ setup(y, { emit: e }) {
914
+ const s = y, o = e, F = re({
915
+ get: () => s.modelValue,
916
+ set: (d) => o("update:modelValue", d)
917
+ }), {
918
+ myUsername: T,
919
+ myAvatar: z,
920
+ userInfo: w,
921
+ loadingUserInfo: U,
922
+ friendList: V,
923
+ filteredFriendList: m,
924
+ searchText: _,
925
+ inputText: C,
926
+ messagesContainer: R,
927
+ filteredUsers: N,
928
+ filteredAvailableUsers: G,
929
+ currentUser: J,
930
+ currentMessages: Q,
931
+ addFriendDialogVisible: le,
932
+ addFriendSearchText: te,
933
+ availableUsers: g,
934
+ loadingAvailableUsers: x,
935
+ friendApplyList: A,
936
+ loadingFriendApply: E,
937
+ formatTime: ie,
938
+ formatLastTime: P,
939
+ scrollToBottom: he,
940
+ getFriendList: ge,
941
+ getChatHistory: ye,
942
+ setFriendToChatStatus: O,
943
+ selectUser: K,
944
+ sendMessage: oe,
945
+ sendFile: He,
946
+ sendFilesAndText: xe,
947
+ initWebSocket: Ae,
948
+ closeWebSocket: _e,
949
+ reset: be,
950
+ openAddFriendDialog: Ce,
951
+ addFriend: Se,
952
+ loadFriendApplyList: Ve,
953
+ agreeFriend: Fe,
954
+ updateMyAvatar: Re,
955
+ getUserInfo: Ie,
956
+ updateUserInfo: Le
957
+ } = Et(s.config), Te = re(() => {
958
+ var l;
959
+ const d = [{ id: "chat", icon: Ee, badge: 0 }];
960
+ return s.config.modules.friends && d.push({ id: "friends", icon: Qe, badge: 0 }), s.config.modules.apply && d.push({ id: "apply", icon: At, badge: ((l = A.value) == null ? void 0 : l.length) || 0 }), d;
961
+ }), Z = f("chat"), de = f(null), D = f(null), M = f(null), ue = f(!1), H = f(!1), W = f({ nickname: "", email: "", phone: "", bio: "" }), a = f(!1), i = f(!1), c = f(!1), S = f(!1), se = f(null), ee = f(""), ve = f(null), B = f([]), pe = f({ visible: !1, x: 0, y: 0, chat: null }), ze = () => {
962
+ pe.value.visible = !1;
963
+ }, st = async () => {
964
+ if (!pe.value.chat) return;
965
+ await O(pe.value.chat.id, 0) && de.value === pe.value.chat.id && (de.value = null, D.value = null), ze();
966
+ }, De = (d) => {
967
+ de.value = d.id, D.value = d, M.value = null, ue.value = !1, K({
968
+ id: d.id,
969
+ name: d.name,
970
+ avatar: d.avatar,
971
+ online: d.online
972
+ });
973
+ }, at = (d) => {
974
+ M.value = d, de.value = null, D.value = null;
975
+ }, nt = async () => {
976
+ if (!M.value) return;
977
+ if (await O(M.value.id)) {
978
+ Z.value = "chat", await Ne();
979
+ const l = N.value.find((h) => h.id === M.value.id);
980
+ l && De(l), M.value = null;
981
+ }
982
+ }, lt = () => {
983
+ i.value = !0;
984
+ }, it = () => {
985
+ var d;
986
+ (d = se.value) == null || d.click();
987
+ }, ot = () => {
988
+ var d;
989
+ (d = ve.value) == null || d.click();
990
+ }, rt = (d) => {
991
+ const l = Array.from(d.target.files || []);
992
+ if (l.length !== 0) {
993
+ for (const h of l) {
994
+ if (h.size > 50 * 1024 * 1024) {
995
+ Y.warning(`文件 ${h.name} 超过50MB,已跳过`);
996
+ continue;
997
+ }
998
+ const L = URL.createObjectURL(h);
999
+ B.value.push({
1000
+ id: Date.now() + Math.random(),
1001
+ file: h,
1002
+ name: h.name,
1003
+ size: h.size,
1004
+ type: h.type,
1005
+ previewUrl: L,
1006
+ isImage: h.type.startsWith("image/")
1007
+ });
1008
+ }
1009
+ ve.value && (ve.value.value = "");
1010
+ }
1011
+ }, qe = (d) => {
1012
+ const l = B.value[d];
1013
+ l.previewUrl && URL.revokeObjectURL(l.previewUrl), B.value.splice(d, 1);
1014
+ }, Pe = (d) => {
1015
+ if (d === 0) return "0 B";
1016
+ const l = 1024, h = ["B", "KB", "MB", "GB"], L = Math.floor(Math.log(d) / Math.log(l));
1017
+ return parseFloat((d / Math.pow(l, L)).toFixed(2)) + " " + h[L];
1018
+ }, Oe = async () => {
1019
+ if (!C.value.trim() && B.value.length === 0) return;
1020
+ const d = [...B.value], l = C.value;
1021
+ C.value = "", B.value.forEach((h) => {
1022
+ h.previewUrl && URL.revokeObjectURL(h.previewUrl);
1023
+ }), B.value = [], await xe(d, l), o("send", { text: l, files: d });
1024
+ }, ct = (d) => {
1025
+ var h;
1026
+ const l = (h = d.clipboardData) == null ? void 0 : h.items;
1027
+ if (l) {
1028
+ for (const L of l)
1029
+ if (L.kind === "file") {
1030
+ const $ = L.getAsFile();
1031
+ if ($) {
1032
+ if ($.size > 50 * 1024 * 1024) {
1033
+ Y.warning(`文件 ${$.name} 超过50MB,已跳过`);
1034
+ continue;
1035
+ }
1036
+ const ae = URL.createObjectURL($);
1037
+ B.value.push({
1038
+ id: Date.now() + Math.random(),
1039
+ file: $,
1040
+ name: $.name,
1041
+ size: $.size,
1042
+ type: $.type,
1043
+ previewUrl: ae,
1044
+ isImage: $.type.startsWith("image/")
1045
+ });
1046
+ }
1047
+ }
1048
+ }
1049
+ }, je = (d) => {
1050
+ if (!d) {
1051
+ Y.warning("文件地址无效");
1052
+ return;
1053
+ }
1054
+ window.open(d, "_blank");
1055
+ }, dt = (d) => {
1056
+ console.warn("图片加载失败", d);
1057
+ }, ut = (d) => {
1058
+ const l = d.target.files[0];
1059
+ if (!l) return;
1060
+ if (!l.type.startsWith("image/")) {
1061
+ Y.error("只能上传图片文件");
1062
+ return;
1063
+ }
1064
+ if (l.size > 5 * 1024 * 1024) {
1065
+ Y.error("图片大小不能超过 5MB");
1066
+ return;
1067
+ }
1068
+ const h = new FileReader();
1069
+ h.onload = (L) => {
1070
+ ee.value = L.target.result, c.value = !0;
1071
+ }, h.readAsDataURL(l);
1072
+ }, vt = async ({ file: d }) => {
1073
+ if (d) {
1074
+ S.value = !0;
1075
+ try {
1076
+ const { ChatApi: l } = await Promise.resolve().then(() => $t), L = await new l(s.config).uploadAvatar(d, T);
1077
+ L.code === 200 ? (Y.success("头像上传成功"), Re(L.data), Xe()) : Y.error(L.msg || "头像上传失败");
1078
+ } catch (l) {
1079
+ console.error(l), Y.error("头像上传失败");
1080
+ } finally {
1081
+ S.value = !1;
1082
+ }
1083
+ }
1084
+ }, Xe = () => {
1085
+ ee.value = "", c.value = !1, se.value && (se.value.value = "");
1086
+ }, pt = () => {
1087
+ W.value = {
1088
+ nickname: w.value.nickname || "",
1089
+ email: w.value.email || "",
1090
+ phone: w.value.phone || "",
1091
+ bio: w.value.bio || ""
1092
+ }, H.value = !0;
1093
+ }, ft = () => {
1094
+ H.value = !1, W.value = { nickname: "", email: "", phone: "", bio: "" };
1095
+ }, mt = async () => {
1096
+ a.value = !0;
1097
+ try {
1098
+ await Le(W.value) ? (Y.success("保存成功"), H.value = !1) : Y.error("保存失败");
1099
+ } catch (d) {
1100
+ console.error(d), Y.error("保存失败");
1101
+ } finally {
1102
+ a.value = !1;
1103
+ }
1104
+ }, ht = () => {
1105
+ be(), _e(), ue.value = !1, i.value = !1, Xe(), H.value = !1, o("close");
1106
+ }, gt = async () => {
1107
+ await Promise.all([ge(), Ve(), Ie()]), Ae(), N.value.length > 0 && De(N.value[0]), o("open");
1108
+ };
1109
+ return _t(() => {
1110
+ document.addEventListener("click", ze);
1111
+ }), bt(() => {
1112
+ document.removeEventListener("click", ze), _e();
1113
+ }), (d, l) => {
1114
+ const h = ce("el-icon"), L = ce("el-input"), $ = ce("el-empty"), ae = ce("el-button"), Me = ce("el-dialog");
1115
+ return r(), q(Me, {
1116
+ modelValue: F.value,
1117
+ "onUpdate:modelValue": l[13] || (l[13] = (ke) => F.value = ke),
1118
+ width: y.width,
1119
+ "close-on-click-modal": !1,
1120
+ class: "chat-dialog",
1121
+ "append-to-body": "",
1122
+ onClosed: ht,
1123
+ onOpen: gt
1124
+ }, {
1125
+ default: b(() => {
1126
+ var ke, Ye, Ge;
1127
+ return [
1128
+ t("div", jt, [
1129
+ t("div", Xt, [
1130
+ t("div", {
1131
+ class: "sidebar-avatar",
1132
+ onClick: lt
1133
+ }, [
1134
+ t("img", {
1135
+ src: u(z),
1136
+ alt: "头像",
1137
+ class: "avatar-img"
1138
+ }, null, 8, Yt)
1139
+ ]),
1140
+ (r(!0), v(fe, null, me(Te.value, (n) => (r(), v("div", {
1141
+ key: n.id,
1142
+ class: X([
1143
+ "nav-item",
1144
+ Z.value === n.id ? "nav-item-active" : "nav-item-inactive"
1145
+ ]),
1146
+ onClick: (j) => Z.value = n.id
1147
+ }, [
1148
+ p(h, { size: 24 }, {
1149
+ default: b(() => [
1150
+ (r(), q(Ct(n.icon)))
1151
+ ]),
1152
+ _: 2
1153
+ }, 1024),
1154
+ n.badge ? (r(), v("span", Jt, k(n.badge > 99 ? "99+" : n.badge), 1)) : I("", !0)
1155
+ ], 10, Gt))), 128)),
1156
+ l[14] || (l[14] = t("div", { class: "nav-spacer" }, null, -1)),
1157
+ y.config.modules.settings ? (r(), v("div", {
1158
+ key: 0,
1159
+ class: "nav-item nav-item-inactive",
1160
+ onClick: l[0] || (l[0] = (n) => i.value = !0),
1161
+ title: "设置"
1162
+ }, [
1163
+ p(h, { size: 24 }, {
1164
+ default: b(() => [
1165
+ p(u(St))
1166
+ ]),
1167
+ _: 1
1168
+ })
1169
+ ])) : I("", !0)
1170
+ ]),
1171
+ t("div", Qt, [
1172
+ t("div", Zt, [
1173
+ p(L, {
1174
+ modelValue: u(_),
1175
+ "onUpdate:modelValue": l[1] || (l[1] = (n) => we(_) ? _.value = n : null),
1176
+ placeholder: "搜索",
1177
+ "prefix-icon": u(Ke)
1178
+ }, null, 8, ["modelValue", "prefix-icon"])
1179
+ ]),
1180
+ t("div", es, [
1181
+ Z.value === "chat" ? (r(), v("div", ts, [
1182
+ (r(!0), v(fe, null, me(u(N), (n) => (r(), v("div", {
1183
+ key: n.id,
1184
+ class: X([
1185
+ "chat-item",
1186
+ de.value === n.id ? "chat-item-active" : ""
1187
+ ]),
1188
+ onClick: (j) => De(n),
1189
+ onContextmenu: Je((j) => d.showContextMenu(j, n), ["prevent", "stop"])
1190
+ }, [
1191
+ t("div", as, [
1192
+ t("img", {
1193
+ src: n.avatar,
1194
+ alt: n.name,
1195
+ class: "friend-avatar"
1196
+ }, null, 8, ns),
1197
+ n.online ? (r(), v("span", ls)) : I("", !0)
1198
+ ]),
1199
+ t("div", is, [
1200
+ t("div", os, [
1201
+ t("span", rs, k(n.name), 1),
1202
+ t("span", cs, k(u(P)(n.lastTime)), 1)
1203
+ ]),
1204
+ t("div", ds, [
1205
+ t("span", us, k(n.lastMsg), 1),
1206
+ n.unread > 0 ? (r(), v("span", vs, k(n.unread > 99 ? "99+" : n.unread), 1)) : I("", !0)
1207
+ ])
1208
+ ])
1209
+ ], 42, ss))), 128))
1210
+ ])) : I("", !0),
1211
+ Z.value === "friends" && y.config.modules.friends ? (r(), v("div", ps, [
1212
+ t("div", fs, [
1213
+ t("div", {
1214
+ class: "add-friend-btn",
1215
+ onClick: l[2] || (l[2] = (...n) => u(Ce) && u(Ce)(...n))
1216
+ }, [
1217
+ t("div", ms, [
1218
+ p(h, {
1219
+ class: "text-white",
1220
+ size: 20
1221
+ }, {
1222
+ default: b(() => [
1223
+ p(u(Vt))
1224
+ ]),
1225
+ _: 1
1226
+ })
1227
+ ]),
1228
+ l[15] || (l[15] = t("span", { class: "add-friend-text" }, "添加好友", -1))
1229
+ ])
1230
+ ]),
1231
+ (r(!0), v(fe, null, me(u(m), (n) => (r(), v("div", {
1232
+ key: n.id,
1233
+ class: "chat-item",
1234
+ onClick: (j) => at(n)
1235
+ }, [
1236
+ t("div", gs, [
1237
+ t("img", {
1238
+ src: n.avatar,
1239
+ alt: n.name,
1240
+ class: "friend-avatar"
1241
+ }, null, 8, ys),
1242
+ t("span", {
1243
+ class: X([
1244
+ "online-indicator",
1245
+ n.online ? "online" : "offline"
1246
+ ])
1247
+ }, null, 2)
1248
+ ]),
1249
+ t("div", _s, [
1250
+ t("span", bs, k(n.name), 1)
1251
+ ])
1252
+ ], 8, hs))), 128))
1253
+ ])) : I("", !0),
1254
+ Z.value === "apply" && y.config.modules.apply ? (r(), v("div", Cs, [
1255
+ u(E) ? (r(), q($, {
1256
+ key: 0,
1257
+ description: "加载中..."
1258
+ })) : u(A).length === 0 ? (r(), q($, {
1259
+ key: 1,
1260
+ description: "暂无好友申请"
1261
+ })) : (r(!0), v(fe, { key: 2 }, me(u(A), (n) => (r(), v("div", {
1262
+ key: n.applyUser || n.id,
1263
+ class: "friend-request-item"
1264
+ }, [
1265
+ t("div", ks, [
1266
+ t("img", {
1267
+ src: `https://api.dicebear.com/7.x/avataaars/svg?seed=${n.applyUser}`,
1268
+ alt: n.applyUser,
1269
+ class: "request-avatar"
1270
+ }, null, 8, ws),
1271
+ t("div", Us, [
1272
+ t("div", xs, k(n.applyUser), 1),
1273
+ l[16] || (l[16] = t("div", { class: "request-desc" }, "请求添加你为好友", -1))
1274
+ ])
1275
+ ]),
1276
+ p(ae, {
1277
+ type: "primary",
1278
+ size: "small",
1279
+ onClick: (j) => u(Fe)(n.applyUser)
1280
+ }, {
1281
+ default: b(() => [...l[17] || (l[17] = [
1282
+ ne("同意", -1)
1283
+ ])]),
1284
+ _: 1
1285
+ }, 8, ["onClick"])
1286
+ ]))), 128))
1287
+ ])) : I("", !0)
1288
+ ])
1289
+ ]),
1290
+ t("div", As, [
1291
+ M.value && !D.value ? (r(), v("div", Ss, [
1292
+ t("img", {
1293
+ src: M.value.avatar,
1294
+ alt: M.value.name,
1295
+ class: "profile-avatar"
1296
+ }, null, 8, Vs),
1297
+ t("div", Fs, k(M.value.name), 1),
1298
+ t("div", Rs, [
1299
+ t("span", {
1300
+ class: X([
1301
+ "status-dot",
1302
+ M.value.online ? "status-online" : "status-offline"
1303
+ ])
1304
+ }, null, 2),
1305
+ t("span", null, k(M.value.online ? "在线" : "离线"), 1)
1306
+ ]),
1307
+ p(ae, {
1308
+ type: "primary",
1309
+ size: "large",
1310
+ onClick: nt,
1311
+ class: "start-chat-btn"
1312
+ }, {
1313
+ default: b(() => [
1314
+ p(h, null, {
1315
+ default: b(() => [
1316
+ p(u(Ee))
1317
+ ]),
1318
+ _: 1
1319
+ }),
1320
+ l[18] || (l[18] = t("span", null, "发消息", -1))
1321
+ ]),
1322
+ _: 1
1323
+ })
1324
+ ])) : I("", !0),
1325
+ D.value ? (r(), v("div", Is, [
1326
+ t("div", Ls, [
1327
+ t("div", Ts, [
1328
+ t("span", zs, k(D.value.name), 1),
1329
+ t("span", {
1330
+ class: X([
1331
+ "status-badge",
1332
+ D.value.online ? "status-badge-online" : "status-badge-offline"
1333
+ ])
1334
+ }, k(D.value.online ? "在线" : "离线"), 3)
1335
+ ]),
1336
+ t("div", Ds, [
1337
+ p(h, { class: "action-icon" }, {
1338
+ default: b(() => [
1339
+ p(u(Ke))
1340
+ ]),
1341
+ _: 1
1342
+ }),
1343
+ p(h, {
1344
+ class: "action-icon",
1345
+ onClick: l[3] || (l[3] = (n) => ue.value = !ue.value)
1346
+ }, {
1347
+ default: b(() => [
1348
+ p(u(Ft))
1349
+ ]),
1350
+ _: 1
1351
+ })
1352
+ ])
1353
+ ]),
1354
+ t("div", {
1355
+ ref_key: "messagesContainer",
1356
+ ref: R,
1357
+ class: "messages-container"
1358
+ }, [
1359
+ (r(!0), v(fe, null, me(u(Q), (n, j) => (r(), v("div", {
1360
+ key: j,
1361
+ class: X([
1362
+ "message-wrapper",
1363
+ n.isSelf ? "message-self" : "message-other"
1364
+ ])
1365
+ }, [
1366
+ t("div", Ms, [
1367
+ t("img", {
1368
+ src: n.isSelf ? u(z) : D.value.avatar,
1369
+ class: "avatar-sm"
1370
+ }, null, 8, $s)
1371
+ ]),
1372
+ t("div", {
1373
+ class: X([
1374
+ "message-content-wrapper",
1375
+ n.isSelf ? "content-self" : "content-other"
1376
+ ])
1377
+ }, [
1378
+ n.isSelf ? I("", !0) : (r(), v("div", Es, k(D.value.name), 1)),
1379
+ t("div", Ks, [
1380
+ n.type === "text" ? (r(), v("div", {
1381
+ key: 0,
1382
+ class: X([
1383
+ "message-bubble",
1384
+ n.isSelf ? "bubble-self" : "bubble-other"
1385
+ ])
1386
+ }, k(n.text), 3)) : n.type === "file" && n.fileType === "image" ? (r(), v("div", {
1387
+ key: 1,
1388
+ class: X([
1389
+ "message-bubble",
1390
+ "image-bubble",
1391
+ n.isSelf ? "bubble-self" : "bubble-other"
1392
+ ]),
1393
+ onClick: ($e) => je(n.fileUrl)
1394
+ }, [
1395
+ t("img", {
1396
+ src: n.fileUrl,
1397
+ alt: n.fileName,
1398
+ class: "message-image",
1399
+ onError: dt
1400
+ }, null, 40, Bs),
1401
+ n.fileSize ? (r(), v("div", Ns, k(Pe(n.fileSize)), 1)) : I("", !0)
1402
+ ], 10, Ws)) : n.type === "file" ? (r(), v("div", {
1403
+ key: 2,
1404
+ class: X([
1405
+ "message-bubble",
1406
+ "file-bubble",
1407
+ n.isSelf ? "bubble-self" : "bubble-other"
1408
+ ]),
1409
+ onClick: ($e) => je(n.fileUrl)
1410
+ }, [
1411
+ t("div", qs, [
1412
+ t("div", Ps, [
1413
+ p(h, { size: 28 }, {
1414
+ default: b(() => [
1415
+ p(u(Rt))
1416
+ ]),
1417
+ _: 1
1418
+ })
1419
+ ]),
1420
+ t("div", Os, [
1421
+ t("div", js, k(n.fileName || n.text), 1),
1422
+ t("div", Xs, [
1423
+ p(h, { size: 12 }, {
1424
+ default: b(() => [
1425
+ p(u(It))
1426
+ ]),
1427
+ _: 1
1428
+ }),
1429
+ l[19] || (l[19] = t("span", null, "点击下载", -1)),
1430
+ n.fileSize ? (r(), v("span", Ys, "· " + k(Pe(n.fileSize)), 1)) : I("", !0)
1431
+ ])
1432
+ ])
1433
+ ])
1434
+ ], 10, Hs)) : I("", !0),
1435
+ t("div", {
1436
+ class: X([
1437
+ "message-time",
1438
+ n.isSelf ? "time-right" : "time-left"
1439
+ ])
1440
+ }, k(u(ie)(n.time)), 3)
1441
+ ])
1442
+ ], 2)
1443
+ ], 2))), 128))
1444
+ ], 512),
1445
+ t("div", Gs, [
1446
+ B.value.length > 0 ? (r(), v("div", Js, [
1447
+ (r(!0), v(fe, null, me(B.value, (n, j) => (r(), v("div", {
1448
+ key: n.id,
1449
+ class: "pending-file"
1450
+ }, [
1451
+ n.isImage ? (r(), v("div", Qs, [
1452
+ t("img", {
1453
+ src: n.previewUrl,
1454
+ alt: n.name,
1455
+ class: "pending-image"
1456
+ }, null, 8, Zs),
1457
+ t("button", {
1458
+ onClick: ($e) => qe(j),
1459
+ class: "remove-file-btn"
1460
+ }, " × ", 8, ea)
1461
+ ])) : (r(), v("div", ta, [
1462
+ p(h, { class: "pending-file-icon" }, {
1463
+ default: b(() => [
1464
+ p(u(Ze))
1465
+ ]),
1466
+ _: 1
1467
+ }),
1468
+ t("span", sa, k(n.name), 1),
1469
+ t("button", {
1470
+ onClick: ($e) => qe(j),
1471
+ class: "remove-file-btn"
1472
+ }, " × ", 8, aa)
1473
+ ]))
1474
+ ]))), 128))
1475
+ ])) : I("", !0),
1476
+ y.config.modules.fileUpload ? (r(), v("div", na, [
1477
+ p(h, { class: "action-icon" }, {
1478
+ default: b(() => [
1479
+ p(u(Ee))
1480
+ ]),
1481
+ _: 1
1482
+ }),
1483
+ p(h, {
1484
+ class: "action-icon",
1485
+ onClick: ot
1486
+ }, {
1487
+ default: b(() => [
1488
+ p(u(Ze))
1489
+ ]),
1490
+ _: 1
1491
+ }),
1492
+ p(h, { class: "action-icon" }, {
1493
+ default: b(() => [
1494
+ p(u(Lt))
1495
+ ]),
1496
+ _: 1
1497
+ })
1498
+ ])) : I("", !0),
1499
+ t("div", la, [
1500
+ kt(t("textarea", {
1501
+ "onUpdate:modelValue": l[4] || (l[4] = (n) => we(C) ? C.value = n : null),
1502
+ onKeydown: wt(Je(Oe, ["prevent"]), ["enter"]),
1503
+ onPaste: ct,
1504
+ placeholder: "输入消息或粘贴文件...",
1505
+ class: "message-input",
1506
+ rows: "3"
1507
+ }, null, 40, ia), [
1508
+ [Ut, u(C)]
1509
+ ])
1510
+ ]),
1511
+ t("div", oa, [
1512
+ p(ae, {
1513
+ type: "primary",
1514
+ disabled: !u(C).trim() && B.value.length === 0,
1515
+ onClick: Oe,
1516
+ class: "send-btn"
1517
+ }, {
1518
+ default: b(() => [...l[20] || (l[20] = [
1519
+ ne(" 发送 ", -1)
1520
+ ])]),
1521
+ _: 1
1522
+ }, 8, ["disabled"])
1523
+ ]),
1524
+ t("input", {
1525
+ ref_key: "fileInputRef",
1526
+ ref: ve,
1527
+ type: "file",
1528
+ multiple: "",
1529
+ class: "hidden-file-input",
1530
+ onChange: rt
1531
+ }, null, 544)
1532
+ ])
1533
+ ])) : M.value ? I("", !0) : (r(), v("div", ra, [
1534
+ p(h, {
1535
+ size: 64,
1536
+ class: "empty-icon"
1537
+ }, {
1538
+ default: b(() => [
1539
+ p(u(Tt))
1540
+ ]),
1541
+ _: 1
1542
+ }),
1543
+ t("div", ca, k(Z.value === "apply" ? "在左侧选择好友申请" : "在左侧选择好友开始聊天"), 1)
1544
+ ]))
1545
+ ]),
1546
+ ue.value ? (r(), v("div", da, [
1547
+ l[22] || (l[22] = t("div", { class: "detail-header" }, "聊天详情", -1)),
1548
+ t("div", ua, [
1549
+ t("div", va, [
1550
+ t("img", {
1551
+ src: (ke = D.value) == null ? void 0 : ke.avatar,
1552
+ alt: (Ye = D.value) == null ? void 0 : Ye.name,
1553
+ class: "detail-avatar"
1554
+ }, null, 8, pa),
1555
+ t("div", fa, k((Ge = D.value) == null ? void 0 : Ge.name), 1),
1556
+ l[21] || (l[21] = t("div", { class: "detail-actions" }, [
1557
+ t("div", { class: "detail-action-item" }, "查找聊天记录"),
1558
+ t("div", { class: "detail-action-item" }, "清空聊天记录")
1559
+ ], -1))
1560
+ ])
1561
+ ])
1562
+ ])) : I("", !0)
1563
+ ]),
1564
+ p(Me, {
1565
+ modelValue: u(le),
1566
+ "onUpdate:modelValue": l[6] || (l[6] = (n) => we(le) ? le.value = n : null),
1567
+ title: "添加好友",
1568
+ width: "500px",
1569
+ "append-to-body": ""
1570
+ }, {
1571
+ default: b(() => [
1572
+ t("div", ma, [
1573
+ t("div", ha, [
1574
+ p(L, {
1575
+ modelValue: u(te),
1576
+ "onUpdate:modelValue": l[5] || (l[5] = (n) => we(te) ? te.value = n : null),
1577
+ placeholder: "搜索用户",
1578
+ "prefix-icon": u(Ke)
1579
+ }, null, 8, ["modelValue", "prefix-icon"])
1580
+ ])
1581
+ ]),
1582
+ t("div", ga, [
1583
+ u(x) ? (r(), q($, {
1584
+ key: 0,
1585
+ description: "加载中..."
1586
+ })) : u(G).length === 0 ? (r(), q($, {
1587
+ key: 1,
1588
+ description: "暂无用户"
1589
+ })) : (r(!0), v(fe, { key: 2 }, me(u(G), (n) => (r(), v("div", {
1590
+ key: n.username,
1591
+ class: "available-user-item"
1592
+ }, [
1593
+ t("div", ya, [
1594
+ t("img", {
1595
+ src: `https://api.dicebear.com/7.x/avataaars/svg?seed=${n.username}`,
1596
+ alt: n.username,
1597
+ class: "available-user-avatar"
1598
+ }, null, 8, _a),
1599
+ t("div", ba, k(n.username), 1)
1600
+ ]),
1601
+ p(ae, {
1602
+ type: "primary",
1603
+ size: "small",
1604
+ onClick: (j) => u(Se)(n)
1605
+ }, {
1606
+ default: b(() => [...l[23] || (l[23] = [
1607
+ ne("添加", -1)
1608
+ ])]),
1609
+ _: 1
1610
+ }, 8, ["onClick"])
1611
+ ]))), 128))
1612
+ ])
1613
+ ]),
1614
+ _: 1
1615
+ }, 8, ["modelValue"]),
1616
+ p(Me, {
1617
+ modelValue: i.value,
1618
+ "onUpdate:modelValue": l[11] || (l[11] = (n) => i.value = n),
1619
+ title: "个人设置",
1620
+ width: "560px",
1621
+ "close-on-click-modal": !1,
1622
+ "append-to-body": "",
1623
+ class: "settings-dialog"
1624
+ }, {
1625
+ default: b(() => [
1626
+ t("div", Ca, [
1627
+ t("div", ka, [
1628
+ t("div", wa, [
1629
+ t("img", {
1630
+ src: u(z),
1631
+ alt: "头像",
1632
+ class: "settings-avatar"
1633
+ }, null, 8, Ua),
1634
+ y.config.modules.avatarCrop ? (r(), v("div", {
1635
+ key: 0,
1636
+ class: "settings-avatar-edit",
1637
+ onClick: it
1638
+ }, [
1639
+ p(h, {
1640
+ size: 18,
1641
+ class: "settings-avatar-icon"
1642
+ }, {
1643
+ default: b(() => [
1644
+ p(u(zt))
1645
+ ]),
1646
+ _: 1
1647
+ })
1648
+ ])) : I("", !0),
1649
+ t("input", {
1650
+ ref_key: "avatarInputRef",
1651
+ ref: se,
1652
+ type: "file",
1653
+ accept: "image/*",
1654
+ class: "hidden-avatar-input",
1655
+ onChange: ut
1656
+ }, null, 544)
1657
+ ]),
1658
+ t("div", xa, [
1659
+ t("div", Aa, k(u(w).nickname || u(T)), 1),
1660
+ t("div", Sa, "@" + k(u(T)), 1)
1661
+ ])
1662
+ ]),
1663
+ t("div", Va, [
1664
+ t("div", Fa, [
1665
+ t("div", Ra, [
1666
+ p(h, null, {
1667
+ default: b(() => [
1668
+ p(u(Qe))
1669
+ ]),
1670
+ _: 1
1671
+ }),
1672
+ l[24] || (l[24] = ne(" 个人信息 ", -1))
1673
+ ]),
1674
+ H.value ? I("", !0) : (r(), q(ae, {
1675
+ key: 0,
1676
+ type: "primary",
1677
+ size: "small",
1678
+ onClick: pt,
1679
+ class: "settings-edit-btn"
1680
+ }, {
1681
+ default: b(() => [...l[25] || (l[25] = [
1682
+ ne(" 编辑 ", -1)
1683
+ ])]),
1684
+ _: 1
1685
+ }))
1686
+ ]),
1687
+ t("div", Ia, [
1688
+ t("div", La, [
1689
+ l[26] || (l[26] = t("label", { class: "settings-form-label" }, "昵称", -1)),
1690
+ H.value ? (r(), q(L, {
1691
+ key: 0,
1692
+ modelValue: W.value.nickname,
1693
+ "onUpdate:modelValue": l[7] || (l[7] = (n) => W.value.nickname = n),
1694
+ placeholder: "请输入昵称",
1695
+ size: "large"
1696
+ }, null, 8, ["modelValue"])) : (r(), v("div", Ta, k(u(w).nickname || "未设置"), 1))
1697
+ ]),
1698
+ t("div", za, [
1699
+ l[27] || (l[27] = t("label", { class: "settings-form-label" }, "邮箱", -1)),
1700
+ H.value ? (r(), q(L, {
1701
+ key: 0,
1702
+ modelValue: W.value.email,
1703
+ "onUpdate:modelValue": l[8] || (l[8] = (n) => W.value.email = n),
1704
+ placeholder: "请输入邮箱",
1705
+ size: "large"
1706
+ }, null, 8, ["modelValue"])) : (r(), v("div", Da, k(u(w).email || "未设置"), 1))
1707
+ ]),
1708
+ t("div", Ma, [
1709
+ l[28] || (l[28] = t("label", { class: "settings-form-label" }, "手机号", -1)),
1710
+ H.value ? (r(), q(L, {
1711
+ key: 0,
1712
+ modelValue: W.value.phone,
1713
+ "onUpdate:modelValue": l[9] || (l[9] = (n) => W.value.phone = n),
1714
+ placeholder: "请输入手机号",
1715
+ size: "large"
1716
+ }, null, 8, ["modelValue"])) : (r(), v("div", $a, k(u(w).phone || "未设置"), 1))
1717
+ ]),
1718
+ t("div", Ea, [
1719
+ l[29] || (l[29] = t("label", { class: "settings-form-label" }, "个人简介", -1)),
1720
+ H.value ? (r(), q(L, {
1721
+ key: 0,
1722
+ modelValue: W.value.bio,
1723
+ "onUpdate:modelValue": l[10] || (l[10] = (n) => W.value.bio = n),
1724
+ type: "textarea",
1725
+ rows: 4,
1726
+ placeholder: "介绍一下自己吧...",
1727
+ size: "large"
1728
+ }, null, 8, ["modelValue"])) : (r(), v("div", Ka, k(u(w).bio || "这个人很懒,什么都没写~"), 1))
1729
+ ]),
1730
+ H.value ? (r(), v("div", Wa, [
1731
+ p(ae, {
1732
+ size: "default",
1733
+ onClick: ft
1734
+ }, {
1735
+ default: b(() => [...l[30] || (l[30] = [
1736
+ ne("取消", -1)
1737
+ ])]),
1738
+ _: 1
1739
+ }),
1740
+ p(ae, {
1741
+ type: "primary",
1742
+ size: "default",
1743
+ loading: a.value,
1744
+ onClick: mt
1745
+ }, {
1746
+ default: b(() => [...l[31] || (l[31] = [
1747
+ ne("保存更改", -1)
1748
+ ])]),
1749
+ _: 1
1750
+ }, 8, ["loading"])
1751
+ ])) : I("", !0)
1752
+ ])
1753
+ ])
1754
+ ])
1755
+ ]),
1756
+ _: 1
1757
+ }, 8, ["modelValue"]),
1758
+ p(Ot, {
1759
+ modelValue: c.value,
1760
+ "onUpdate:modelValue": l[12] || (l[12] = (n) => c.value = n),
1761
+ src: ee.value,
1762
+ onConfirm: vt
1763
+ }, null, 8, ["modelValue", "src"]),
1764
+ pe.value.visible ? (r(), v("div", {
1765
+ key: 0,
1766
+ class: "context-menu",
1767
+ style: xt({ left: pe.value.x + "px", top: pe.value.y + "px" })
1768
+ }, [
1769
+ t("div", {
1770
+ class: "context-menu-item",
1771
+ onClick: st
1772
+ }, "删除聊天")
1773
+ ], 4)) : I("", !0)
1774
+ ];
1775
+ }),
1776
+ _: 1
1777
+ }, 8, ["modelValue", "width"]);
1778
+ };
1779
+ }
1780
+ }, ja = /* @__PURE__ */ et(Ba, [["__scopeId", "data-v-a76a4ef3"]]), Na = {
1781
+ // API 配置
1782
+ api: {
1783
+ baseUrl: "",
1784
+ websocketUrl: "",
1785
+ endpoints: {
1786
+ getFriends: "/chart/friends",
1787
+ getHistory: "/chart/history",
1788
+ setRead: "/chart/read",
1789
+ uploadFile: "/chart/upload/file",
1790
+ addFriend: "/chart/friend/add",
1791
+ getApplyList: "/chart/friend/applyList",
1792
+ agreeFriend: "/chart/friend/agree",
1793
+ setChatStatus: "/chart/friend/chat/status",
1794
+ getAvailableUsers: "/chart/user/canAddFriend",
1795
+ getUserInfo: "/user/info",
1796
+ updateUserInfo: "/user/info",
1797
+ getUserAvatar: "/user/getAvatar",
1798
+ uploadAvatar: "/user/uploadAvatar"
1799
+ },
1800
+ adapter: null
1801
+ },
1802
+ // 用户信息
1803
+ user: {
1804
+ username: "",
1805
+ avatar: "",
1806
+ nickname: "",
1807
+ email: "",
1808
+ phone: "",
1809
+ bio: ""
1810
+ },
1811
+ // 模块开关
1812
+ modules: {
1813
+ friends: !0,
1814
+ apply: !0,
1815
+ settings: !0,
1816
+ fileUpload: !0,
1817
+ avatarCrop: !0
1818
+ },
1819
+ // 主题配置
1820
+ theme: {
1821
+ primaryColor: "#07c160",
1822
+ selfMessageBg: "#95ec69",
1823
+ otherMessageBg: "#ffffff"
1824
+ },
1825
+ // 自定义请求头
1826
+ headers: {},
1827
+ // WebSocket 配置
1828
+ websocket: {
1829
+ maxReconnectAttempts: 5,
1830
+ reconnectDelay: 3e3
1831
+ },
1832
+ // 文件配置
1833
+ file: {
1834
+ maxSize: 50 * 1024 * 1024,
1835
+ // 50MB
1836
+ allowedTypes: ["*"]
1837
+ }
1838
+ };
1839
+ function Xa(y = {}) {
1840
+ const e = tt(Na, y);
1841
+ return e.api.baseUrl || console.warn("[VueChatKit] 请配置 api.baseUrl"), e.api.websocketUrl || console.warn("[VueChatKit] 请配置 api.websocketUrl"), e.user.username || console.warn("[VueChatKit] 请配置 user.username"), e;
1842
+ }
1843
+ function tt(y, e) {
1844
+ const s = { ...y };
1845
+ for (const o in e)
1846
+ e[o] && typeof e[o] == "object" && !Array.isArray(e[o]) ? s[o] = tt(y[o] || {}, e[o]) : s[o] = e[o];
1847
+ return s;
1848
+ }
1849
+ const Ya = {
1850
+ install(y) {
1851
+ y.component("ChatWindow", ChatWindow), y.component("AvatarCrop", AvatarCrop);
1852
+ }
1853
+ };
1854
+ export {
1855
+ Ot as AvatarCrop,
1856
+ Be as ChatApi,
1857
+ Dt as ChatWebSocket,
1858
+ ja as ChatWindow,
1859
+ Mt as HttpClient,
1860
+ Ya as VueChatKit,
1861
+ Xa as createChatConfig,
1862
+ Ya as default,
1863
+ Et as useChat
1864
+ };