vue-chat-kit 0.1.1 → 0.1.2

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