@billtaofbj/explosion-image 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2298 @@
1
+ import { Fragment as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, h as l, nextTick as u, normalizeClass as d, normalizeStyle as f, onMounted as p, onUnmounted as m, openBlock as h, reactive as g, ref as _, renderList as v, resolveComponent as y, resolveDynamicComponent as b, toDisplayString as x, unref as S, watch as C, withCtx as w, withKeys as T, withModifiers as E } from "vue";
2
+ import { BrandWatermark as D } from "@billtaofbj/core";
3
+ import { useRoute as O, useRouter as k } from "vue-router";
4
+ import { ElMessage as A, ElMessageBox as j } from "element-plus";
5
+ import { ArrowDown as M, ArrowLeft as N, Bell as P, Brush as F, Clock as I, Close as L, Connection as R, Delete as z, Download as B, InfoFilled as V, Link as H, Loading as ee, Location as U, Minus as W, Monitor as G, MoreFilled as K, Plus as te, Promotion as ne, Right as re, SemiSelect as q, Share as ie, TrendCharts as J, Upload as ae, UploadFilled as oe } from "@element-plus/icons-vue";
6
+ import Y from "axios";
7
+ import * as X from "yjs";
8
+ import { HocuspocusProvider as se } from "@hocuspocus/provider";
9
+ //#region \0plugin-vue:export-helper
10
+ var Z = (e, t) => {
11
+ let n = e.__vccOpts || e;
12
+ for (let [e, r] of t) n[e] = r;
13
+ return n;
14
+ }, ce = { class: "chat-header" }, le = { class: "chat-header-left" }, ue = { class: "chat-title" }, Q = { class: "online-users-list" }, de = { class: "online-user-item" }, fe = { class: "online-user-name" }, pe = { key: 1 }, me = { class: "online-user-name" }, he = { class: "chat-header-right" }, ge = {
15
+ key: 0,
16
+ class: "chat-empty"
17
+ }, _e = { class: "chat-empty-hint" }, ve = { key: 1 }, ye = { class: "message-content" }, be = {
18
+ key: 0,
19
+ class: "message-meta"
20
+ }, $ = {
21
+ key: 0,
22
+ class: "message-mention"
23
+ }, xe = ["innerHTML"], Se = { class: "message-time" }, Ce = {
24
+ key: 1,
25
+ class: "chat-message chat-message-ai"
26
+ }, we = { class: "message-avatar ai" }, Te = { class: "chat-input-area" }, Ee = {
27
+ key: 0,
28
+ class: "mention-popup"
29
+ }, De = ["onClick", "onMouseenter"], Oe = { key: 1 }, ke = /*#__PURE__*/ Z({
30
+ __name: "AiChatPanel",
31
+ props: {
32
+ visible: {
33
+ type: Boolean,
34
+ default: !1
35
+ },
36
+ messages: {
37
+ type: Array,
38
+ default: () => []
39
+ },
40
+ loading: {
41
+ type: Boolean,
42
+ default: !1
43
+ },
44
+ panelWidth: {
45
+ type: Number,
46
+ default: 360
47
+ },
48
+ isCollab: {
49
+ type: Boolean,
50
+ default: !1
51
+ },
52
+ collabUsers: {
53
+ type: Array,
54
+ default: () => []
55
+ },
56
+ currentUser: {
57
+ type: Object,
58
+ default: () => ({
59
+ id: "",
60
+ name: "",
61
+ color: ""
62
+ })
63
+ },
64
+ isOwner: {
65
+ type: Boolean,
66
+ default: !0
67
+ },
68
+ unreadMention: {
69
+ type: Boolean,
70
+ default: !1
71
+ }
72
+ },
73
+ emits: [
74
+ "send",
75
+ "close",
76
+ "clear",
77
+ "clear-unread"
78
+ ],
79
+ setup(c, { emit: l }) {
80
+ let p = c, m = l, g = _(""), b = _(null), D = _(null), O = _(!1), k = _([]), A = _(0), j = "", M = -1, N = {
81
+ id: "ai-assistant",
82
+ name: "AI助手",
83
+ color: "#409EFF",
84
+ isAi: !0
85
+ }, F = t(() => {
86
+ let e = p.currentUser.id, t = /* @__PURE__ */ new Set();
87
+ return [N, ...p.collabUsers.filter((n) => {
88
+ let r = n.clientId || n.id || "";
89
+ if (r && r === e) return !1;
90
+ let i = String(r || n.name || "");
91
+ return t.has(i) ? !1 : (t.add(i), !0);
92
+ })];
93
+ }), I = t(() => F.value.length + 1), R = (e) => e.role === "ai" ? "chat-message-ai" : p.isCollab && e.user_id && e.user_id !== p.currentUser.id ? "chat-message-other" : "chat-message-user", B = (e) => e.role === "ai" ? { background: "linear-gradient(135deg, #409EFF, #337ECC)" } : { background: e.user_color || "#67C23A" }, V = (e) => (e.user_name || "U").charAt(0), H = (e) => {
94
+ if (!p.isCollab) return;
95
+ let t = typeof e == "string" ? e : e.target?.value || g.value, n = t.length, r = t.lastIndexOf("@", n);
96
+ if (r !== -1 && r < n) {
97
+ let e = t.slice(r + 1, n);
98
+ if (!e.includes(" ") && !e.includes("\n")) {
99
+ j = e, M = r, k.value = F.value.filter((t) => t.name && t.name.toLowerCase().includes(e.toLowerCase())), O.value = k.value.length > 0, A.value = 0;
100
+ return;
101
+ }
102
+ }
103
+ O.value = !1;
104
+ }, ee = () => {
105
+ O.value && (A.value = Math.min(A.value + 1, k.value.length - 1));
106
+ }, U = () => {
107
+ O.value && (A.value = Math.max(A.value - 1, 0));
108
+ }, W = (e) => {
109
+ let t = g.value.slice(0, M), n = g.value.slice(M + j.length + 1);
110
+ g.value = `${t}@${e.name} ${n}`, O.value = !1;
111
+ }, K = (e) => {
112
+ if (e) {
113
+ if (e.shiftKey) return;
114
+ if (O.value) {
115
+ let t = k.value[A.value];
116
+ if (t) {
117
+ e.preventDefault(), W(t);
118
+ return;
119
+ }
120
+ }
121
+ e.preventDefault();
122
+ }
123
+ let t = g.value.trim();
124
+ if (!t || p.loading) return;
125
+ let n = null;
126
+ if (p.isCollab) {
127
+ let e = t.match(/@(\S+)/);
128
+ e && (n = e[1]);
129
+ }
130
+ m("send", t, { mentionedUser: n }), g.value = "", O.value = !1;
131
+ }, te = () => {
132
+ u(() => {
133
+ b.value && (b.value.scrollTop = b.value.scrollHeight);
134
+ });
135
+ };
136
+ return C(() => p.messages.length, te), C(() => p.messages, te, { deep: !0 }), (t, l) => {
137
+ let u = y("el-icon"), p = y("el-tag"), _ = y("el-popover"), C = y("el-button"), j = y("el-input");
138
+ return c.visible ? (h(), i("div", {
139
+ key: 0,
140
+ class: "ai-chat-panel",
141
+ style: f({ width: c.panelWidth + "px" })
142
+ }, [
143
+ a("div", ce, [a("div", le, [
144
+ s(u, {
145
+ size: 18,
146
+ color: "#409EFF"
147
+ }, {
148
+ default: w(() => [s(S(G))]),
149
+ _: 1
150
+ }),
151
+ a("span", ue, x(c.isCollab ? "协作聊天" : "AI 助手"), 1),
152
+ c.isCollab ? (h(), n(_, {
153
+ key: 0,
154
+ width: 200,
155
+ placement: "bottom-start",
156
+ trigger: "click"
157
+ }, {
158
+ reference: w(() => [s(p, {
159
+ size: "small",
160
+ type: "success",
161
+ effect: "plain",
162
+ class: "online-tag"
163
+ }, {
164
+ default: w(() => [o(x(I.value) + "人在线 ", 1)]),
165
+ _: 1
166
+ })]),
167
+ default: w(() => [a("div", Q, [a("div", de, [
168
+ a("div", {
169
+ class: "online-user-avatar",
170
+ style: f({ background: c.currentUser.color || "#409EFF" })
171
+ }, x((c.currentUser.name || "U").charAt(0)), 5),
172
+ a("span", fe, x(c.currentUser.name || "我"), 1),
173
+ s(p, {
174
+ size: "small",
175
+ type: c.isOwner ? "warning" : "success",
176
+ effect: "plain",
177
+ class: "role-tag"
178
+ }, {
179
+ default: w(() => [o(x(c.isOwner ? "发起人" : "协作人"), 1)]),
180
+ _: 1
181
+ }, 8, ["type"]),
182
+ l[4] ||= a("span", { class: "self-tag" }, "(我)", -1)
183
+ ]), (h(!0), i(e, null, v(F.value, (e) => (h(), i("div", {
184
+ key: e.id || e.clientId,
185
+ class: "online-user-item"
186
+ }, [
187
+ a("div", {
188
+ class: "online-user-avatar",
189
+ style: f({ background: e.color || "#909399" })
190
+ }, [e.isAi ? (h(), n(u, {
191
+ key: 0,
192
+ size: 14
193
+ }, {
194
+ default: w(() => [s(S(G))]),
195
+ _: 1
196
+ })) : (h(), i("span", pe, x((e.name || "U").charAt(0)), 1))], 4),
197
+ a("span", me, x(e.name || "未知用户"), 1),
198
+ e.isAi ? (h(), n(p, {
199
+ key: 0,
200
+ size: "small",
201
+ type: "primary",
202
+ effect: "plain",
203
+ class: "role-tag"
204
+ }, {
205
+ default: w(() => [...l[5] ||= [o("AI助手", -1)]]),
206
+ _: 1
207
+ })) : (h(), n(p, {
208
+ key: 1,
209
+ size: "small",
210
+ type: "success",
211
+ effect: "plain",
212
+ class: "role-tag"
213
+ }, {
214
+ default: w(() => [...l[6] ||= [o("协作人", -1)]]),
215
+ _: 1
216
+ }))
217
+ ]))), 128))])]),
218
+ _: 1
219
+ })) : r("", !0)
220
+ ]), a("div", he, [
221
+ c.isCollab && c.unreadMention ? (h(), i("div", {
222
+ key: 0,
223
+ class: "mention-bell",
224
+ title: "有新消息",
225
+ onClick: l[0] ||= (e) => m("clear-unread")
226
+ }, [s(u, {
227
+ size: 18,
228
+ color: "#F56C6C"
229
+ }, {
230
+ default: w(() => [s(S(P))]),
231
+ _: 1
232
+ })])) : r("", !0),
233
+ s(C, {
234
+ text: "",
235
+ circle: "",
236
+ size: "small",
237
+ onClick: l[1] ||= (e) => t.$emit("clear"),
238
+ title: "清空对话"
239
+ }, {
240
+ default: w(() => [s(u, null, {
241
+ default: w(() => [s(S(z))]),
242
+ _: 1
243
+ })]),
244
+ _: 1
245
+ }),
246
+ s(C, {
247
+ text: "",
248
+ circle: "",
249
+ size: "small",
250
+ onClick: l[2] ||= (e) => t.$emit("close"),
251
+ title: "关闭"
252
+ }, {
253
+ default: w(() => [s(u, null, {
254
+ default: w(() => [s(S(L))]),
255
+ _: 1
256
+ })]),
257
+ _: 1
258
+ })
259
+ ])]),
260
+ a("div", {
261
+ class: "chat-messages",
262
+ ref_key: "messagesRef",
263
+ ref: b
264
+ }, [
265
+ c.messages.length === 0 ? (h(), i("div", ge, [
266
+ s(u, {
267
+ size: 40,
268
+ color: "#c0c4cc"
269
+ }, {
270
+ default: w(() => [s(S(G))]),
271
+ _: 1
272
+ }),
273
+ a("p", null, x(c.isCollab ? "协作聊天室" : "你好!我是 AI 助手"), 1),
274
+ a("p", _e, x(c.isCollab ? "与团队成员和AI助手实时聊天" : "可以问我任何关于文档编辑的问题"), 1)
275
+ ])) : r("", !0),
276
+ (h(!0), i(e, null, v(c.messages, (e) => (h(), i("div", {
277
+ key: e._msgId || e.time + e.content,
278
+ class: d(["chat-message", R(e)])
279
+ }, [a("div", {
280
+ class: "message-avatar",
281
+ style: f(B(e))
282
+ }, [e.role === "ai" ? (h(), n(u, {
283
+ key: 0,
284
+ size: 16
285
+ }, {
286
+ default: w(() => [s(S(G))]),
287
+ _: 1
288
+ })) : (h(), i("span", ve, x(V(e)), 1))], 4), a("div", ye, [
289
+ c.isCollab && e.role === "user" ? (h(), i("div", be, [a("span", {
290
+ class: "message-sender",
291
+ style: f({ color: e.user_color || "#67C23A" })
292
+ }, x(e.user_name || "用户"), 5), e.mentioned_user ? (h(), i("span", $, "@" + x(e.mentioned_user), 1)) : r("", !0)])) : r("", !0),
293
+ a("div", {
294
+ class: "message-text",
295
+ innerHTML: e.content
296
+ }, null, 8, xe),
297
+ a("div", Se, x(e.time), 1)
298
+ ])], 2))), 128)),
299
+ c.loading ? (h(), i("div", Ce, [a("div", we, [s(u, { size: 16 }, {
300
+ default: w(() => [s(S(G))]),
301
+ _: 1
302
+ })]), l[7] ||= a("div", { class: "message-content" }, [a("div", { class: "message-text typing-indicator" }, [
303
+ a("span"),
304
+ a("span"),
305
+ a("span")
306
+ ])], -1)])) : r("", !0)
307
+ ], 512),
308
+ a("div", Te, [a("div", {
309
+ class: "chat-input-wrapper",
310
+ ref_key: "inputWrapperRef",
311
+ ref: D
312
+ }, [
313
+ s(j, {
314
+ modelValue: g.value,
315
+ "onUpdate:modelValue": l[3] ||= (e) => g.value = e,
316
+ type: "textarea",
317
+ autosize: {
318
+ minRows: 1,
319
+ maxRows: 4
320
+ },
321
+ placeholder: c.isCollab ? "输入消息... @提及成员" : "输入消息...",
322
+ onKeydown: [
323
+ T(E(K, ["exact"]), ["enter"]),
324
+ T(E(ee, ["prevent"]), ["down"]),
325
+ T(E(U, ["prevent"]), ["up"])
326
+ ],
327
+ onInput: H,
328
+ resize: "none"
329
+ }, null, 8, [
330
+ "modelValue",
331
+ "placeholder",
332
+ "onKeydown"
333
+ ]),
334
+ O.value ? (h(), i("div", Ee, [(h(!0), i(e, null, v(k.value, (e, t) => (h(), i("div", {
335
+ key: e.id || e.clientId,
336
+ class: d(["mention-item", { active: t === A.value }]),
337
+ onClick: (t) => W(e),
338
+ onMouseenter: (e) => A.value = t
339
+ }, [a("div", {
340
+ class: "mention-avatar",
341
+ style: f({ background: e.color || "#909399" })
342
+ }, [e.isAi ? (h(), n(u, {
343
+ key: 0,
344
+ size: 12
345
+ }, {
346
+ default: w(() => [s(S(G))]),
347
+ _: 1
348
+ })) : (h(), i("span", Oe, x((e.name || "U").charAt(0)), 1))], 4), a("span", null, x(e.name), 1)], 42, De))), 128))])) : r("", !0),
349
+ s(C, {
350
+ class: "send-btn",
351
+ type: "primary",
352
+ circle: "",
353
+ disabled: !g.value.trim() || c.loading,
354
+ onClick: K
355
+ }, {
356
+ default: w(() => [s(u, null, {
357
+ default: w(() => [s(S(ne))]),
358
+ _: 1
359
+ })]),
360
+ _: 1
361
+ }, 8, ["disabled"])
362
+ ], 512)])
363
+ ], 4)) : r("", !0);
364
+ };
365
+ }
366
+ }, [["__scopeId", "data-v-01960100"]]);
367
+ //#endregion
368
+ //#region ../../src/composables/useChat.js
369
+ function Ae() {
370
+ let e = _([]), t = _(!1), n = _(!1), r = _([]), i = _({
371
+ id: "",
372
+ name: "",
373
+ color: ""
374
+ }), a = _(!1), o = null, s = null, c = null, l = /* @__PURE__ */ new Set(), u = "/api/chat", d = null, f = ({ ydoc: t, provider: s, onlineUsers: u }) => {
375
+ if (t) {
376
+ n.value = !0, c = u, d && d(), d = C(c, (e) => {
377
+ r.value = Array.isArray(e) ? e : [];
378
+ }, {
379
+ immediate: !0,
380
+ deep: !0
381
+ });
382
+ try {
383
+ o = t.getArray("chat-messages"), o.observe((t) => {
384
+ try {
385
+ t.changes.added.forEach((t) => {
386
+ t.content.getContent().forEach((t) => {
387
+ t && t._msgId && !l.has(t._msgId) && (l.add(t._msgId), e.value = [...e.value, t], t.mentioned_user && t.user_id !== i.value.id && (a.value = !0));
388
+ });
389
+ });
390
+ } catch (e) {
391
+ console.warn("[useChat] Y.Array observer error:", e);
392
+ }
393
+ });
394
+ } catch (e) {
395
+ console.warn("[useChat] Failed to create Y.Array:", e);
396
+ }
397
+ }
398
+ }, p = (e) => {
399
+ i.value = {
400
+ ...i.value,
401
+ ...e
402
+ };
403
+ }, h = (e) => {
404
+ r.value = e || [];
405
+ }, g = () => {
406
+ let e = /* @__PURE__ */ new Date();
407
+ return `${e.getHours().toString().padStart(2, "0")}:${e.getMinutes().toString().padStart(2, "0")}`;
408
+ }, v = async (t, r = {}) => {
409
+ let a = {
410
+ _msgId: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
411
+ role: "user",
412
+ content: t,
413
+ time: g(),
414
+ user_id: i.value.id,
415
+ user_name: i.value.name,
416
+ user_color: i.value.color,
417
+ mentioned_user: r.mentionedUser || null
418
+ };
419
+ if (l.add(a._msgId), e.value = [...e.value, a], o && S(n)) try {
420
+ o.push([a]);
421
+ } catch (e) {
422
+ console.warn("[useChat] Failed to push to Y.Array:", e);
423
+ }
424
+ if (r.roomId) try {
425
+ await Y.post(u, {
426
+ room_id: r.roomId,
427
+ role: "user",
428
+ content: t,
429
+ user_id: i.value.id,
430
+ user_name: i.value.name,
431
+ mentioned_user: r.mentionedUser || null
432
+ });
433
+ } catch (e) {
434
+ console.warn("[useChat] Failed to persist message:", e);
435
+ }
436
+ }, y = async (t, r) => {
437
+ let i = {
438
+ _msgId: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
439
+ role: "ai",
440
+ content: t,
441
+ time: g(),
442
+ user_id: "ai-assistant",
443
+ user_name: "AI助手"
444
+ };
445
+ if (l.add(i._msgId), e.value = [...e.value, i], o && S(n)) try {
446
+ o.push([i]);
447
+ } catch (e) {
448
+ console.warn("[useChat] Failed to push AI message to Y.Array:", e);
449
+ }
450
+ if (r) try {
451
+ await Y.post(u, {
452
+ room_id: r,
453
+ role: "ai",
454
+ content: t,
455
+ user_id: "ai-assistant",
456
+ user_name: "AI助手"
457
+ });
458
+ } catch (e) {
459
+ console.warn("[useChat] Failed to persist AI message:", e);
460
+ }
461
+ }, b = async (t) => {
462
+ if (t) try {
463
+ let n = await Y.get(u, { params: { room_id: t } });
464
+ if (Array.isArray(n.data)) {
465
+ let t = n.data.map((e) => ({
466
+ _msgId: e._msgId || `hist-${e.id || Date.now()}`,
467
+ role: e.role,
468
+ content: e.content,
469
+ time: e.time || g(),
470
+ user_id: e.user_id || "",
471
+ user_name: e.user_name || "",
472
+ user_color: e.user_color || "",
473
+ mentioned_user: e.mentioned_user || null
474
+ }));
475
+ t.forEach((e) => l.add(e._msgId)), e.value = [...t, ...e.value];
476
+ }
477
+ } catch (e) {
478
+ console.warn("[useChat] Failed to load history:", e);
479
+ }
480
+ }, x = async (t) => {
481
+ if (e.value = [], l.clear(), t) try {
482
+ await Y.delete(u, { params: { room_id: t } });
483
+ } catch (e) {
484
+ console.warn("[useChat] Failed to clear messages on server:", e);
485
+ }
486
+ }, w = () => {
487
+ a.value = !1;
488
+ }, T = () => {
489
+ if (d &&= (d(), null), o && s) {
490
+ try {
491
+ o.unobserve(s);
492
+ } catch {}
493
+ s = null;
494
+ }
495
+ o = null, c = null, l.clear();
496
+ };
497
+ return m(() => T()), {
498
+ messages: e,
499
+ loading: t,
500
+ isCollabMode: n,
501
+ collabUsers: r,
502
+ currentUser: i,
503
+ unreadMention: a,
504
+ setCollabContext: f,
505
+ setCurrentUser: p,
506
+ updateCollabUsers: h,
507
+ sendMessage: v,
508
+ sendAiMessage: y,
509
+ loadHistory: b,
510
+ clearMessages: x,
511
+ clearUnreadMention: w,
512
+ destroy: T
513
+ };
514
+ }
515
+ //#endregion
516
+ //#region ../../src/composables/useVersionHistory.js
517
+ var je = "/api/document-versions", Me = 5e3, Ne = () => {
518
+ let e = _([]), t = _(!1);
519
+ return {
520
+ versions: e,
521
+ loading: t,
522
+ saveVersion: async ({ documentId: e, docType: t, content: n, userId: r, userName: i }) => {
523
+ if (!e || !t || !n) return null;
524
+ try {
525
+ let { data: a } = await Y.post(je, {
526
+ document_id: e,
527
+ doc_type: t,
528
+ content: typeof n == "string" ? n : JSON.stringify(n),
529
+ user_id: r || null,
530
+ user_name: i || null
531
+ }, { timeout: Me });
532
+ return a;
533
+ } catch (e) {
534
+ return console.warn("[useVersionHistory] Failed to save version:", e), null;
535
+ }
536
+ },
537
+ loadVersions: async (n) => {
538
+ if (!n) return [];
539
+ t.value = !0;
540
+ try {
541
+ let { data: t } = await Y.get(je, {
542
+ params: { document_id: n },
543
+ timeout: Me
544
+ });
545
+ return e.value = t, t;
546
+ } catch (t) {
547
+ return console.warn("[useVersionHistory] Failed to load versions:", t), e.value = [], [];
548
+ } finally {
549
+ t.value = !1;
550
+ }
551
+ },
552
+ getVersionContent: async (e) => {
553
+ try {
554
+ let { data: t } = await Y.get(`${je}/${e}`, { timeout: Me });
555
+ return t;
556
+ } catch (e) {
557
+ return console.warn("[useVersionHistory] Failed to get version content:", e), null;
558
+ }
559
+ }
560
+ };
561
+ }, Pe = { class: "version-history-panel" }, Fe = {
562
+ key: 0,
563
+ class: "loading-state"
564
+ }, Ie = {
565
+ key: 1,
566
+ class: "empty-state"
567
+ }, Le = {
568
+ key: 2,
569
+ class: "version-list"
570
+ }, Re = {
571
+ key: 0,
572
+ class: "current-version"
573
+ }, ze = { class: "current-version-header" }, Be = { class: "version-number" }, Ve = ["onClick"], He = { class: "version-number" }, Ue = { class: "version-user" }, We = { class: "panel-footer" }, Ge = /*#__PURE__*/ Z({
574
+ __name: "VersionHistoryPanel",
575
+ props: {
576
+ modelValue: {
577
+ type: Boolean,
578
+ default: !1
579
+ },
580
+ documentId: {
581
+ type: [Number, String],
582
+ default: null
583
+ }
584
+ },
585
+ emits: ["update:modelValue", "apply"],
586
+ setup(t, { expose: c, emit: l }) {
587
+ let u = t, f = l, { versions: p, loading: m, loadVersions: g, getVersionContent: b } = Ne(), T = _(!1), E = _(null), D = _(!1), O = _(null);
588
+ C(() => u.modelValue, (e) => {
589
+ T.value = e, e && u.documentId && (E.value = null, g(u.documentId).then((e) => {
590
+ e && e.length > 0 && (O.value = e[0]);
591
+ }));
592
+ }), C(T, (e) => {
593
+ f("update:modelValue", e);
594
+ });
595
+ let k = (e) => {
596
+ E.value = e;
597
+ }, j = async () => {
598
+ if (E.value) {
599
+ D.value = !0;
600
+ try {
601
+ let e = await b(E.value.id);
602
+ e && e.content ? (O.value = E.value, E.value = null, f("apply", e.content), A.success("已切换到版本 v" + O.value.version_number)) : A.error("获取版本内容失败");
603
+ } finally {
604
+ D.value = !1;
605
+ }
606
+ }
607
+ }, M = () => {
608
+ T.value = !1;
609
+ }, N = (e) => {
610
+ if (!e) return "";
611
+ let t = new Date(e), n = (e) => String(e).padStart(2, "0");
612
+ return `${t.getFullYear()}-${n(t.getMonth() + 1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`;
613
+ };
614
+ return c({ currentVersion: O }), (t, c) => {
615
+ let l = y("el-icon"), u = y("el-tag"), f = y("el-timeline-item"), g = y("el-timeline"), _ = y("el-button"), b = y("el-drawer");
616
+ return h(), n(b, {
617
+ modelValue: T.value,
618
+ "onUpdate:modelValue": c[0] ||= (e) => T.value = e,
619
+ title: "更新履历",
620
+ direction: "rtl",
621
+ size: "420px",
622
+ "before-close": M
623
+ }, {
624
+ footer: w(() => [a("div", We, [s(_, {
625
+ type: "primary",
626
+ disabled: !E.value,
627
+ loading: D.value,
628
+ onClick: j
629
+ }, {
630
+ default: w(() => [...c[4] ||= [o(" 切换到此版本 ", -1)]]),
631
+ _: 1
632
+ }, 8, ["disabled", "loading"])])]),
633
+ default: w(() => [a("div", Pe, [S(m) ? (h(), i("div", Fe, [s(l, { class: "is-loading" }, {
634
+ default: w(() => [s(S(ee))]),
635
+ _: 1
636
+ }), c[1] ||= a("span", null, "加载中...", -1)])) : S(p).length === 0 ? (h(), i("div", Ie, [s(l, {
637
+ size: 48,
638
+ color: "#c0c4cc"
639
+ }, {
640
+ default: w(() => [s(S(I))]),
641
+ _: 1
642
+ }), c[2] ||= a("p", null, "暂无历史版本", -1)])) : (h(), i("div", Le, [O.value ? (h(), i("div", Re, [a("div", ze, [s(u, {
643
+ type: "success",
644
+ size: "small"
645
+ }, {
646
+ default: w(() => [...c[3] ||= [o("当前版本", -1)]]),
647
+ _: 1
648
+ }), a("span", Be, "v" + x(O.value.version_number), 1)])])) : r("", !0), s(g, null, {
649
+ default: w(() => [(h(!0), i(e, null, v(S(p), (e) => (h(), n(f, {
650
+ key: e.id,
651
+ timestamp: N(e.created_at),
652
+ placement: "top",
653
+ type: E.value?.id === e.id ? "primary" : "",
654
+ hollow: E.value?.id !== e.id
655
+ }, {
656
+ default: w(() => [a("div", {
657
+ class: d(["version-item", { active: E.value?.id === e.id }]),
658
+ onClick: (t) => k(e)
659
+ }, [a("span", He, "版本号:v" + x(e.version_number), 1), a("span", Ue, "提交人:" + x(e.user_name || "未知用户"), 1)], 10, Ve)]),
660
+ _: 2
661
+ }, 1032, [
662
+ "timestamp",
663
+ "type",
664
+ "hollow"
665
+ ]))), 128))]),
666
+ _: 1
667
+ })]))])]),
668
+ _: 1
669
+ }, 8, ["modelValue"]);
670
+ };
671
+ }
672
+ }, [["__scopeId", "data-v-87924b7c"]]), Ke = { class: "toolbar" }, qe = { class: "toolbar-left" }, Je = { class: "toolbar-center" }, Ye = { class: "group-popover" }, Xe = { class: "group-popover-header" }, Ze = { class: "group-list" }, Qe = ["onClick"], $e = { class: "group-name" }, et = { class: "group-item-actions" }, tt = {
673
+ key: 1,
674
+ class: "group-empty"
675
+ }, nt = { class: "toolbar-right" }, rt = {
676
+ key: 0,
677
+ class: "collab-users"
678
+ }, it = ["title"], at = /*#__PURE__*/ Z({
679
+ __name: "Toolbar",
680
+ props: {
681
+ title: {
682
+ type: String,
683
+ default: ""
684
+ },
685
+ lineStyle: {
686
+ type: String,
687
+ default: "straight"
688
+ },
689
+ groups: {
690
+ type: Array,
691
+ default: () => []
692
+ },
693
+ activeGroupId: {
694
+ type: String,
695
+ default: null
696
+ },
697
+ collapsedGroups: {
698
+ type: Array,
699
+ default: () => []
700
+ },
701
+ isConnected: Boolean,
702
+ onlineUsers: {
703
+ type: Array,
704
+ default: () => []
705
+ },
706
+ isJoinMode: Boolean,
707
+ showHistory: {
708
+ type: Boolean,
709
+ default: !1
710
+ }
711
+ },
712
+ emits: [
713
+ "update:title",
714
+ "back",
715
+ "add-annotation",
716
+ "set-line-style",
717
+ "add-group",
718
+ "group-action",
719
+ "clear-group-filter",
720
+ "export",
721
+ "import-json",
722
+ "save",
723
+ "toggle-collab",
724
+ "share-collab",
725
+ "history"
726
+ ],
727
+ setup(c) {
728
+ let l = c, u = _(l.title);
729
+ C(() => l.title, (e) => u.value = e);
730
+ let p = {
731
+ straight: {
732
+ label: "直线",
733
+ icon: q
734
+ },
735
+ polyline: {
736
+ label: "折线",
737
+ icon: R
738
+ },
739
+ "right-angle": {
740
+ label: "直角折线",
741
+ icon: re
742
+ },
743
+ curve: {
744
+ label: "曲线",
745
+ icon: J
746
+ },
747
+ wave: {
748
+ label: "波浪线",
749
+ icon: J
750
+ },
751
+ dashed: {
752
+ label: "虚线",
753
+ icon: W
754
+ },
755
+ dotted: {
756
+ label: "点线",
757
+ icon: K
758
+ },
759
+ dashdot: {
760
+ label: "点划线",
761
+ icon: q
762
+ }
763
+ }, m = t(() => p[l.lineStyle]?.label || "引线"), g = t(() => p[l.lineStyle]?.icon || q);
764
+ return (t, l) => {
765
+ let p = y("el-icon"), _ = y("el-button"), C = y("el-input"), T = y("el-tooltip"), D = y("el-divider"), O = y("el-dropdown-item"), k = y("el-dropdown-menu"), A = y("el-dropdown"), j = y("el-badge"), P = y("el-tag"), V = y("el-popover");
766
+ return h(), i("div", Ke, [
767
+ a("div", qe, [s(_, {
768
+ onClick: l[0] ||= (e) => t.$emit("back"),
769
+ size: "small",
770
+ circle: ""
771
+ }, {
772
+ default: w(() => [s(p, null, {
773
+ default: w(() => [s(S(N))]),
774
+ _: 1
775
+ })]),
776
+ _: 1
777
+ }), s(C, {
778
+ modelValue: u.value,
779
+ "onUpdate:modelValue": l[1] ||= (e) => u.value = e,
780
+ onBlur: l[2] ||= (e) => t.$emit("update:title", u.value),
781
+ placeholder: "输入标题",
782
+ class: "title-input",
783
+ size: "small"
784
+ }, null, 8, ["modelValue"])]),
785
+ a("div", Je, [
786
+ s(T, {
787
+ content: "添加标注",
788
+ placement: "bottom"
789
+ }, {
790
+ default: w(() => [s(_, {
791
+ size: "small",
792
+ circle: "",
793
+ onClick: l[3] ||= (e) => t.$emit("add-annotation")
794
+ }, {
795
+ default: w(() => [s(p, null, {
796
+ default: w(() => [s(S(U))]),
797
+ _: 1
798
+ })]),
799
+ _: 1
800
+ })]),
801
+ _: 1
802
+ }),
803
+ s(D, { direction: "vertical" }),
804
+ s(A, {
805
+ trigger: "click",
806
+ onCommand: l[4] ||= (e) => t.$emit("set-line-style", e)
807
+ }, {
808
+ dropdown: w(() => [s(k, null, {
809
+ default: w(() => [
810
+ s(O, {
811
+ command: "straight",
812
+ class: d({ "is-active": c.lineStyle === "straight" })
813
+ }, {
814
+ default: w(() => [s(p, null, {
815
+ default: w(() => [s(S(q))]),
816
+ _: 1
817
+ }), l[14] ||= o("直线 ", -1)]),
818
+ _: 1
819
+ }, 8, ["class"]),
820
+ s(O, {
821
+ command: "polyline",
822
+ class: d({ "is-active": c.lineStyle === "polyline" })
823
+ }, {
824
+ default: w(() => [s(p, null, {
825
+ default: w(() => [s(S(R))]),
826
+ _: 1
827
+ }), l[15] ||= o("折线 ", -1)]),
828
+ _: 1
829
+ }, 8, ["class"]),
830
+ s(O, {
831
+ command: "right-angle",
832
+ class: d({ "is-active": c.lineStyle === "right-angle" })
833
+ }, {
834
+ default: w(() => [s(p, null, {
835
+ default: w(() => [s(S(re))]),
836
+ _: 1
837
+ }), l[16] ||= o("直角折线 ", -1)]),
838
+ _: 1
839
+ }, 8, ["class"]),
840
+ s(O, {
841
+ command: "curve",
842
+ class: d({ "is-active": c.lineStyle === "curve" })
843
+ }, {
844
+ default: w(() => [s(p, null, {
845
+ default: w(() => [s(S(J))]),
846
+ _: 1
847
+ }), l[17] ||= o("曲线 ", -1)]),
848
+ _: 1
849
+ }, 8, ["class"]),
850
+ s(O, {
851
+ command: "wave",
852
+ class: d({ "is-active": c.lineStyle === "wave" })
853
+ }, {
854
+ default: w(() => [s(p, null, {
855
+ default: w(() => [s(S(J))]),
856
+ _: 1
857
+ }), l[18] ||= o("波浪线 ", -1)]),
858
+ _: 1
859
+ }, 8, ["class"]),
860
+ s(O, {
861
+ divided: "",
862
+ command: "dashed",
863
+ class: d({ "is-active": c.lineStyle === "dashed" })
864
+ }, {
865
+ default: w(() => [s(p, null, {
866
+ default: w(() => [s(S(W))]),
867
+ _: 1
868
+ }), l[19] ||= o("虚线 ", -1)]),
869
+ _: 1
870
+ }, 8, ["class"]),
871
+ s(O, {
872
+ command: "dotted",
873
+ class: d({ "is-active": c.lineStyle === "dotted" })
874
+ }, {
875
+ default: w(() => [s(p, null, {
876
+ default: w(() => [s(S(K))]),
877
+ _: 1
878
+ }), l[20] ||= o("点线 ", -1)]),
879
+ _: 1
880
+ }, 8, ["class"]),
881
+ s(O, {
882
+ command: "dashdot",
883
+ class: d({ "is-active": c.lineStyle === "dashdot" })
884
+ }, {
885
+ default: w(() => [s(p, null, {
886
+ default: w(() => [s(S(q))]),
887
+ _: 1
888
+ }), l[21] ||= o("点划线 ", -1)]),
889
+ _: 1
890
+ }, 8, ["class"])
891
+ ]),
892
+ _: 1
893
+ })]),
894
+ default: w(() => [s(_, { size: "small" }, {
895
+ default: w(() => [
896
+ s(p, null, {
897
+ default: w(() => [(h(), n(b(g.value)))]),
898
+ _: 1
899
+ }),
900
+ o(" " + x(m.value) + " ", 1),
901
+ s(p, { class: "el-icon--right" }, {
902
+ default: w(() => [s(S(M))]),
903
+ _: 1
904
+ })
905
+ ]),
906
+ _: 1
907
+ })]),
908
+ _: 1
909
+ }),
910
+ s(D, { direction: "vertical" }),
911
+ s(V, {
912
+ placement: "bottom",
913
+ width: 280,
914
+ trigger: "click"
915
+ }, {
916
+ reference: w(() => [s(_, { size: "small" }, {
917
+ default: w(() => [
918
+ l[22] ||= o(" 分组 ", -1),
919
+ c.activeGroupId ? (h(), n(j, {
920
+ key: 0,
921
+ value: 1,
922
+ offset: [-2, -2],
923
+ class: "group-badge"
924
+ })) : r("", !0),
925
+ s(p, { class: "el-icon--right" }, {
926
+ default: w(() => [s(S(M))]),
927
+ _: 1
928
+ })
929
+ ]),
930
+ _: 1
931
+ })]),
932
+ default: w(() => [a("div", Ye, [
933
+ a("div", Xe, [s(_, {
934
+ size: "small",
935
+ onClick: l[5] ||= (e) => t.$emit("add-group", "new"),
936
+ type: "primary",
937
+ plain: ""
938
+ }, {
939
+ default: w(() => [s(p, null, {
940
+ default: w(() => [s(S(te))]),
941
+ _: 1
942
+ }), l[23] ||= o("新建分组 ", -1)]),
943
+ _: 1
944
+ }), c.activeGroupId ? (h(), n(_, {
945
+ key: 0,
946
+ size: "small",
947
+ onClick: l[6] ||= (e) => t.$emit("clear-group-filter")
948
+ }, {
949
+ default: w(() => [s(p, null, {
950
+ default: w(() => [s(S(L))]),
951
+ _: 1
952
+ }), l[24] ||= o("显示全部 ", -1)]),
953
+ _: 1
954
+ })) : r("", !0)]),
955
+ c.groups.length ? (h(), n(D, {
956
+ key: 0,
957
+ style: { margin: "8px 0" }
958
+ })) : r("", !0),
959
+ a("div", Ze, [(h(!0), i(e, null, v(c.groups, (e) => (h(), i("div", {
960
+ key: e.id,
961
+ class: d(["group-item", { active: c.activeGroupId === e.id }])
962
+ }, [a("div", {
963
+ class: "group-item-main",
964
+ onClick: (n) => t.$emit("group-action", "filter", e.id)
965
+ }, [a("span", $e, x(e.name), 1), c.activeGroupId === e.id ? (h(), n(P, {
966
+ key: 0,
967
+ size: "small",
968
+ type: "primary"
969
+ }, {
970
+ default: w(() => [...l[25] ||= [o("筛选", -1)]]),
971
+ _: 1
972
+ })) : r("", !0)], 8, Qe), a("div", et, [
973
+ s(T, {
974
+ content: "展开/折叠",
975
+ placement: "top"
976
+ }, {
977
+ default: w(() => [s(_, {
978
+ size: "small",
979
+ circle: "",
980
+ onClick: E((n) => t.$emit("group-action", "collapse", e.id), ["stop"])
981
+ }, {
982
+ default: w(() => [s(p, null, {
983
+ default: w(() => [(h(), n(b(c.collapsedGroups.includes(e.id) ? "View" : "Hide")))]),
984
+ _: 2
985
+ }, 1024)]),
986
+ _: 2
987
+ }, 1032, ["onClick"])]),
988
+ _: 2
989
+ }, 1024),
990
+ s(T, {
991
+ content: "修改颜色",
992
+ placement: "top"
993
+ }, {
994
+ default: w(() => [s(_, {
995
+ size: "small",
996
+ circle: "",
997
+ onClick: E((n) => t.$emit("group-action", "color", e.id), ["stop"])
998
+ }, {
999
+ default: w(() => [s(p, null, {
1000
+ default: w(() => [s(S(F))]),
1001
+ _: 1
1002
+ })]),
1003
+ _: 1
1004
+ }, 8, ["onClick"])]),
1005
+ _: 2
1006
+ }, 1024),
1007
+ s(T, {
1008
+ content: "删除分组",
1009
+ placement: "top"
1010
+ }, {
1011
+ default: w(() => [s(_, {
1012
+ size: "small",
1013
+ circle: "",
1014
+ type: "danger",
1015
+ onClick: E((n) => t.$emit("group-action", "delete", e.id), ["stop"])
1016
+ }, {
1017
+ default: w(() => [s(p, null, {
1018
+ default: w(() => [s(S(z))]),
1019
+ _: 1
1020
+ })]),
1021
+ _: 1
1022
+ }, 8, ["onClick"])]),
1023
+ _: 2
1024
+ }, 1024)
1025
+ ])], 2))), 128))]),
1026
+ c.groups.length ? r("", !0) : (h(), i("div", tt, "暂无分组"))
1027
+ ])]),
1028
+ _: 1
1029
+ })
1030
+ ]),
1031
+ a("div", nt, [
1032
+ c.onlineUsers.length > 0 ? (h(), i("div", rt, [(h(!0), i(e, null, v(c.onlineUsers.slice(0, 5), (e) => (h(), i("div", {
1033
+ key: e.clientId,
1034
+ class: "collab-avatar",
1035
+ style: f({ background: e.color }),
1036
+ title: e.name
1037
+ }, x(e.name?.charAt(0)), 13, it))), 128))])) : r("", !0),
1038
+ c.isJoinMode ? r("", !0) : (h(), n(_, {
1039
+ key: 1,
1040
+ size: "small",
1041
+ type: c.isConnected ? "success" : "default",
1042
+ onClick: l[7] ||= (e) => t.$emit("toggle-collab")
1043
+ }, {
1044
+ default: w(() => [s(p, null, {
1045
+ default: w(() => [s(S(ie))]),
1046
+ _: 1
1047
+ }), a("span", null, x(c.isConnected ? "协作中" : "协作"), 1)]),
1048
+ _: 1
1049
+ }, 8, ["type"])),
1050
+ !c.isJoinMode && c.isConnected ? (h(), n(_, {
1051
+ key: 2,
1052
+ size: "small",
1053
+ circle: "",
1054
+ onClick: l[8] ||= (e) => t.$emit("share-collab"),
1055
+ title: "分享链接"
1056
+ }, {
1057
+ default: w(() => [s(p, null, {
1058
+ default: w(() => [s(S(H))]),
1059
+ _: 1
1060
+ })]),
1061
+ _: 1
1062
+ })) : r("", !0),
1063
+ s(D, { direction: "vertical" }),
1064
+ s(A, {
1065
+ trigger: "click",
1066
+ onCommand: l[9] ||= (e) => t.$emit("export", e)
1067
+ }, {
1068
+ dropdown: w(() => [s(k, null, {
1069
+ default: w(() => [
1070
+ c.activeGroupId ? (h(), n(O, {
1071
+ key: 0,
1072
+ command: "png-filtered"
1073
+ }, {
1074
+ default: w(() => [...l[27] ||= [o("PNG(当前分组)", -1)]]),
1075
+ _: 1
1076
+ })) : r("", !0),
1077
+ s(O, { command: "png" }, {
1078
+ default: w(() => [...l[28] ||= [o("PNG(全部)", -1)]]),
1079
+ _: 1
1080
+ }),
1081
+ s(O, { command: "svg" }, {
1082
+ default: w(() => [...l[29] ||= [o("SVG", -1)]]),
1083
+ _: 1
1084
+ }),
1085
+ s(O, { command: "pdf" }, {
1086
+ default: w(() => [...l[30] ||= [o("PDF", -1)]]),
1087
+ _: 1
1088
+ }),
1089
+ s(O, { command: "html" }, {
1090
+ default: w(() => [...l[31] ||= [o("HTML", -1)]]),
1091
+ _: 1
1092
+ }),
1093
+ s(O, {
1094
+ divided: "",
1095
+ command: "json"
1096
+ }, {
1097
+ default: w(() => [...l[32] ||= [o("JSON(完整数据)", -1)]]),
1098
+ _: 1
1099
+ })
1100
+ ]),
1101
+ _: 1
1102
+ })]),
1103
+ default: w(() => [s(_, { size: "small" }, {
1104
+ default: w(() => [l[26] ||= o("导出", -1), s(p, { class: "el-icon--right" }, {
1105
+ default: w(() => [s(S(M))]),
1106
+ _: 1
1107
+ })]),
1108
+ _: 1
1109
+ })]),
1110
+ _: 1
1111
+ }),
1112
+ s(T, {
1113
+ content: "导入JSON",
1114
+ placement: "bottom"
1115
+ }, {
1116
+ default: w(() => [s(_, {
1117
+ size: "small",
1118
+ circle: "",
1119
+ onClick: l[10] ||= (e) => t.$refs.jsonInput.click()
1120
+ }, {
1121
+ default: w(() => [s(p, null, {
1122
+ default: w(() => [s(S(ae))]),
1123
+ _: 1
1124
+ })]),
1125
+ _: 1
1126
+ })]),
1127
+ _: 1
1128
+ }),
1129
+ a("input", {
1130
+ ref: "jsonInput",
1131
+ type: "file",
1132
+ accept: ".json",
1133
+ style: { display: "none" },
1134
+ onChange: l[11] ||= (e) => t.$emit("import-json", e)
1135
+ }, null, 544),
1136
+ s(_, {
1137
+ size: "small",
1138
+ onClick: l[12] ||= (e) => t.$emit("save")
1139
+ }, {
1140
+ default: w(() => [s(p, null, {
1141
+ default: w(() => [s(S(B))]),
1142
+ _: 1
1143
+ })]),
1144
+ _: 1
1145
+ }),
1146
+ c.showHistory ? (h(), n(_, {
1147
+ key: 3,
1148
+ size: "small",
1149
+ circle: "",
1150
+ title: "更新履历",
1151
+ onClick: l[13] ||= (e) => t.$emit("history")
1152
+ }, {
1153
+ default: w(() => [s(p, null, {
1154
+ default: w(() => [s(S(I))]),
1155
+ _: 1
1156
+ })]),
1157
+ _: 1
1158
+ })) : r("", !0)
1159
+ ])
1160
+ ]);
1161
+ };
1162
+ }
1163
+ }, [["__scopeId", "data-v-081fbd64"]]), ot = ["src"], st = ["onMousedown"], ct = {
1164
+ class: "leader-line-svg",
1165
+ style: {
1166
+ left: 0,
1167
+ top: 0,
1168
+ width: "100%",
1169
+ height: "100%"
1170
+ }
1171
+ }, lt = ["id", "fill"], ut = [
1172
+ "d",
1173
+ "stroke",
1174
+ "stroke-width",
1175
+ "stroke-dasharray",
1176
+ "marker-start"
1177
+ ], dt = ["onMousedown"], ft = ["onBlur"], pt = ["onMousedown"], mt = ["onMousedown"], ht = ["onMousedown"], gt = /*#__PURE__*/ Z({
1178
+ __name: "AnnotationCanvas",
1179
+ props: {
1180
+ imageUrl: String,
1181
+ annotations: {
1182
+ type: Array,
1183
+ default: () => []
1184
+ },
1185
+ collapsedGroups: {
1186
+ type: Array,
1187
+ default: () => []
1188
+ },
1189
+ selectedId: [
1190
+ String,
1191
+ Number,
1192
+ null
1193
+ ],
1194
+ lineStyle: {
1195
+ type: String,
1196
+ default: "straight"
1197
+ }
1198
+ },
1199
+ emits: [
1200
+ "select",
1201
+ "upload-image",
1202
+ "change"
1203
+ ],
1204
+ setup(n, { expose: r, emit: o }) {
1205
+ let c = n, l = o, u = _(null), p = _(null), m = _(800), g = _(600), b = _(!1), C = _(null), T = t(() => c.annotations.filter((e) => e.groupId ? !c.collapsedGroups.includes(e.groupId) : !0)), D = t(() => c.lineStyle === "dashed" ? "8,4" : c.lineStyle === "dotted" ? "3,3" : c.lineStyle === "dashdot" ? "8,3,2,3" : "none"), O = () => {
1206
+ let e = u.value, t = p.value;
1207
+ if (!e || !t) return;
1208
+ let n = t.naturalWidth, r = t.naturalHeight, i = e.clientWidth - 40, a = e.clientHeight - 40, o = i / n, s = a / r, c = Math.min(o, s, 1);
1209
+ m.value = Math.round(n * c), g.value = Math.round(r * c);
1210
+ }, k = () => {
1211
+ O();
1212
+ }, A = (e) => {
1213
+ O();
1214
+ }, j = (e) => {
1215
+ let t = e.x / 100 * m.value, n = e.y / 100 * g.value, r = t + (e.labelX || 0), i = n + (e.labelY || 0), a = [
1216
+ "dashed",
1217
+ "dotted",
1218
+ "dashdot"
1219
+ ].includes(c.lineStyle) ? "straight" : c.lineStyle;
1220
+ if (a === "straight" || a === "dashed" || a === "dotted" || a === "dashdot") return `M${t},${n} L${r},${i}`;
1221
+ if (a === "polyline") return `M${t},${n} L${e.x < 50 ? t + 20 : t - 20},${n} L${r},${i}`;
1222
+ if (a === "right-angle") return `M${t},${n} L${t},${i} L${r},${i}`;
1223
+ if (a === "curve") return `M${t},${n} C${e.x < 50 ? t + 30 : t - 30},${n} ${r},${i} ${r},${i}`;
1224
+ if (a === "wave") {
1225
+ let e = r - t, a = i - n, o = Math.sqrt(e * e + a * a), s = Math.max(2, Math.floor(o / 20)), c = `M${t},${n}`;
1226
+ for (let r = 1; r <= s; r++) {
1227
+ let i = r / s, o = t + e * i, l = n + a * i + Math.sin(i * Math.PI * s / 2) * 8;
1228
+ c += ` L${o},${l}`;
1229
+ }
1230
+ return c;
1231
+ }
1232
+ return `M${t},${n} L${r},${i}`;
1233
+ }, M = (e) => {
1234
+ let t = e.x / 100 * m.value, n = e.y / 100 * g.value, r = {
1235
+ left: `${t + (e.labelX || 0)}px`,
1236
+ top: `${n + (e.labelY || 0)}px`
1237
+ };
1238
+ if (e.labelBgColor) {
1239
+ let t = (e.labelBgOpacity ?? 100) / 100, n = e.labelBgColor;
1240
+ r.background = `rgba(${parseInt(n.slice(1, 3), 16)}, ${parseInt(n.slice(3, 5), 16)}, ${parseInt(n.slice(5, 7), 16)}, ${t})`;
1241
+ }
1242
+ return r;
1243
+ }, N = (e) => ({ background: e.numberColor || e.color || "#e74c3c" }), P = (e) => {
1244
+ let t = {
1245
+ fontFamily: e.fontFamily || "inherit",
1246
+ fontSize: e.fontSize ? e.fontSize + "px" : "inherit"
1247
+ };
1248
+ return e.textColor && (t.color = e.textColor), e.fontWeight === "bold" ? t.fontWeight = "bold" : e.fontWeight === "bolder" && (t.fontWeight = "bolder"), e.fontStyle === "italic" && (t.fontStyle = "italic"), e.fontStyle === "oblique" && (t.fontStyle = "oblique"), e.textDecoration === "underline" ? t.textDecoration = "underline" : e.textDecoration === "line-through" ? t.textDecoration = "line-through" : e.textDecoration === "underline line-through" && (t.textDecoration = "underline line-through"), t;
1249
+ }, F = (e) => ({
1250
+ left: e.x + "%",
1251
+ top: e.y + "%"
1252
+ }), I = (e) => {
1253
+ let t = {
1254
+ left: e.x + "%",
1255
+ top: e.y + "%",
1256
+ background: e.color || "#e74c3c"
1257
+ };
1258
+ return e.pointStyle === "square" ? t.borderRadius = "2px" : e.pointStyle === "diamond" ? (t.borderRadius = "2px", t.transform = "translate(-50%, -50%) rotate(45deg)") : e.pointStyle === "arrow" && (t.background = "transparent", t.border = "none", t.width = "0", t.height = "0", t.boxShadow = "none"), t;
1259
+ }, L = null, R = null, z = (e, t) => {
1260
+ l("select", e), R = "label", C.value = e.id, b.value = !0, L = {
1261
+ ann: e,
1262
+ startX: t.clientX,
1263
+ startY: t.clientY,
1264
+ origLabelX: e.labelX || 0,
1265
+ origLabelY: e.labelY || 0
1266
+ }, document.addEventListener("mousemove", V), document.addEventListener("mouseup", H);
1267
+ }, B = (e, t) => {
1268
+ l("select", e), R = "dot", C.value = e.id, b.value = !0, L = {
1269
+ ann: e,
1270
+ startX: t.clientX,
1271
+ startY: t.clientY,
1272
+ origX: e.x,
1273
+ origY: e.y
1274
+ }, document.addEventListener("mousemove", V), document.addEventListener("mouseup", H);
1275
+ }, V = (e) => {
1276
+ if (!L) return;
1277
+ let t = e.clientX - L.startX, n = e.clientY - L.startY;
1278
+ if (R === "label") L.ann.labelX = L.origLabelX + t, L.ann.labelY = L.origLabelY + n;
1279
+ else if (R === "dot") {
1280
+ let e = u.value;
1281
+ if (!e) return;
1282
+ let r = e.querySelector(".image-wrapper").getBoundingClientRect(), i = Math.max(0, Math.min(100, L.origX + t / r.width * 100)), a = Math.max(0, Math.min(100, L.origY + n / r.height * 100));
1283
+ L.ann.x = Math.round(i * 10) / 10, L.ann.y = Math.round(a * 10) / 10;
1284
+ }
1285
+ }, H = () => {
1286
+ b.value = !1, C.value = null, L = null, R = null, l("change"), document.removeEventListener("mousemove", V), document.removeEventListener("mouseup", H);
1287
+ };
1288
+ return r({ recalculateSize: k }), (t, r) => {
1289
+ let o = y("el-icon");
1290
+ return h(), i("div", {
1291
+ class: d(["annotation-canvas", { "is-dragging": b.value }]),
1292
+ ref_key: "containerRef",
1293
+ ref: u
1294
+ }, [n.imageUrl ? (h(), i("div", {
1295
+ key: 0,
1296
+ class: "image-wrapper",
1297
+ style: f({
1298
+ width: m.value + "px",
1299
+ height: g.value + "px"
1300
+ })
1301
+ }, [a("img", {
1302
+ src: n.imageUrl,
1303
+ onLoad: A,
1304
+ ref_key: "imgRef",
1305
+ ref: p,
1306
+ class: "annotation-image",
1307
+ draggable: "false"
1308
+ }, null, 40, ot), (h(!0), i(e, null, v(T.value, (e) => (h(), i("div", {
1309
+ key: e.id,
1310
+ class: d(["annotation-group", {
1311
+ selected: n.selectedId === e.id,
1312
+ "is-active": n.selectedId === e.id
1313
+ }]),
1314
+ onMousedown: E((n) => t.$emit("select", e), ["stop"])
1315
+ }, [
1316
+ (h(), i("svg", ct, [a("defs", null, [a("marker", {
1317
+ id: "arrow-start-" + e.id,
1318
+ markerWidth: "10",
1319
+ markerHeight: "7",
1320
+ refX: "1",
1321
+ refY: "3.5",
1322
+ orient: "auto",
1323
+ fill: e.lineColor || (n.selectedId === e.id ? "#409EFF" : e.color || "#e74c3c")
1324
+ }, [...r[2] ||= [a("polygon", { points: "10 0, 0 3.5, 10 7" }, null, -1)]], 8, lt)]), a("path", {
1325
+ d: j(e),
1326
+ fill: "none",
1327
+ stroke: e.lineColor || (n.selectedId === e.id ? "#409EFF" : e.color || "#e74c3c"),
1328
+ "stroke-width": e.strokeWidth || 1.5,
1329
+ "stroke-dasharray": D.value,
1330
+ "marker-start": e.pointStyle === "arrow" ? `url(#arrow-start-${e.id})` : ""
1331
+ }, null, 8, ut)])),
1332
+ a("div", {
1333
+ class: d(["annotation-label", { dragging: b.value && C.value === e.id }]),
1334
+ style: f(M(e)),
1335
+ onMousedown: E((t) => z(e, t), ["stop"])
1336
+ }, [a("span", {
1337
+ class: "annotation-number",
1338
+ style: f(N(e))
1339
+ }, x(e.number), 5), a("span", {
1340
+ class: "annotation-text",
1341
+ style: f(P(e)),
1342
+ contenteditable: "",
1343
+ onBlur: (t) => {
1344
+ e.text = t.target.textContent, l("change");
1345
+ },
1346
+ onMousedown: r[0] ||= E(() => {}, ["stop"])
1347
+ }, x(e.text), 45, ft)], 46, dt),
1348
+ e.pointStyle === "flag" ? (h(), i("div", {
1349
+ key: 0,
1350
+ class: "annotation-flag",
1351
+ style: f(F(e)),
1352
+ onMousedown: E((t) => B(e, t), ["stop"])
1353
+ }, [a("div", {
1354
+ class: "flag-pole",
1355
+ style: f({ background: e.color || "#e74c3c" })
1356
+ }, null, 4), a("div", {
1357
+ class: "flag-cloth",
1358
+ style: f({ background: e.color || "#e74c3c" })
1359
+ }, null, 4)], 44, pt)) : e.pointStyle === "arrow" ? (h(), i("div", {
1360
+ key: 2,
1361
+ class: d(["annotation-dot arrow-point", { dragging: b.value && C.value === e.id }]),
1362
+ style: f(I(e)),
1363
+ onMousedown: E((t) => B(e, t), ["stop"])
1364
+ }, null, 46, ht)) : (h(), i("div", {
1365
+ key: 1,
1366
+ class: d(["annotation-dot", [e.pointStyle || "circle", { dragging: b.value && C.value === e.id }]]),
1367
+ style: f(I(e)),
1368
+ onMousedown: E((t) => B(e, t), ["stop"])
1369
+ }, null, 46, mt))
1370
+ ], 42, st))), 128))], 4)) : (h(), i("div", {
1371
+ key: 1,
1372
+ class: "upload-placeholder",
1373
+ onClick: r[1] ||= (e) => t.$emit("upload-image")
1374
+ }, [s(o, { size: "48" }, {
1375
+ default: w(() => [s(S(oe))]),
1376
+ _: 1
1377
+ }), r[3] ||= a("p", null, "点击上传图片", -1)]))], 2);
1378
+ };
1379
+ }
1380
+ }, [["__scopeId", "data-v-d9ef76f4"]]);
1381
+ //#endregion
1382
+ //#region ../../src/composables/useExplosionCollaboration.js
1383
+ function _t(e, { roomPrefix: t, syncKey: n = "_data" } = {}) {
1384
+ let r = new X.Doc(), i = _(!1), a = _(!1), o = _(!1), s = _(!1), c = _([]), l = null, u = null, d = null, f = null, p = !1, h = null, g = `ws://${window.location.hostname || "localhost"}:1234`, v = `${t}-${e}`, y = () => {
1385
+ b(), h = setInterval(() => {
1386
+ if (l && l.connection && l.connection.ws && l.connection.ws.readyState === WebSocket.CLOSED) try {
1387
+ l.connect();
1388
+ } catch (e) {
1389
+ console.warn("[ExplosionCollab] reconnect failed:", e);
1390
+ }
1391
+ }, 3e4);
1392
+ }, b = () => {
1393
+ h &&= (clearInterval(h), null);
1394
+ };
1395
+ l = new se({
1396
+ url: g,
1397
+ name: v,
1398
+ document: r,
1399
+ connect: !1,
1400
+ reconnect: !0,
1401
+ onConnect: () => {
1402
+ i.value = !0, y();
1403
+ },
1404
+ onClose: () => {
1405
+ i.value = !1, a.value = !1;
1406
+ },
1407
+ onSynced: ({ state: e }) => {
1408
+ a.value = e;
1409
+ }
1410
+ }), l.awareness.on("change", () => {
1411
+ c.value = Array.from(l.awareness.getStates().entries()).filter(([e, t]) => t.user).map(([e, t]) => ({
1412
+ clientId: e,
1413
+ ...t.user
1414
+ }));
1415
+ }), u = r.getMap(t);
1416
+ let x = r.getMap("_meta");
1417
+ x.observe((e) => {
1418
+ e.keysChanged.has("_closed") && (s.value = x.get("_closed") === !0, s.value && console.log("[ExplosionCollab] collaboration closed by owner"));
1419
+ });
1420
+ let S = () => {
1421
+ l.connect();
1422
+ }, C = () => {
1423
+ if (b(), l) {
1424
+ try {
1425
+ l.disconnect(), l.destroy();
1426
+ } catch (e) {
1427
+ console.warn("[ExplosionCollab] disconnect error:", e);
1428
+ }
1429
+ l = null;
1430
+ }
1431
+ i.value = !1, a.value = !1, c.value = [];
1432
+ }, w = (e = {}) => (p = !1, l.connect(), new Promise((t) => {
1433
+ let n = () => {
1434
+ l && a.value ? (p = !0, e.userInfo && l.awareness.setLocalStateField("user", e.userInfo), t()) : setTimeout(n, 100);
1435
+ };
1436
+ setTimeout(n, 200);
1437
+ })), T = (e) => {
1438
+ !i.value || !u || (d && clearTimeout(d), d = setTimeout(() => {
1439
+ let t = JSON.stringify(e);
1440
+ f = t, r.transact(() => {
1441
+ u.set(n, t);
1442
+ });
1443
+ }, 50));
1444
+ }, E = () => {
1445
+ if (!u) return null;
1446
+ let e = u.get(n);
1447
+ if (!e) return null;
1448
+ f = e;
1449
+ try {
1450
+ return JSON.parse(e);
1451
+ } catch {
1452
+ return null;
1453
+ }
1454
+ }, D = (e) => {
1455
+ l && l.awareness.setLocalStateField("user", {
1456
+ id: e.id || `user-${Date.now()}`,
1457
+ name: e.name || `用户${Math.floor(Math.random() * 1e3)}`,
1458
+ color: e.color || `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`,
1459
+ ...e
1460
+ });
1461
+ }, O = () => {
1462
+ s.value = !0, r.transact(() => {
1463
+ x.set("_closed", !0);
1464
+ }), p = !1, l?.awareness?.setLocalState(null), C(), o.value = !1;
1465
+ }, k = () => x.get("_closed") === !0 ? (s.value = !0, !0) : !1, A = () => {
1466
+ C(), r.destroy();
1467
+ };
1468
+ return m(() => A()), {
1469
+ ydoc: r,
1470
+ provider: l,
1471
+ yMap: u,
1472
+ isConnected: i,
1473
+ isSynced: a,
1474
+ isCollabOwner: o,
1475
+ collaborationClosed: s,
1476
+ onlineUsers: c,
1477
+ connect: S,
1478
+ disconnect: C,
1479
+ init: w,
1480
+ pushToYjs: T,
1481
+ pullFromYjs: E,
1482
+ setLocalUser: D,
1483
+ closeCollaboration: O,
1484
+ checkCollaborationClosed: k,
1485
+ destroy: A,
1486
+ _getSyncReady: () => p,
1487
+ _setSyncReady: (e) => {
1488
+ p = e;
1489
+ },
1490
+ _getLastSyncedValue: () => f,
1491
+ _setLastSyncedValue: (e) => {
1492
+ f = e;
1493
+ }
1494
+ };
1495
+ }
1496
+ //#endregion
1497
+ //#region ../../src/composables/useExplosionImageCollaboration.js
1498
+ var vt = (e, { onRemoteChange: t } = {}) => {
1499
+ let n = _t(e, {
1500
+ roomPrefix: "explosion-image",
1501
+ syncKey: "_data"
1502
+ });
1503
+ t && n.yMap.observe((e) => {
1504
+ if (!n._getSyncReady()) return;
1505
+ let r = n.yMap.get("_data");
1506
+ if (r && r !== n._getLastSyncedValue()) {
1507
+ n._setLastSyncedValue(r);
1508
+ try {
1509
+ t(JSON.parse(r));
1510
+ } catch (e) {
1511
+ console.error("[EV-Image] remote data parse error:", e);
1512
+ }
1513
+ }
1514
+ });
1515
+ let r = (e) => {
1516
+ n.pushToYjs({
1517
+ title: e.title,
1518
+ imageUrl: e.imageUrl,
1519
+ annotations: e.annotations,
1520
+ groups: e.groups
1521
+ });
1522
+ }, i = () => n.pullFromYjs();
1523
+ return {
1524
+ ...n,
1525
+ pushToYjs: r,
1526
+ pullFromYjs: i
1527
+ };
1528
+ }, yt = { class: "explosion-image-editor" }, bt = { class: "editor-body" }, xt = { class: "canvas-area" }, St = { class: "props-panel" }, Ct = { class: "prop-row" }, wt = { class: "prop-row" }, Tt = { class: "prop-row" }, Et = { class: "prop-row" }, Dt = { class: "prop-row" }, Ot = { class: "prop-row" }, kt = { class: "prop-row" }, At = { class: "prop-row" }, jt = { class: "prop-row" }, Mt = { class: "prop-row" }, Nt = { class: "prop-row" }, Pt = { class: "prop-row" }, Ft = { class: "font-style-btns" }, It = { class: "prop-row" }, Lt = { class: "font-style-btns" }, Rt = { class: "prop-row" }, zt = { class: "prop-row" }, Bt = { class: "prop-row" }, Vt = { class: "prop-row" }, Ht = {
1529
+ key: 0,
1530
+ class: "prop-row filter-info"
1531
+ }, Ut = {
1532
+ key: 1,
1533
+ class: "no-selection"
1534
+ }, Wt = { class: "color-dialog-body" }, Gt = "explosion-image", Kt = /*#__PURE__*/ Z({
1535
+ __name: "ExplosionImageEditor",
1536
+ setup(c) {
1537
+ let l = O(), u = k(), d = _(null), f = _(null), b = _(!1), T = _(!1), { saveVersion: E } = Ne(), D = Ae(), M = g({
1538
+ title: "图片标注",
1539
+ imageUrl: "",
1540
+ annotations: [],
1541
+ groups: []
1542
+ }), N = _(!1), P = _(!1), F = _(!1), I = null, R = _("straight"), z = _(null), B = _(null), H = _(null), ee = 0, U = _(null), W = _([]), G = t(() => U.value ? M.annotations.filter((e) => e.groupId === U.value) : M.annotations), K = () => f.value?.click(), te = async (e) => {
1543
+ let t = e.target.files?.[0];
1544
+ if (!t) return;
1545
+ let n = new FormData();
1546
+ n.append("file", t);
1547
+ try {
1548
+ let e = await Y.post("/api/files/upload/image", n);
1549
+ M.imageUrl = e.data.url || e.data.file_path, $();
1550
+ } catch {
1551
+ A.error("上传失败");
1552
+ }
1553
+ }, ne = () => {
1554
+ if (!M.imageUrl) {
1555
+ A.warning("请先上传图片");
1556
+ return;
1557
+ }
1558
+ let e = M.annotations.reduce((e, t) => Math.max(e, t.number), 0);
1559
+ M.annotations.push({
1560
+ id: `ann-${++ee}-${Date.now()}`,
1561
+ number: e + 1,
1562
+ text: "",
1563
+ x: 50,
1564
+ y: 50,
1565
+ labelX: 80,
1566
+ labelY: -30,
1567
+ color: "#e74c3c",
1568
+ numberColor: "",
1569
+ textColor: "",
1570
+ labelBgColor: "",
1571
+ labelBgOpacity: 100,
1572
+ lineColor: "",
1573
+ strokeWidth: 1.5,
1574
+ pointStyle: "circle",
1575
+ fontFamily: "",
1576
+ fontSize: 13,
1577
+ fontWeight: "",
1578
+ fontStyle: "",
1579
+ textDecoration: "",
1580
+ groupId: ""
1581
+ }), $();
1582
+ }, re = (e) => {
1583
+ z.value = e.id, B.value = e;
1584
+ }, q = (e, t) => {
1585
+ B.value && (B.value[e] === t ? B.value[e] = "" : B.value[e] = t);
1586
+ }, ie = () => {
1587
+ B.value && (B.value.fontFamily = "", B.value.fontSize = 13, B.value.fontWeight = "", B.value.fontStyle = "", B.value.textDecoration = "");
1588
+ }, J = () => {
1589
+ M.annotations = M.annotations.filter((e) => e.id !== z.value), z.value = null, B.value = null, $();
1590
+ }, ae = (e) => {
1591
+ e === "new" && j.prompt("分组名称", "新建分组", { inputPlaceholder: "名称" }).then(({ value: e }) => {
1592
+ e && (M.groups.push({
1593
+ id: `grp-${Date.now()}`,
1594
+ name: e
1595
+ }), $());
1596
+ }).catch(() => {});
1597
+ }, oe = (e, t) => {
1598
+ e === "filter" ? U.value = U.value === t ? null : t : e === "collapse" ? le(t) : e === "color" ? (se.value = t, X.value = !0) : e === "delete" && j.confirm("确定删除该分组?分组内的标注将保留,但分组关系将被移除。", "删除分组", { type: "warning" }).then(() => {
1599
+ M.annotations.forEach((e) => {
1600
+ e.groupId === t && (e.groupId = "");
1601
+ }), M.groups = M.groups.filter((e) => e.id !== t), U.value === t && (U.value = null), A.success("分组已删除"), $();
1602
+ }).catch(() => {});
1603
+ }, X = _(!1), se = _(null), Z = _("#e74c3c"), ce = () => {
1604
+ M.annotations.forEach((e) => {
1605
+ e.groupId === se.value && (e.color = Z.value, e.numberColor = Z.value, e.lineColor = Z.value, e.textColor = Z.value);
1606
+ }), X.value = !1, A.success("颜色已更新"), $();
1607
+ }, le = (e) => {
1608
+ let t = W.value.indexOf(e);
1609
+ t === -1 ? W.value.push(e) : W.value.splice(t, 1);
1610
+ }, ue = () => {
1611
+ U.value = null, W.value = [];
1612
+ }, Q = async () => {
1613
+ if (N.value && I?.collaborationClosed.value && !F.value) {
1614
+ A.warning("协作已关闭,无法保存");
1615
+ return;
1616
+ }
1617
+ try {
1618
+ let e = {
1619
+ title: M.title,
1620
+ view_type: "image",
1621
+ config: JSON.stringify({
1622
+ imageUrl: M.imageUrl,
1623
+ annotations: M.annotations,
1624
+ groups: M.groups,
1625
+ lineStyle: R.value
1626
+ })
1627
+ };
1628
+ d.value ? await Y.put(`/api/explosion-views/${d.value}`, e) : d.value = (await Y.post("/api/explosion-views/", e)).data.id, A.success("保存成功"), E({
1629
+ documentId: d.value,
1630
+ docType: "image",
1631
+ content: JSON.stringify({
1632
+ imageUrl: M.imageUrl,
1633
+ annotations: M.annotations,
1634
+ groups: M.groups,
1635
+ lineStyle: R.value
1636
+ }),
1637
+ userId: String(D.currentUser.value?.id || ""),
1638
+ userName: D.currentUser.value?.name || "未知"
1639
+ });
1640
+ } catch {
1641
+ A.error("保存失败");
1642
+ }
1643
+ }, de = async () => {
1644
+ if (l.params.id) try {
1645
+ let e = (await Y.get(`/api/explosion-views/${l.params.id}`)).data;
1646
+ if (d.value = e.id, M.title = e.title, e.config) {
1647
+ let t = JSON.parse(e.config);
1648
+ M.imageUrl = t.imageUrl || "", M.annotations = t.annotations || [], M.groups = t.groups || [], R.value = t.lineStyle || "straight";
1649
+ }
1650
+ } catch (e) {
1651
+ console.error(e);
1652
+ }
1653
+ }, fe = () => u.push("/"), pe = [
1654
+ "我可以帮您优化图片标注、检查注释内容,或者提供标注建议。请问有什么需要帮助的?",
1655
+ "这张图片的标注很详细。建议检查标注线条是否清晰,避免与其他标注重叠。",
1656
+ "根据当前的标注内容,我建议为关键部件添加更详细的文字说明。",
1657
+ "我可以帮您检查标注中是否有遗漏的区域或重复的编号。需要我逐个分析吗?",
1658
+ "建议使用不同颜色的标注来区分不同类别的部件,提高可读性。",
1659
+ "图片标注的分组功能可以帮助您管理复杂的标注。建议按功能模块进行分组。",
1660
+ "我可以帮您将标注信息整理成表格,方便后续查阅和修改。",
1661
+ "标注的连线样式建议统一,直线适合简单标注,折线适合复杂场景。"
1662
+ ], me = async (e, t = {}) => {
1663
+ let n = d.value ? `${Gt}-${d.value}` : null;
1664
+ await D.sendMessage(e, {
1665
+ ...t,
1666
+ roomId: n
1667
+ });
1668
+ let r = t.mentionedUser, i = r && r.toLowerCase().includes("ai"), a = D.collabUsers.value.filter((e) => e.name !== D.currentUser.value.name);
1669
+ (!r || i || a.length === 0) && (D.loading.value = !0, setTimeout(() => {
1670
+ D.sendAiMessage(pe[Math.floor(Math.random() * pe.length)], n), D.loading.value = !1;
1671
+ }, 800 + Math.random() * 1200));
1672
+ }, he = () => {
1673
+ let e = d.value ? `${Gt}-${d.value}` : null;
1674
+ D.clearMessages(e);
1675
+ }, ge = () => {
1676
+ if (!d.value) {
1677
+ A.warning("请先保存文档");
1678
+ return;
1679
+ }
1680
+ T.value = !0;
1681
+ }, _e = (e) => {
1682
+ try {
1683
+ let t = typeof e == "string" ? JSON.parse(e) : e;
1684
+ t.imageUrl && (M.imageUrl = t.imageUrl), t.annotations && (M.annotations = t.annotations), t.groups && (M.groups = t.groups), t.lineStyle && (R.value = t.lineStyle), z.value = null, B.value = null;
1685
+ } catch (e) {
1686
+ console.error("Version apply error:", e);
1687
+ }
1688
+ }, ve = (e) => {
1689
+ if (e === "png" || e === "png-filtered") {
1690
+ let t = document.querySelector(".annotation-image");
1691
+ if (!t) return A.error("未找到图片");
1692
+ let n = document.createElement("canvas");
1693
+ n.width = t.naturalWidth, n.height = t.naturalHeight;
1694
+ let r = n.getContext("2d");
1695
+ r.drawImage(t, 0, 0);
1696
+ let i = n.width / t.clientWidth, a = n.height / t.clientHeight, o = Math.max(i, a), s = e === "png-filtered" ? G.value : M.annotations, c = [
1697
+ "dashed",
1698
+ "dotted",
1699
+ "dashdot"
1700
+ ].includes(R.value) ? "straight" : R.value, l = s.map((e) => {
1701
+ let t = e.x / 100 * n.width, r = e.y / 100 * n.height;
1702
+ return {
1703
+ ann: e,
1704
+ x: t,
1705
+ y: r,
1706
+ lx: t + (e.labelX || 0) * i,
1707
+ ly: r + (e.labelY || 0) * a
1708
+ };
1709
+ });
1710
+ l.forEach(({ ann: e, x: t, y: n, lx: s, ly: l }) => {
1711
+ let u = e.color || "#e74c3c", d = e.lineColor || u, f = (e.strokeWidth || 1.5) * o;
1712
+ if (r.strokeStyle = d, r.lineWidth = f, r.setLineDash([]), c === "dashed" ? r.setLineDash([8 * i, 4 * a]) : c === "dotted" ? r.setLineDash([3 * i, 3 * a]) : c === "dashdot" && r.setLineDash([
1713
+ 8 * i,
1714
+ 3 * a,
1715
+ 2 * i,
1716
+ 3 * a
1717
+ ]), r.beginPath(), c === "polyline") {
1718
+ let a = e.x < 50 ? t + 20 * i : t - 20 * i;
1719
+ r.moveTo(t, n), r.lineTo(a, n), r.lineTo(s, l);
1720
+ } else if (c === "right-angle") r.moveTo(t, n), r.lineTo(t, l), r.lineTo(s, l);
1721
+ else if (c === "curve") {
1722
+ let a = e.x < 50 ? t + 30 * i : t - 30 * i;
1723
+ r.moveTo(t, n), r.bezierCurveTo(a, n, s, l, s, l);
1724
+ } else if (c === "wave") {
1725
+ let e = s - t, o = l - n, c = Math.sqrt(e * e + o * o), u = Math.max(2, Math.floor(c / (20 * i)));
1726
+ r.moveTo(t, n);
1727
+ for (let i = 1; i <= u; i++) {
1728
+ let s = i / u;
1729
+ r.lineTo(t + e * s, n + o * s + Math.sin(s * Math.PI * u / 2) * 8 * a);
1730
+ }
1731
+ } else r.moveTo(t, n), r.lineTo(s, l);
1732
+ r.stroke(), r.setLineDash([]);
1733
+ let p = 10 * o, m = e.pointStyle || "circle";
1734
+ if (m === "square") r.fillStyle = u, r.fillRect(t - p, n - p, p * 2, p * 2);
1735
+ else if (m === "diamond") r.fillStyle = u, r.beginPath(), r.moveTo(t, n - p * 1.2), r.lineTo(t + p * 1.2, n), r.lineTo(t, n + p * 1.2), r.lineTo(t - p * 1.2, n), r.closePath(), r.fill();
1736
+ else if (m === "arrow") {
1737
+ r.fillStyle = d, r.beginPath();
1738
+ let e = Math.atan2(l - n, s - t), i = p * 1.5;
1739
+ r.moveTo(t + Math.cos(e) * i, n + Math.sin(e) * i), r.lineTo(t + Math.cos(e + 2.5) * i * .6, n + Math.sin(e + 2.5) * i * .6), r.lineTo(t + Math.cos(e - 2.5) * i * .6, n + Math.sin(e - 2.5) * i * .6), r.closePath(), r.fill();
1740
+ } else m === "flag" ? (r.strokeStyle = u, r.lineWidth = 2 * o, r.beginPath(), r.moveTo(t, n), r.lineTo(t, n - 20 * a), r.stroke(), r.fillStyle = u, r.beginPath(), r.moveTo(t, n - 20 * a), r.lineTo(t + 14 * i, n - 15 * a), r.lineTo(t, n - 10 * a), r.closePath(), r.fill()) : (r.fillStyle = u, r.beginPath(), r.arc(t, n, p, 0, Math.PI * 2), r.fill());
1741
+ }), 10 * o, l.forEach(({ ann: e, lx: t, ly: n }) => {
1742
+ let i = e.color || "#e74c3c", a = e.numberColor || i, s = 11 * o;
1743
+ if (r.fillStyle = a, r.beginPath(), r.arc(t, n, s, 0, Math.PI * 2), r.fill(), r.fillStyle = "#fff", r.font = `bold ${s}px sans-serif`, r.textAlign = "center", r.textBaseline = "middle", r.fillText(String(e.number), t, n), e.text) {
1744
+ let i = (e.fontSize || 13) * o, a = e.fontWeight === "bold" || e.fontWeight === "bolder" ? "bold " : "";
1745
+ r.font = `${e.fontStyle === "italic" || e.fontStyle === "oblique" ? "italic " : ""}${a}${i}px ${e.fontFamily || "sans-serif"}`;
1746
+ let c = r.measureText(e.text).width, l = 4 * o, u = t + s + l, d = u - l, f = n - i / 2 - l, p = c + l * 2, m = i + l * 2;
1747
+ if (e.labelBgColor) {
1748
+ let t = (e.labelBgOpacity ?? 100) / 100, n = e.labelBgColor;
1749
+ r.fillStyle = `rgba(${parseInt(n.slice(1, 3), 16)}, ${parseInt(n.slice(3, 5), 16)}, ${parseInt(n.slice(5, 7), 16)}, ${t})`;
1750
+ } else r.fillStyle = "rgba(255,255,255,0.9)";
1751
+ r.beginPath(), r.roundRect(d, f, p, m, 3 * o), r.fill(), r.fillStyle = e.textColor || "#333", r.textAlign = "left", r.textBaseline = "middle", r.fillText(e.text, u, n);
1752
+ }
1753
+ }), n.toBlob((e) => {
1754
+ let t = document.createElement("a");
1755
+ t.href = URL.createObjectURL(e), t.download = `${M.title || "图片标注"}.png`, t.click();
1756
+ });
1757
+ } else e === "json" ? ye() : A.info(`导出 ${e} 开发中`);
1758
+ }, ye = () => {
1759
+ let e = {
1760
+ title: M.title,
1761
+ imageUrl: M.imageUrl,
1762
+ annotations: M.annotations,
1763
+ groups: M.groups,
1764
+ lineStyle: R.value,
1765
+ exportTime: (/* @__PURE__ */ new Date()).toISOString()
1766
+ }, t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), n = document.createElement("a");
1767
+ n.href = URL.createObjectURL(t), n.download = `${M.title || "爆炸图"}.json`, n.click(), A.success("JSON已导出");
1768
+ }, be = (e) => {
1769
+ let t = e.target.files[0];
1770
+ if (!t) return;
1771
+ let n = new FileReader();
1772
+ n.onload = (e) => {
1773
+ try {
1774
+ let t = JSON.parse(e.target.result);
1775
+ if (!t.imageUrl && (!t.annotations || !t.annotations.length)) {
1776
+ A.error("JSON格式无效:缺少图片或标注数据");
1777
+ return;
1778
+ }
1779
+ M.title = t.title || "图片标注", M.imageUrl = t.imageUrl || "", M.annotations = t.annotations || [], M.groups = t.groups || [], R.value = t.lineStyle || "straight", z.value = null, B.value = null, $(), A.success("导入成功");
1780
+ } catch {
1781
+ A.error("JSON解析失败,请检查文件格式");
1782
+ }
1783
+ }, n.readAsText(t), e.target.value = "";
1784
+ }, $ = () => {
1785
+ N.value && I && I.pushToYjs(M);
1786
+ };
1787
+ C(B, () => {
1788
+ $();
1789
+ }, { deep: !0 });
1790
+ let xe = (e) => {
1791
+ I &&= (I.destroy(), null), I = vt(e, { onRemoteChange: (e) => {
1792
+ e.title && (M.title = e.title), e.imageUrl && (M.imageUrl = e.imageUrl), e.annotations && (M.annotations = e.annotations), e.groups && (M.groups = e.groups);
1793
+ } }), I._setSyncReady(!1);
1794
+ }, Se = async () => {
1795
+ if (N.value) return;
1796
+ if (!d.value && (await Q(), !d.value)) {
1797
+ A.error("请先保存文档");
1798
+ return;
1799
+ }
1800
+ xe(String(d.value)), I.connect();
1801
+ let e = {
1802
+ name: `用户${Math.floor(Math.random() * 1e3)}`,
1803
+ color: `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`
1804
+ }, t = () => {
1805
+ if (I.provider && I.provider.synced) {
1806
+ I._setSyncReady(!0), I.setLocalUser(e);
1807
+ let t = I.pullFromYjs();
1808
+ t ? (t.title && (M.title = t.title), t.imageUrl && (M.imageUrl = t.imageUrl), t.annotations && (M.annotations = t.annotations), t.groups && (M.groups = t.groups)) : (M.annotations.length > 0 || M.imageUrl) && I.pushToYjs(M), N.value = !0, F.value = !0, P.value = !1, D.setCollabContext({
1809
+ ydoc: I.ydoc,
1810
+ provider: I.provider,
1811
+ onlineUsers: I.onlineUsers
1812
+ }), D.setCurrentUser({
1813
+ id: I.provider.awareness.clientID,
1814
+ name: e.name,
1815
+ color: e.color
1816
+ }), A.success("协作已开启");
1817
+ } else setTimeout(t, 100);
1818
+ };
1819
+ setTimeout(t, 200);
1820
+ }, Ce = () => {
1821
+ I && (I.closeCollaboration(), N.value = !1, F.value = !1, A.info("协作已关闭"));
1822
+ }, we = () => {
1823
+ let e = l.params.id;
1824
+ if (!e) return;
1825
+ xe(e), I.connect();
1826
+ let t = {
1827
+ name: `协作人${Math.floor(Math.random() * 1e3)}`,
1828
+ color: `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`
1829
+ }, n = () => {
1830
+ if (I.provider && I.provider.synced) {
1831
+ if (I.checkCollaborationClosed()) {
1832
+ I.disconnect(), N.value = !1, A.warning("该协作已关闭,无法加入");
1833
+ return;
1834
+ }
1835
+ I._setSyncReady(!0), I.setLocalUser(t);
1836
+ let e = I.pullFromYjs();
1837
+ e && (e.title && (M.title = e.title), e.imageUrl && (M.imageUrl = e.imageUrl), e.annotations && (M.annotations = e.annotations), e.groups && (M.groups = e.groups)), N.value = !0, F.value = !1, D.setCollabContext({
1838
+ ydoc: I.ydoc,
1839
+ provider: I.provider,
1840
+ onlineUsers: I.onlineUsers
1841
+ }), D.setCurrentUser({
1842
+ id: I.provider.awareness.clientID,
1843
+ name: t.name,
1844
+ color: t.color
1845
+ }), A.success("已加入协作");
1846
+ } else setTimeout(n, 100);
1847
+ };
1848
+ setTimeout(n, 200);
1849
+ }, Te = () => {
1850
+ N.value ? Ce() : Se();
1851
+ }, Ee = async () => {
1852
+ if (N.value || await Se(), !d.value && (await Q(), !d.value)) {
1853
+ A.warning("请先保存文档后再分享");
1854
+ return;
1855
+ }
1856
+ let e = `${window.location.origin}/explosion-image/${d.value}?collab=1`;
1857
+ try {
1858
+ await navigator.clipboard.writeText(e), A.success("协作链接已复制到剪贴板");
1859
+ } catch {
1860
+ A.info("协作链接: " + e);
1861
+ }
1862
+ };
1863
+ p(async () => {
1864
+ let e = localStorage.getItem("editor-user-name") || `用户${Math.floor(Math.random() * 1e3)}`;
1865
+ localStorage.setItem("editor-user-name", e), D.setCurrentUser({
1866
+ id: Date.now(),
1867
+ name: e,
1868
+ color: "#409eff"
1869
+ }), await de(), l.params.id && l.query.collab === "1" && we();
1870
+ });
1871
+ let De = (e) => {
1872
+ e.key === "Delete" && z.value && J();
1873
+ };
1874
+ return p(() => document.addEventListener("keydown", De)), m(() => {
1875
+ document.removeEventListener("keydown", De), I &&= (I.destroy(), null);
1876
+ }), (t, c) => {
1877
+ let u = y("el-input-number"), p = y("el-input"), m = y("el-color-picker"), g = y("el-option"), _ = y("el-select"), C = y("el-slider"), E = y("el-button"), O = y("el-icon"), k = y("el-tag"), A = y("el-dialog"), j = y("Monitor");
1878
+ return h(), i("div", yt, [
1879
+ s(at, {
1880
+ title: M.title,
1881
+ "onUpdate:title": c[0] ||= (e) => M.title = e,
1882
+ "line-style": R.value,
1883
+ groups: M.groups,
1884
+ "active-group-id": U.value,
1885
+ "collapsed-groups": W.value,
1886
+ "is-connected": N.value,
1887
+ "online-users": S(I) ? S(I).onlineUsers.value : [],
1888
+ "is-join-mode": S(l).query.collab === "1",
1889
+ onBack: fe,
1890
+ onAddAnnotation: ne,
1891
+ onSetLineStyle: c[1] ||= (e) => R.value = e,
1892
+ onAddGroup: ae,
1893
+ onGroupAction: oe,
1894
+ onClearGroupFilter: ue,
1895
+ onExport: ve,
1896
+ onImportJson: be,
1897
+ onSave: Q,
1898
+ onToggleCollab: Te,
1899
+ onShareCollab: Ee,
1900
+ "show-history": !!d.value,
1901
+ onHistory: ge
1902
+ }, null, 8, [
1903
+ "title",
1904
+ "line-style",
1905
+ "groups",
1906
+ "active-group-id",
1907
+ "collapsed-groups",
1908
+ "is-connected",
1909
+ "online-users",
1910
+ "is-join-mode",
1911
+ "show-history"
1912
+ ]),
1913
+ a("div", bt, [a("div", xt, [s(gt, {
1914
+ ref_key: "annotationCanvasRef",
1915
+ ref: H,
1916
+ "image-url": M.imageUrl,
1917
+ annotations: G.value,
1918
+ "collapsed-groups": W.value,
1919
+ "selected-id": z.value,
1920
+ "line-style": R.value,
1921
+ onSelect: re,
1922
+ onUploadImage: K,
1923
+ onChange: $
1924
+ }, null, 8, [
1925
+ "image-url",
1926
+ "annotations",
1927
+ "collapsed-groups",
1928
+ "selected-id",
1929
+ "line-style"
1930
+ ]), a("input", {
1931
+ ref_key: "fileInputRef",
1932
+ ref: f,
1933
+ type: "file",
1934
+ accept: "image/*",
1935
+ style: { display: "none" },
1936
+ onChange: te
1937
+ }, null, 544)]), a("div", St, [c[58] ||= a("h4", null, "标注属性", -1), B.value ? (h(), i(e, { key: 0 }, [
1938
+ a("div", Ct, [c[31] ||= a("label", null, "编号", -1), s(u, {
1939
+ modelValue: B.value.number,
1940
+ "onUpdate:modelValue": c[2] ||= (e) => B.value.number = e,
1941
+ min: 1,
1942
+ size: "small"
1943
+ }, null, 8, ["modelValue"])]),
1944
+ a("div", wt, [c[32] ||= a("label", null, "文字", -1), s(p, {
1945
+ modelValue: B.value.text,
1946
+ "onUpdate:modelValue": c[3] ||= (e) => B.value.text = e,
1947
+ size: "small"
1948
+ }, null, 8, ["modelValue"])]),
1949
+ a("div", Tt, [c[33] ||= a("label", null, "引线颜色", -1), s(m, {
1950
+ modelValue: B.value.lineColor,
1951
+ "onUpdate:modelValue": c[4] ||= (e) => B.value.lineColor = e,
1952
+ size: "small",
1953
+ "show-alpha": ""
1954
+ }, null, 8, ["modelValue"])]),
1955
+ a("div", Et, [c[34] ||= a("label", null, "标注点样式", -1), s(_, {
1956
+ modelValue: B.value.pointStyle,
1957
+ "onUpdate:modelValue": c[5] ||= (e) => B.value.pointStyle = e,
1958
+ size: "small"
1959
+ }, {
1960
+ default: w(() => [
1961
+ s(g, {
1962
+ label: "圆形",
1963
+ value: "circle"
1964
+ }),
1965
+ s(g, {
1966
+ label: "方形",
1967
+ value: "square"
1968
+ }),
1969
+ s(g, {
1970
+ label: "菱形",
1971
+ value: "diamond"
1972
+ }),
1973
+ s(g, {
1974
+ label: "箭头",
1975
+ value: "arrow"
1976
+ }),
1977
+ s(g, {
1978
+ label: "红旗",
1979
+ value: "flag"
1980
+ })
1981
+ ]),
1982
+ _: 1
1983
+ }, 8, ["modelValue"])]),
1984
+ a("div", Dt, [c[35] ||= a("label", null, "标注点颜色", -1), s(m, {
1985
+ modelValue: B.value.color,
1986
+ "onUpdate:modelValue": c[6] ||= (e) => B.value.color = e,
1987
+ size: "small"
1988
+ }, null, 8, ["modelValue"])]),
1989
+ a("div", Ot, [c[36] ||= a("label", null, "编号颜色", -1), s(m, {
1990
+ modelValue: B.value.numberColor,
1991
+ "onUpdate:modelValue": c[7] ||= (e) => B.value.numberColor = e,
1992
+ size: "small"
1993
+ }, null, 8, ["modelValue"])]),
1994
+ a("div", kt, [c[37] ||= a("label", null, "文字颜色", -1), s(m, {
1995
+ modelValue: B.value.textColor,
1996
+ "onUpdate:modelValue": c[8] ||= (e) => B.value.textColor = e,
1997
+ size: "small"
1998
+ }, null, 8, ["modelValue"])]),
1999
+ a("div", At, [c[38] ||= a("label", null, "文字背景色", -1), s(m, {
2000
+ modelValue: B.value.labelBgColor,
2001
+ "onUpdate:modelValue": c[9] ||= (e) => B.value.labelBgColor = e,
2002
+ size: "small",
2003
+ "show-alpha": ""
2004
+ }, null, 8, ["modelValue"])]),
2005
+ a("div", jt, [c[39] ||= a("label", null, "背景透明度", -1), s(C, {
2006
+ modelValue: B.value.labelBgOpacity,
2007
+ "onUpdate:modelValue": c[10] ||= (e) => B.value.labelBgOpacity = e,
2008
+ min: 0,
2009
+ max: 100,
2010
+ step: 5,
2011
+ "show-input": "",
2012
+ "input-size": "small"
2013
+ }, null, 8, ["modelValue"])]),
2014
+ a("div", Mt, [c[40] ||= a("label", null, "字体", -1), s(_, {
2015
+ modelValue: B.value.fontFamily,
2016
+ "onUpdate:modelValue": c[11] ||= (e) => B.value.fontFamily = e,
2017
+ size: "small",
2018
+ clearable: ""
2019
+ }, {
2020
+ default: w(() => [
2021
+ s(g, {
2022
+ label: "默认",
2023
+ value: ""
2024
+ }),
2025
+ s(g, {
2026
+ label: "宋体",
2027
+ value: "SimSun"
2028
+ }),
2029
+ s(g, {
2030
+ label: "黑体",
2031
+ value: "SimHei"
2032
+ }),
2033
+ s(g, {
2034
+ label: "微软雅黑",
2035
+ value: "Microsoft YaHei"
2036
+ }),
2037
+ s(g, {
2038
+ label: "楷体",
2039
+ value: "KaiTi"
2040
+ }),
2041
+ s(g, {
2042
+ label: "Arial",
2043
+ value: "Arial"
2044
+ }),
2045
+ s(g, {
2046
+ label: "Times New Roman",
2047
+ value: "Times New Roman"
2048
+ })
2049
+ ]),
2050
+ _: 1
2051
+ }, 8, ["modelValue"])]),
2052
+ a("div", Nt, [c[41] ||= a("label", null, "字号", -1), s(u, {
2053
+ modelValue: B.value.fontSize,
2054
+ "onUpdate:modelValue": c[12] ||= (e) => B.value.fontSize = e,
2055
+ min: 10,
2056
+ max: 32,
2057
+ size: "small"
2058
+ }, null, 8, ["modelValue"])]),
2059
+ a("div", Pt, [c[46] ||= a("label", null, "字体样式", -1), a("div", Ft, [
2060
+ s(E, {
2061
+ type: B.value.fontWeight === "bold" ? "primary" : "",
2062
+ size: "small",
2063
+ onClick: c[13] ||= (e) => q("fontWeight", "bold")
2064
+ }, {
2065
+ default: w(() => [...c[42] ||= [a("b", null, "B", -1)]]),
2066
+ _: 1
2067
+ }, 8, ["type"]),
2068
+ s(E, {
2069
+ type: B.value.fontWeight === "bolder" ? "primary" : "",
2070
+ size: "small",
2071
+ onClick: c[14] ||= (e) => q("fontWeight", "bolder")
2072
+ }, {
2073
+ default: w(() => [...c[43] ||= [a("b", { style: { "font-size": "14px" } }, "B", -1)]]),
2074
+ _: 1
2075
+ }, 8, ["type"]),
2076
+ s(E, {
2077
+ type: B.value.fontStyle === "italic" ? "primary" : "",
2078
+ size: "small",
2079
+ onClick: c[15] ||= (e) => q("fontStyle", "italic")
2080
+ }, {
2081
+ default: w(() => [...c[44] ||= [a("i", null, "I", -1)]]),
2082
+ _: 1
2083
+ }, 8, ["type"]),
2084
+ s(E, {
2085
+ type: B.value.fontStyle === "oblique" ? "primary" : "",
2086
+ size: "small",
2087
+ onClick: c[16] ||= (e) => q("fontStyle", "oblique")
2088
+ }, {
2089
+ default: w(() => [...c[45] ||= [a("i", { style: { "font-style": "oblique" } }, "I", -1)]]),
2090
+ _: 1
2091
+ }, 8, ["type"])
2092
+ ])]),
2093
+ a("div", It, [c[51] ||= a("label", null, "装饰", -1), a("div", Lt, [
2094
+ s(E, {
2095
+ type: B.value.textDecoration === "underline" ? "primary" : "",
2096
+ size: "small",
2097
+ onClick: c[17] ||= (e) => q("textDecoration", "underline")
2098
+ }, {
2099
+ default: w(() => [...c[47] ||= [a("u", null, "U", -1)]]),
2100
+ _: 1
2101
+ }, 8, ["type"]),
2102
+ s(E, {
2103
+ type: B.value.textDecoration === "line-through" ? "primary" : "",
2104
+ size: "small",
2105
+ onClick: c[18] ||= (e) => q("textDecoration", "line-through")
2106
+ }, {
2107
+ default: w(() => [...c[48] ||= [a("s", null, "S", -1)]]),
2108
+ _: 1
2109
+ }, 8, ["type"]),
2110
+ s(E, {
2111
+ type: B.value.textDecoration === "underline line-through" ? "primary" : "",
2112
+ size: "small",
2113
+ onClick: c[19] ||= (e) => q("textDecoration", "underline line-through")
2114
+ }, {
2115
+ default: w(() => [...c[49] ||= [a("u", null, [a("s", null, "U")], -1)]]),
2116
+ _: 1
2117
+ }, 8, ["type"]),
2118
+ s(E, {
2119
+ size: "small",
2120
+ onClick: ie
2121
+ }, {
2122
+ default: w(() => [...c[50] ||= [o("清除", -1)]]),
2123
+ _: 1
2124
+ })
2125
+ ])]),
2126
+ a("div", Rt, [c[52] ||= a("label", null, "X% (点)", -1), s(C, {
2127
+ modelValue: B.value.x,
2128
+ "onUpdate:modelValue": c[20] ||= (e) => B.value.x = e,
2129
+ min: 0,
2130
+ max: 100,
2131
+ step: .5,
2132
+ "show-input": "",
2133
+ "input-size": "small"
2134
+ }, null, 8, ["modelValue"])]),
2135
+ a("div", zt, [c[53] ||= a("label", null, "Y% (点)", -1), s(C, {
2136
+ modelValue: B.value.y,
2137
+ "onUpdate:modelValue": c[21] ||= (e) => B.value.y = e,
2138
+ min: 0,
2139
+ max: 100,
2140
+ step: .5,
2141
+ "show-input": "",
2142
+ "input-size": "small"
2143
+ }, null, 8, ["modelValue"])]),
2144
+ a("div", Bt, [c[54] ||= a("label", null, "线宽", -1), s(u, {
2145
+ modelValue: B.value.strokeWidth,
2146
+ "onUpdate:modelValue": c[22] ||= (e) => B.value.strokeWidth = e,
2147
+ min: 1,
2148
+ max: 5,
2149
+ size: "small"
2150
+ }, null, 8, ["modelValue"])]),
2151
+ a("div", Vt, [c[55] ||= a("label", null, "分组", -1), s(_, {
2152
+ modelValue: B.value.groupId,
2153
+ "onUpdate:modelValue": c[23] ||= (e) => B.value.groupId = e,
2154
+ size: "small",
2155
+ clearable: ""
2156
+ }, {
2157
+ default: w(() => [(h(!0), i(e, null, v(M.groups, (e) => (h(), n(g, {
2158
+ key: e.id,
2159
+ label: e.name,
2160
+ value: e.id
2161
+ }, null, 8, ["label", "value"]))), 128))]),
2162
+ _: 1
2163
+ }, 8, ["modelValue"])]),
2164
+ U.value ? (h(), i("div", Ht, [s(k, {
2165
+ size: "small",
2166
+ type: "info"
2167
+ }, {
2168
+ default: w(() => [o(" 当前筛选: " + x(M.groups.find((e) => e.id === U.value)?.name || "未知分组") + " ", 1), s(O, {
2169
+ class: "el-tag__close",
2170
+ onClick: ue
2171
+ }, {
2172
+ default: w(() => [s(S(L))]),
2173
+ _: 1
2174
+ })]),
2175
+ _: 1
2176
+ })])) : r("", !0),
2177
+ s(E, {
2178
+ size: "small",
2179
+ type: "danger",
2180
+ onClick: J
2181
+ }, {
2182
+ default: w(() => [...c[56] ||= [o("删除", -1)]]),
2183
+ _: 1
2184
+ })
2185
+ ], 64)) : (h(), i("div", Ut, [s(O, {
2186
+ size: "48",
2187
+ color: "#ccc"
2188
+ }, {
2189
+ default: w(() => [s(S(V))]),
2190
+ _: 1
2191
+ }), c[57] ||= a("p", null, "点击标注进行编辑", -1)]))])]),
2192
+ s(A, {
2193
+ modelValue: X.value,
2194
+ "onUpdate:modelValue": c[26] ||= (e) => X.value = e,
2195
+ title: "批量修改颜色",
2196
+ width: "320px",
2197
+ "show-close": !0
2198
+ }, {
2199
+ footer: w(() => [s(E, { onClick: c[25] ||= (e) => X.value = !1 }, {
2200
+ default: w(() => [...c[60] ||= [o("取消", -1)]]),
2201
+ _: 1
2202
+ }), s(E, {
2203
+ type: "primary",
2204
+ onClick: ce
2205
+ }, {
2206
+ default: w(() => [...c[61] ||= [o("确定", -1)]]),
2207
+ _: 1
2208
+ })]),
2209
+ default: w(() => [a("div", Wt, [c[59] ||= a("span", null, "选择颜色:", -1), s(m, {
2210
+ modelValue: Z.value,
2211
+ "onUpdate:modelValue": c[24] ||= (e) => Z.value = e,
2212
+ "show-alpha": ""
2213
+ }, null, 8, ["modelValue"])])]),
2214
+ _: 1
2215
+ }, 8, ["modelValue"]),
2216
+ s(E, {
2217
+ class: "ai-chat-fab",
2218
+ type: b.value ? "primary" : "default",
2219
+ circle: "",
2220
+ size: "large",
2221
+ onClick: c[27] ||= (e) => b.value = !b.value,
2222
+ title: "AI助手"
2223
+ }, {
2224
+ default: w(() => [s(O, null, {
2225
+ default: w(() => [s(j)]),
2226
+ _: 1
2227
+ })]),
2228
+ _: 1
2229
+ }, 8, ["type"]),
2230
+ s(ke, {
2231
+ visible: b.value,
2232
+ messages: S(D).messages.value,
2233
+ loading: S(D).loading.value,
2234
+ "is-collab": S(D).isCollabMode.value,
2235
+ "collab-users": S(D).collabUsers.value,
2236
+ "current-user": S(D).currentUser.value,
2237
+ "is-owner": F.value,
2238
+ onSend: me,
2239
+ onClose: c[28] ||= (e) => b.value = !1,
2240
+ "unread-mention": S(D).unreadMention.value,
2241
+ onClearUnread: c[29] ||= (e) => S(D).clearUnreadMention(),
2242
+ onClear: he
2243
+ }, null, 8, [
2244
+ "visible",
2245
+ "messages",
2246
+ "loading",
2247
+ "is-collab",
2248
+ "collab-users",
2249
+ "current-user",
2250
+ "is-owner",
2251
+ "unread-mention"
2252
+ ]),
2253
+ s(Ge, {
2254
+ modelValue: T.value,
2255
+ "onUpdate:modelValue": c[30] ||= (e) => T.value = e,
2256
+ "document-id": d.value,
2257
+ onApply: _e
2258
+ }, null, 8, ["modelValue", "document-id"])
2259
+ ]);
2260
+ };
2261
+ }
2262
+ }, [["__scopeId", "data-v-8aef20c7"]]), qt = c({
2263
+ name: "YourCompanyExplosionImage",
2264
+ props: {
2265
+ docId: {
2266
+ type: [Number, String],
2267
+ default: null
2268
+ },
2269
+ apiBase: {
2270
+ type: String,
2271
+ default: "/api"
2272
+ },
2273
+ wsUrl: {
2274
+ type: String,
2275
+ default: ""
2276
+ },
2277
+ user: {
2278
+ type: Object,
2279
+ default: () => ({
2280
+ id: "",
2281
+ name: "",
2282
+ color: ""
2283
+ })
2284
+ },
2285
+ roomId: {
2286
+ type: String,
2287
+ default: ""
2288
+ }
2289
+ },
2290
+ setup(e, { slots: t }) {
2291
+ return () => l("div", {
2292
+ class: "yourcompany-explosion-image-wrapper",
2293
+ style: "position:relative"
2294
+ }, [l(Kt, { ...e }), l(D)]);
2295
+ }
2296
+ });
2297
+ //#endregion
2298
+ export { qt as default };