@billtaofbj/explosion-diagram 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,2758 @@
1
+ import { Fragment as e, Transition as t, computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, defineComponent as l, h as u, nextTick as d, normalizeClass as f, normalizeStyle as p, onMounted as m, onUnmounted as h, openBlock as g, reactive as _, ref as v, renderList as y, resolveComponent 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 ee, Back as te, Bell as N, Clock as P, Close as F, Connection as I, Delete as L, Download as R, Files as z, Link as B, Loading as V, Monitor as H, Promotion as U, RefreshLeft as W, RefreshRight as ne, Share as re, Upload as G, ZoomIn as ie, ZoomOut as K } from "@element-plus/icons-vue";
6
+ import q from "axios";
7
+ import * as J from "yjs";
8
+ import { HocuspocusProvider as ae } from "@hocuspocus/provider";
9
+ //#region \0plugin-vue:export-helper
10
+ var Y = (e, t) => {
11
+ let n = e.__vccOpts || e;
12
+ for (let [e, r] of t) n[e] = r;
13
+ return n;
14
+ }, oe = { class: "chat-header" }, se = { class: "chat-header-left" }, X = { class: "chat-title" }, ce = { class: "online-users-list" }, le = { class: "online-user-item" }, ue = { class: "online-user-name" }, de = { key: 1 }, fe = { class: "online-user-name" }, pe = { class: "chat-header-right" }, Z = {
15
+ key: 0,
16
+ class: "chat-empty"
17
+ }, me = { class: "chat-empty-hint" }, he = { key: 1 }, ge = { class: "message-content" }, Q = {
18
+ key: 0,
19
+ class: "message-meta"
20
+ }, _e = {
21
+ key: 0,
22
+ class: "message-mention"
23
+ }, ve = ["innerHTML"], ye = { class: "message-time" }, $ = {
24
+ key: 1,
25
+ class: "chat-message chat-message-ai"
26
+ }, be = { class: "message-avatar ai" }, xe = { class: "chat-input-area" }, Se = {
27
+ key: 0,
28
+ class: "mention-popup"
29
+ }, Ce = ["onClick", "onMouseenter"], we = { key: 1 }, Te = /*#__PURE__*/ Y({
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(t, { emit: l }) {
80
+ let u = t, m = l, h = v(""), _ = v(null), D = v(null), O = v(!1), k = v([]), A = v(0), j = "", M = -1, ee = {
81
+ id: "ai-assistant",
82
+ name: "AI助手",
83
+ color: "#409EFF",
84
+ isAi: !0
85
+ }, te = n(() => {
86
+ let e = u.currentUser.id, t = /* @__PURE__ */ new Set();
87
+ return [ee, ...u.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
+ }), P = n(() => te.value.length + 1), I = (e) => e.role === "ai" ? "chat-message-ai" : u.isCollab && e.user_id && e.user_id !== u.currentUser.id ? "chat-message-other" : "chat-message-user", R = (e) => e.role === "ai" ? { background: "linear-gradient(135deg, #409EFF, #337ECC)" } : { background: e.user_color || "#67C23A" }, z = (e) => (e.user_name || "U").charAt(0), B = (e) => {
94
+ if (!u.isCollab) return;
95
+ let t = typeof e == "string" ? e : e.target?.value || h.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 = te.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
+ }, V = () => {
105
+ O.value && (A.value = Math.min(A.value + 1, k.value.length - 1));
106
+ }, W = () => {
107
+ O.value && (A.value = Math.max(A.value - 1, 0));
108
+ }, ne = (e) => {
109
+ let t = h.value.slice(0, M), n = h.value.slice(M + j.length + 1);
110
+ h.value = `${t}@${e.name} ${n}`, O.value = !1;
111
+ }, re = (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(), ne(t);
118
+ return;
119
+ }
120
+ }
121
+ e.preventDefault();
122
+ }
123
+ let t = h.value.trim();
124
+ if (!t || u.loading) return;
125
+ let n = null;
126
+ if (u.isCollab) {
127
+ let e = t.match(/@(\S+)/);
128
+ e && (n = e[1]);
129
+ }
130
+ m("send", t, { mentionedUser: n }), h.value = "", O.value = !1;
131
+ }, G = () => {
132
+ d(() => {
133
+ _.value && (_.value.scrollTop = _.value.scrollHeight);
134
+ });
135
+ };
136
+ return C(() => u.messages.length, G), C(() => u.messages, G, { deep: !0 }), (n, l) => {
137
+ let u = b("el-icon"), d = b("el-tag"), v = b("el-popover"), C = b("el-button"), j = b("el-input");
138
+ return t.visible ? (g(), a("div", {
139
+ key: 0,
140
+ class: "ai-chat-panel",
141
+ style: p({ width: t.panelWidth + "px" })
142
+ }, [
143
+ o("div", oe, [o("div", se, [
144
+ c(u, {
145
+ size: 18,
146
+ color: "#409EFF"
147
+ }, {
148
+ default: w(() => [c(S(H))]),
149
+ _: 1
150
+ }),
151
+ o("span", X, x(t.isCollab ? "协作聊天" : "AI 助手"), 1),
152
+ t.isCollab ? (g(), r(v, {
153
+ key: 0,
154
+ width: 200,
155
+ placement: "bottom-start",
156
+ trigger: "click"
157
+ }, {
158
+ reference: w(() => [c(d, {
159
+ size: "small",
160
+ type: "success",
161
+ effect: "plain",
162
+ class: "online-tag"
163
+ }, {
164
+ default: w(() => [s(x(P.value) + "人在线 ", 1)]),
165
+ _: 1
166
+ })]),
167
+ default: w(() => [o("div", ce, [o("div", le, [
168
+ o("div", {
169
+ class: "online-user-avatar",
170
+ style: p({ background: t.currentUser.color || "#409EFF" })
171
+ }, x((t.currentUser.name || "U").charAt(0)), 5),
172
+ o("span", ue, x(t.currentUser.name || "我"), 1),
173
+ c(d, {
174
+ size: "small",
175
+ type: t.isOwner ? "warning" : "success",
176
+ effect: "plain",
177
+ class: "role-tag"
178
+ }, {
179
+ default: w(() => [s(x(t.isOwner ? "发起人" : "协作人"), 1)]),
180
+ _: 1
181
+ }, 8, ["type"]),
182
+ l[4] ||= o("span", { class: "self-tag" }, "(我)", -1)
183
+ ]), (g(!0), a(e, null, y(te.value, (e) => (g(), a("div", {
184
+ key: e.id || e.clientId,
185
+ class: "online-user-item"
186
+ }, [
187
+ o("div", {
188
+ class: "online-user-avatar",
189
+ style: p({ background: e.color || "#909399" })
190
+ }, [e.isAi ? (g(), r(u, {
191
+ key: 0,
192
+ size: 14
193
+ }, {
194
+ default: w(() => [c(S(H))]),
195
+ _: 1
196
+ })) : (g(), a("span", de, x((e.name || "U").charAt(0)), 1))], 4),
197
+ o("span", fe, x(e.name || "未知用户"), 1),
198
+ e.isAi ? (g(), r(d, {
199
+ key: 0,
200
+ size: "small",
201
+ type: "primary",
202
+ effect: "plain",
203
+ class: "role-tag"
204
+ }, {
205
+ default: w(() => [...l[5] ||= [s("AI助手", -1)]]),
206
+ _: 1
207
+ })) : (g(), r(d, {
208
+ key: 1,
209
+ size: "small",
210
+ type: "success",
211
+ effect: "plain",
212
+ class: "role-tag"
213
+ }, {
214
+ default: w(() => [...l[6] ||= [s("协作人", -1)]]),
215
+ _: 1
216
+ }))
217
+ ]))), 128))])]),
218
+ _: 1
219
+ })) : i("", !0)
220
+ ]), o("div", pe, [
221
+ t.isCollab && t.unreadMention ? (g(), a("div", {
222
+ key: 0,
223
+ class: "mention-bell",
224
+ title: "有新消息",
225
+ onClick: l[0] ||= (e) => m("clear-unread")
226
+ }, [c(u, {
227
+ size: 18,
228
+ color: "#F56C6C"
229
+ }, {
230
+ default: w(() => [c(S(N))]),
231
+ _: 1
232
+ })])) : i("", !0),
233
+ c(C, {
234
+ text: "",
235
+ circle: "",
236
+ size: "small",
237
+ onClick: l[1] ||= (e) => n.$emit("clear"),
238
+ title: "清空对话"
239
+ }, {
240
+ default: w(() => [c(u, null, {
241
+ default: w(() => [c(S(L))]),
242
+ _: 1
243
+ })]),
244
+ _: 1
245
+ }),
246
+ c(C, {
247
+ text: "",
248
+ circle: "",
249
+ size: "small",
250
+ onClick: l[2] ||= (e) => n.$emit("close"),
251
+ title: "关闭"
252
+ }, {
253
+ default: w(() => [c(u, null, {
254
+ default: w(() => [c(S(F))]),
255
+ _: 1
256
+ })]),
257
+ _: 1
258
+ })
259
+ ])]),
260
+ o("div", {
261
+ class: "chat-messages",
262
+ ref_key: "messagesRef",
263
+ ref: _
264
+ }, [
265
+ t.messages.length === 0 ? (g(), a("div", Z, [
266
+ c(u, {
267
+ size: 40,
268
+ color: "#c0c4cc"
269
+ }, {
270
+ default: w(() => [c(S(H))]),
271
+ _: 1
272
+ }),
273
+ o("p", null, x(t.isCollab ? "协作聊天室" : "你好!我是 AI 助手"), 1),
274
+ o("p", me, x(t.isCollab ? "与团队成员和AI助手实时聊天" : "可以问我任何关于文档编辑的问题"), 1)
275
+ ])) : i("", !0),
276
+ (g(!0), a(e, null, y(t.messages, (e) => (g(), a("div", {
277
+ key: e._msgId || e.time + e.content,
278
+ class: f(["chat-message", I(e)])
279
+ }, [o("div", {
280
+ class: "message-avatar",
281
+ style: p(R(e))
282
+ }, [e.role === "ai" ? (g(), r(u, {
283
+ key: 0,
284
+ size: 16
285
+ }, {
286
+ default: w(() => [c(S(H))]),
287
+ _: 1
288
+ })) : (g(), a("span", he, x(z(e)), 1))], 4), o("div", ge, [
289
+ t.isCollab && e.role === "user" ? (g(), a("div", Q, [o("span", {
290
+ class: "message-sender",
291
+ style: p({ color: e.user_color || "#67C23A" })
292
+ }, x(e.user_name || "用户"), 5), e.mentioned_user ? (g(), a("span", _e, "@" + x(e.mentioned_user), 1)) : i("", !0)])) : i("", !0),
293
+ o("div", {
294
+ class: "message-text",
295
+ innerHTML: e.content
296
+ }, null, 8, ve),
297
+ o("div", ye, x(e.time), 1)
298
+ ])], 2))), 128)),
299
+ t.loading ? (g(), a("div", $, [o("div", be, [c(u, { size: 16 }, {
300
+ default: w(() => [c(S(H))]),
301
+ _: 1
302
+ })]), l[7] ||= o("div", { class: "message-content" }, [o("div", { class: "message-text typing-indicator" }, [
303
+ o("span"),
304
+ o("span"),
305
+ o("span")
306
+ ])], -1)])) : i("", !0)
307
+ ], 512),
308
+ o("div", xe, [o("div", {
309
+ class: "chat-input-wrapper",
310
+ ref_key: "inputWrapperRef",
311
+ ref: D
312
+ }, [
313
+ c(j, {
314
+ modelValue: h.value,
315
+ "onUpdate:modelValue": l[3] ||= (e) => h.value = e,
316
+ type: "textarea",
317
+ autosize: {
318
+ minRows: 1,
319
+ maxRows: 4
320
+ },
321
+ placeholder: t.isCollab ? "输入消息... @提及成员" : "输入消息...",
322
+ onKeydown: [
323
+ T(E(re, ["exact"]), ["enter"]),
324
+ T(E(V, ["prevent"]), ["down"]),
325
+ T(E(W, ["prevent"]), ["up"])
326
+ ],
327
+ onInput: B,
328
+ resize: "none"
329
+ }, null, 8, [
330
+ "modelValue",
331
+ "placeholder",
332
+ "onKeydown"
333
+ ]),
334
+ O.value ? (g(), a("div", Se, [(g(!0), a(e, null, y(k.value, (e, t) => (g(), a("div", {
335
+ key: e.id || e.clientId,
336
+ class: f(["mention-item", { active: t === A.value }]),
337
+ onClick: (t) => ne(e),
338
+ onMouseenter: (e) => A.value = t
339
+ }, [o("div", {
340
+ class: "mention-avatar",
341
+ style: p({ background: e.color || "#909399" })
342
+ }, [e.isAi ? (g(), r(u, {
343
+ key: 0,
344
+ size: 12
345
+ }, {
346
+ default: w(() => [c(S(H))]),
347
+ _: 1
348
+ })) : (g(), a("span", we, x((e.name || "U").charAt(0)), 1))], 4), o("span", null, x(e.name), 1)], 42, Ce))), 128))])) : i("", !0),
349
+ c(C, {
350
+ class: "send-btn",
351
+ type: "primary",
352
+ circle: "",
353
+ disabled: !h.value.trim() || t.loading,
354
+ onClick: re
355
+ }, {
356
+ default: w(() => [c(u, null, {
357
+ default: w(() => [c(S(U))]),
358
+ _: 1
359
+ })]),
360
+ _: 1
361
+ }, 8, ["disabled"])
362
+ ], 512)])
363
+ ], 4)) : i("", !0);
364
+ };
365
+ }
366
+ }, [["__scopeId", "data-v-01960100"]]);
367
+ //#endregion
368
+ //#region ../../src/composables/useChat.js
369
+ function Ee() {
370
+ let e = v([]), t = v(!1), n = v(!1), r = v([]), i = v({
371
+ id: "",
372
+ name: "",
373
+ color: ""
374
+ }), a = v(!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
+ }, m = (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
+ }, _ = 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 q.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 q.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 q.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 q.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 h(() => 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: m,
507
+ sendMessage: _,
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 De = "/api/document-versions", Oe = 5e3, ke = () => {
518
+ let e = v([]), t = v(!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 q.post(De, {
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: Oe });
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 q.get(De, {
542
+ params: { document_id: n },
543
+ timeout: Oe
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 q.get(`${De}/${e}`, { timeout: Oe });
555
+ return t;
556
+ } catch (e) {
557
+ return console.warn("[useVersionHistory] Failed to get version content:", e), null;
558
+ }
559
+ }
560
+ };
561
+ }, Ae = { class: "version-history-panel" }, je = {
562
+ key: 0,
563
+ class: "loading-state"
564
+ }, Me = {
565
+ key: 1,
566
+ class: "empty-state"
567
+ }, Ne = {
568
+ key: 2,
569
+ class: "version-list"
570
+ }, Pe = {
571
+ key: 0,
572
+ class: "current-version"
573
+ }, Fe = { class: "current-version-header" }, Ie = { class: "version-number" }, Le = ["onClick"], Re = { class: "version-number" }, ze = { class: "version-user" }, Be = { class: "panel-footer" }, Ve = /*#__PURE__*/ Y({
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: n, emit: l }) {
587
+ let u = t, d = l, { versions: p, loading: m, loadVersions: h, getVersionContent: _ } = ke(), T = v(!1), E = v(null), D = v(!1), O = v(null);
588
+ C(() => u.modelValue, (e) => {
589
+ T.value = e, e && u.documentId && (E.value = null, h(u.documentId).then((e) => {
590
+ e && e.length > 0 && (O.value = e[0]);
591
+ }));
592
+ }), C(T, (e) => {
593
+ d("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 _(E.value.id);
602
+ e && e.content ? (O.value = E.value, E.value = null, d("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
+ }, ee = (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 n({ currentVersion: O }), (t, n) => {
615
+ let l = b("el-icon"), u = b("el-tag"), d = b("el-timeline-item"), h = b("el-timeline"), _ = b("el-button"), v = b("el-drawer");
616
+ return g(), r(v, {
617
+ modelValue: T.value,
618
+ "onUpdate:modelValue": n[0] ||= (e) => T.value = e,
619
+ title: "更新履历",
620
+ direction: "rtl",
621
+ size: "420px",
622
+ "before-close": M
623
+ }, {
624
+ footer: w(() => [o("div", Be, [c(_, {
625
+ type: "primary",
626
+ disabled: !E.value,
627
+ loading: D.value,
628
+ onClick: j
629
+ }, {
630
+ default: w(() => [...n[4] ||= [s(" 切换到此版本 ", -1)]]),
631
+ _: 1
632
+ }, 8, ["disabled", "loading"])])]),
633
+ default: w(() => [o("div", Ae, [S(m) ? (g(), a("div", je, [c(l, { class: "is-loading" }, {
634
+ default: w(() => [c(S(V))]),
635
+ _: 1
636
+ }), n[1] ||= o("span", null, "加载中...", -1)])) : S(p).length === 0 ? (g(), a("div", Me, [c(l, {
637
+ size: 48,
638
+ color: "#c0c4cc"
639
+ }, {
640
+ default: w(() => [c(S(P))]),
641
+ _: 1
642
+ }), n[2] ||= o("p", null, "暂无历史版本", -1)])) : (g(), a("div", Ne, [O.value ? (g(), a("div", Pe, [o("div", Fe, [c(u, {
643
+ type: "success",
644
+ size: "small"
645
+ }, {
646
+ default: w(() => [...n[3] ||= [s("当前版本", -1)]]),
647
+ _: 1
648
+ }), o("span", Ie, "v" + x(O.value.version_number), 1)])])) : i("", !0), c(h, null, {
649
+ default: w(() => [(g(!0), a(e, null, y(S(p), (e) => (g(), r(d, {
650
+ key: e.id,
651
+ timestamp: ee(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(() => [o("div", {
657
+ class: f(["version-item", { active: E.value?.id === e.id }]),
658
+ onClick: (t) => k(e)
659
+ }, [o("span", Re, "版本号:v" + x(e.version_number), 1), o("span", ze, "提交人:" + x(e.user_name || "未知用户"), 1)], 10, Le)]),
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"]]), He = { class: "toolbar" }, Ue = { class: "toolbar-left" }, We = { class: "toolbar-center" }, Ge = { class: "toolbar-right" }, Ke = {
673
+ key: 0,
674
+ class: "collab-users"
675
+ }, qe = ["title"], Je = /*#__PURE__*/ Y({
676
+ __name: "Toolbar",
677
+ props: {
678
+ title: {
679
+ type: String,
680
+ default: ""
681
+ },
682
+ canUndo: Boolean,
683
+ canRedo: Boolean,
684
+ connectingMode: Boolean,
685
+ isConnected: Boolean,
686
+ onlineUsers: {
687
+ type: Array,
688
+ default: () => []
689
+ },
690
+ isJoinMode: Boolean,
691
+ showHistory: {
692
+ type: Boolean,
693
+ default: !1
694
+ }
695
+ },
696
+ emits: [
697
+ "update:title",
698
+ "back",
699
+ "add-component",
700
+ "group-selected",
701
+ "toggle-connecting",
702
+ "auto-layout",
703
+ "undo",
704
+ "redo",
705
+ "zoom-in",
706
+ "zoom-out",
707
+ "export",
708
+ "save",
709
+ "toggle-collab",
710
+ "share-collab",
711
+ "export-json",
712
+ "import-json",
713
+ "history"
714
+ ],
715
+ setup(t) {
716
+ let n = t, l = v(n.title);
717
+ return C(() => n.title, (e) => l.value = e), (n, u) => {
718
+ let d = b("el-icon"), f = b("el-button"), m = b("el-input"), h = b("el-dropdown-item"), _ = b("el-dropdown-menu"), v = b("el-dropdown"), C = b("el-tooltip"), T = b("el-divider");
719
+ return g(), a("div", He, [
720
+ o("div", Ue, [c(f, {
721
+ onClick: u[0] ||= (e) => n.$emit("back"),
722
+ size: "small",
723
+ circle: ""
724
+ }, {
725
+ default: w(() => [c(d, null, {
726
+ default: w(() => [c(S(ee))]),
727
+ _: 1
728
+ })]),
729
+ _: 1
730
+ }), c(m, {
731
+ modelValue: l.value,
732
+ "onUpdate:modelValue": u[1] ||= (e) => l.value = e,
733
+ onBlur: u[2] ||= (e) => n.$emit("update:title", l.value),
734
+ placeholder: "输入标题",
735
+ class: "title-input",
736
+ size: "small"
737
+ }, null, 8, ["modelValue"])]),
738
+ o("div", We, [
739
+ c(v, {
740
+ trigger: "click",
741
+ onCommand: u[3] ||= (e) => n.$emit("add-component", e)
742
+ }, {
743
+ dropdown: w(() => [c(_, null, {
744
+ default: w(() => [
745
+ c(h, { command: "rect" }, {
746
+ default: w(() => [...u[19] ||= [s("矩形", -1)]]),
747
+ _: 1
748
+ }),
749
+ c(h, { command: "circle" }, {
750
+ default: w(() => [...u[20] ||= [s("圆形", -1)]]),
751
+ _: 1
752
+ }),
753
+ c(h, { command: "diamond" }, {
754
+ default: w(() => [...u[21] ||= [s("菱形", -1)]]),
755
+ _: 1
756
+ }),
757
+ c(h, { command: "triangle" }, {
758
+ default: w(() => [...u[22] ||= [s("三角形", -1)]]),
759
+ _: 1
760
+ }),
761
+ c(h, { command: "text" }, {
762
+ default: w(() => [...u[23] ||= [s("文本", -1)]]),
763
+ _: 1
764
+ }),
765
+ c(h, {
766
+ divided: "",
767
+ command: "image"
768
+ }, {
769
+ default: w(() => [...u[24] ||= [s("图片零件", -1)]]),
770
+ _: 1
771
+ }),
772
+ c(h, { command: "polygon" }, {
773
+ default: w(() => [...u[25] ||= [s("自定义多边形", -1)]]),
774
+ _: 1
775
+ }),
776
+ c(h, { command: "svg" }, {
777
+ default: w(() => [...u[26] ||= [s("SVG导入", -1)]]),
778
+ _: 1
779
+ })
780
+ ]),
781
+ _: 1
782
+ })]),
783
+ default: w(() => [c(f, { size: "small" }, {
784
+ default: w(() => [u[18] ||= s("形状", -1), c(d, { class: "el-icon--right" }, {
785
+ default: w(() => [c(S(M))]),
786
+ _: 1
787
+ })]),
788
+ _: 1
789
+ })]),
790
+ _: 1
791
+ }),
792
+ c(C, {
793
+ content: "导出JSON",
794
+ placement: "bottom"
795
+ }, {
796
+ default: w(() => [c(f, {
797
+ size: "small",
798
+ circle: "",
799
+ onClick: u[4] ||= (e) => n.$emit("export-json")
800
+ }, {
801
+ default: w(() => [c(d, null, {
802
+ default: w(() => [c(S(R))]),
803
+ _: 1
804
+ })]),
805
+ _: 1
806
+ })]),
807
+ _: 1
808
+ }),
809
+ c(C, {
810
+ content: "导入JSON",
811
+ placement: "bottom"
812
+ }, {
813
+ default: w(() => [c(f, {
814
+ size: "small",
815
+ circle: "",
816
+ onClick: u[5] ||= (e) => n.$emit("import-json")
817
+ }, {
818
+ default: w(() => [c(d, null, {
819
+ default: w(() => [c(S(G))]),
820
+ _: 1
821
+ })]),
822
+ _: 1
823
+ })]),
824
+ _: 1
825
+ }),
826
+ c(C, {
827
+ content: "组合",
828
+ placement: "bottom"
829
+ }, {
830
+ default: w(() => [c(f, {
831
+ size: "small",
832
+ circle: "",
833
+ onClick: u[6] ||= (e) => n.$emit("group-selected"),
834
+ title: "将选中零件组合为一个"
835
+ }, {
836
+ default: w(() => [c(d, null, {
837
+ default: w(() => [c(S(z))]),
838
+ _: 1
839
+ })]),
840
+ _: 1
841
+ })]),
842
+ _: 1
843
+ }),
844
+ c(T, { direction: "vertical" }),
845
+ c(C, {
846
+ content: "连线模式",
847
+ placement: "bottom"
848
+ }, {
849
+ default: w(() => [c(f, {
850
+ size: "small",
851
+ circle: "",
852
+ type: t.connectingMode ? "primary" : "",
853
+ onClick: u[7] ||= (e) => n.$emit("toggle-connecting")
854
+ }, {
855
+ default: w(() => [c(d, null, {
856
+ default: w(() => [c(S(I))]),
857
+ _: 1
858
+ })]),
859
+ _: 1
860
+ }, 8, ["type"])]),
861
+ _: 1
862
+ }),
863
+ c(f, {
864
+ size: "small",
865
+ onClick: u[8] ||= (e) => n.$emit("auto-layout")
866
+ }, {
867
+ default: w(() => [...u[27] ||= [s("自动布局", -1)]]),
868
+ _: 1
869
+ }),
870
+ c(T, { direction: "vertical" }),
871
+ c(f, {
872
+ size: "small",
873
+ circle: "",
874
+ onClick: u[9] ||= (e) => n.$emit("undo"),
875
+ disabled: !t.canUndo
876
+ }, {
877
+ default: w(() => [c(d, null, {
878
+ default: w(() => [c(S(W))]),
879
+ _: 1
880
+ })]),
881
+ _: 1
882
+ }, 8, ["disabled"]),
883
+ c(f, {
884
+ size: "small",
885
+ circle: "",
886
+ onClick: u[10] ||= (e) => n.$emit("redo"),
887
+ disabled: !t.canRedo
888
+ }, {
889
+ default: w(() => [c(d, null, {
890
+ default: w(() => [c(S(ne))]),
891
+ _: 1
892
+ })]),
893
+ _: 1
894
+ }, 8, ["disabled"]),
895
+ c(T, { direction: "vertical" }),
896
+ c(f, {
897
+ size: "small",
898
+ circle: "",
899
+ onClick: u[11] ||= (e) => n.$emit("zoom-in")
900
+ }, {
901
+ default: w(() => [c(d, null, {
902
+ default: w(() => [c(S(ie))]),
903
+ _: 1
904
+ })]),
905
+ _: 1
906
+ }),
907
+ c(f, {
908
+ size: "small",
909
+ circle: "",
910
+ onClick: u[12] ||= (e) => n.$emit("zoom-out")
911
+ }, {
912
+ default: w(() => [c(d, null, {
913
+ default: w(() => [c(S(K))]),
914
+ _: 1
915
+ })]),
916
+ _: 1
917
+ })
918
+ ]),
919
+ o("div", Ge, [
920
+ t.onlineUsers.length > 0 ? (g(), a("div", Ke, [(g(!0), a(e, null, y(t.onlineUsers.slice(0, 5), (e) => (g(), a("div", {
921
+ key: e.clientId,
922
+ class: "collab-avatar",
923
+ style: p({ background: e.color }),
924
+ title: e.name
925
+ }, x(e.name?.charAt(0)), 13, qe))), 128))])) : i("", !0),
926
+ t.isJoinMode ? i("", !0) : (g(), r(f, {
927
+ key: 1,
928
+ size: "small",
929
+ type: t.isConnected ? "success" : "default",
930
+ onClick: u[13] ||= (e) => n.$emit("toggle-collab")
931
+ }, {
932
+ default: w(() => [c(d, null, {
933
+ default: w(() => [c(S(re))]),
934
+ _: 1
935
+ }), o("span", null, x(t.isConnected ? "协作中" : "协作"), 1)]),
936
+ _: 1
937
+ }, 8, ["type"])),
938
+ !t.isJoinMode && t.isConnected ? (g(), r(f, {
939
+ key: 2,
940
+ size: "small",
941
+ circle: "",
942
+ onClick: u[14] ||= (e) => n.$emit("share-collab"),
943
+ title: "分享链接"
944
+ }, {
945
+ default: w(() => [c(d, null, {
946
+ default: w(() => [c(S(B))]),
947
+ _: 1
948
+ })]),
949
+ _: 1
950
+ })) : i("", !0),
951
+ c(T, { direction: "vertical" }),
952
+ c(v, {
953
+ trigger: "click",
954
+ onCommand: u[15] ||= (e) => n.$emit("export", e)
955
+ }, {
956
+ dropdown: w(() => [c(_, null, {
957
+ default: w(() => [
958
+ c(h, { command: "png" }, {
959
+ default: w(() => [...u[29] ||= [s("PNG", -1)]]),
960
+ _: 1
961
+ }),
962
+ c(h, { command: "svg" }, {
963
+ default: w(() => [...u[30] ||= [s("SVG", -1)]]),
964
+ _: 1
965
+ }),
966
+ c(h, { command: "pdf" }, {
967
+ default: w(() => [...u[31] ||= [s("PDF", -1)]]),
968
+ _: 1
969
+ }),
970
+ c(h, { command: "html" }, {
971
+ default: w(() => [...u[32] ||= [s("HTML", -1)]]),
972
+ _: 1
973
+ })
974
+ ]),
975
+ _: 1
976
+ })]),
977
+ default: w(() => [c(f, { size: "small" }, {
978
+ default: w(() => [u[28] ||= s("导出", -1), c(d, { class: "el-icon--right" }, {
979
+ default: w(() => [c(S(M))]),
980
+ _: 1
981
+ })]),
982
+ _: 1
983
+ })]),
984
+ _: 1
985
+ }),
986
+ c(f, {
987
+ size: "small",
988
+ onClick: u[16] ||= (e) => n.$emit("save")
989
+ }, {
990
+ default: w(() => [c(d, null, {
991
+ default: w(() => [c(S(R))]),
992
+ _: 1
993
+ })]),
994
+ _: 1
995
+ }),
996
+ t.showHistory ? (g(), r(f, {
997
+ key: 3,
998
+ size: "small",
999
+ circle: "",
1000
+ title: "更新履历",
1001
+ onClick: u[17] ||= (e) => n.$emit("history")
1002
+ }, {
1003
+ default: w(() => [c(d, null, {
1004
+ default: w(() => [c(S(P))]),
1005
+ _: 1
1006
+ })]),
1007
+ _: 1
1008
+ })) : i("", !0)
1009
+ ])
1010
+ ]);
1011
+ };
1012
+ }
1013
+ }, [["__scopeId", "data-v-919c0dae"]]), Ye = ["viewBox"], Xe = ["id"], Ze = [
1014
+ "x",
1015
+ "y",
1016
+ "width",
1017
+ "height"
1018
+ ], Qe = [
1019
+ "transform",
1020
+ "onMousedown",
1021
+ "onDblclick",
1022
+ "onMouseenter"
1023
+ ], $e = [
1024
+ "href",
1025
+ "width",
1026
+ "height"
1027
+ ], et = ["innerHTML", "transform"], tt = [
1028
+ "points",
1029
+ "fill",
1030
+ "stroke",
1031
+ "stroke-width"
1032
+ ], nt = [
1033
+ "width",
1034
+ "height",
1035
+ "fill",
1036
+ "stroke",
1037
+ "stroke-width"
1038
+ ], rt = [
1039
+ "width",
1040
+ "height",
1041
+ "fill",
1042
+ "stroke",
1043
+ "stroke-width"
1044
+ ], it = [
1045
+ "cx",
1046
+ "cy",
1047
+ "rx",
1048
+ "ry",
1049
+ "fill",
1050
+ "stroke",
1051
+ "stroke-width"
1052
+ ], at = [
1053
+ "points",
1054
+ "fill",
1055
+ "stroke",
1056
+ "stroke-width"
1057
+ ], ot = [
1058
+ "points",
1059
+ "fill",
1060
+ "stroke",
1061
+ "stroke-width"
1062
+ ], st = [
1063
+ "width",
1064
+ "height",
1065
+ "stroke",
1066
+ "stroke-width"
1067
+ ], ct = [
1068
+ "x",
1069
+ "y",
1070
+ "fill",
1071
+ "font-size"
1072
+ ], lt = ["x", "y"], ut = [
1073
+ "x",
1074
+ "y",
1075
+ "fill",
1076
+ "font-size"
1077
+ ], dt = [
1078
+ "x",
1079
+ "y",
1080
+ "fill",
1081
+ "font-size"
1082
+ ], ft = ["x", "y"], pt = { key: 12 }, mt = [
1083
+ "x",
1084
+ "y",
1085
+ "onMousedown"
1086
+ ], ht = ["y", "onMousedown"], gt = ["x", "onMousedown"], _t = ["onMousedown"], vt = { key: 13 }, yt = [
1087
+ "cx",
1088
+ "cy",
1089
+ "onMousedown"
1090
+ ], bt = ["x", "y"], xt = [
1091
+ "d",
1092
+ "stroke",
1093
+ "stroke-width",
1094
+ "stroke-dasharray",
1095
+ "onMousedown"
1096
+ ], St = ["x", "y"], Ct = [
1097
+ "x1",
1098
+ "y1",
1099
+ "x2",
1100
+ "y2"
1101
+ ], wt = { key: 1 }, Tt = [
1102
+ "cx",
1103
+ "cy",
1104
+ "onMousedown"
1105
+ ], Et = [
1106
+ "href",
1107
+ "x",
1108
+ "y",
1109
+ "width",
1110
+ "height",
1111
+ "clip-path"
1112
+ ], Dt = { class: "popup-tooltip-key" }, Ot = { class: "popup-tooltip-val" }, kt = /*#__PURE__*/ Y({
1113
+ __name: "DiagramCanvas",
1114
+ props: {
1115
+ components: {
1116
+ type: Array,
1117
+ default: () => []
1118
+ },
1119
+ connections: {
1120
+ type: Array,
1121
+ default: () => []
1122
+ },
1123
+ selectedId: [
1124
+ String,
1125
+ Number,
1126
+ null
1127
+ ],
1128
+ selectedIds: {
1129
+ type: Array,
1130
+ default: () => []
1131
+ },
1132
+ connectingMode: Boolean,
1133
+ drawingConn: Object,
1134
+ editingPolygon: Object,
1135
+ viewBox: {
1136
+ type: String,
1137
+ default: "0 0 2000 1500"
1138
+ },
1139
+ isExpanded: Boolean,
1140
+ expandedGroupId: [
1141
+ String,
1142
+ Number,
1143
+ null
1144
+ ]
1145
+ },
1146
+ emits: [
1147
+ "select",
1148
+ "edit",
1149
+ "clear-selection",
1150
+ "start-connect",
1151
+ "start-resize",
1152
+ "move-component",
1153
+ "drag-polygon-vertex"
1154
+ ],
1155
+ setup(t, { emit: r }) {
1156
+ let s = t, c = r, l = v(null), u = v(null), d = v(null), f = v({
1157
+ x: 0,
1158
+ y: 0
1159
+ }), m = n(() => {
1160
+ let e = s.components.filter((e) => e.shape === "group"), t = s.components.filter((e) => e.shape !== "group");
1161
+ return [...e, ...t];
1162
+ }), h = n(() => s.viewBox), _ = n(() => s.components.filter((e) => e.shape === "group" && e.imageUrl)), b = (e) => !s.isExpanded && e.groupId, S = (e) => {
1163
+ if (s.isExpanded) return !1;
1164
+ let t = s.components.find((t) => t.id === e.fromId), n = s.components.find((t) => t.id === e.toId);
1165
+ return t && t.groupId || n && n.groupId;
1166
+ }, C = n(() => s.editingPolygon ? (s.editingPolygon.points || "").trim().split(/\s+/).map((e) => {
1167
+ let [t, n] = e.split(",").map(Number);
1168
+ return {
1169
+ x: t,
1170
+ y: n
1171
+ };
1172
+ }) : []), w = (e) => [
1173
+ {
1174
+ x: e.width / 2,
1175
+ y: 0,
1176
+ dir: "top"
1177
+ },
1178
+ {
1179
+ x: e.width,
1180
+ y: e.height / 2,
1181
+ dir: "right"
1182
+ },
1183
+ {
1184
+ x: e.width / 2,
1185
+ y: e.height,
1186
+ dir: "bottom"
1187
+ },
1188
+ {
1189
+ x: 0,
1190
+ y: e.height / 2,
1191
+ dir: "left"
1192
+ }
1193
+ ], T = (e) => {
1194
+ let t = s.components.find((t) => t.id === e.fromId), n = s.components.find((t) => t.id === e.toId);
1195
+ if (!t || !n) return "";
1196
+ let r = t.x + (e.fromAnchor?.x ?? t.width / 2), i = t.y + (e.fromAnchor?.y ?? t.height / 2), a = n.x + (e.toAnchor?.x ?? n.width / 2), o = n.y + (e.toAnchor?.y ?? n.height / 2), c = a - r;
1197
+ return `M${r},${i} C${r + c * .3},${i} ${a - c * .3},${o} ${a},${o}`;
1198
+ }, D = (e) => {
1199
+ let t = s.components.find((t) => t.id === e.fromId), n = s.components.find((t) => t.id === e.toId);
1200
+ return !t || !n ? {
1201
+ x: 0,
1202
+ y: 0
1203
+ } : {
1204
+ x: (t.x + n.x) / 2,
1205
+ y: (t.y + n.y) / 2
1206
+ };
1207
+ }, O = (e, t) => {
1208
+ if (!e.popupConfig || !e.popupConfig.length) return;
1209
+ d.value = e;
1210
+ let n = l.value.getBoundingClientRect();
1211
+ f.value = {
1212
+ x: t.clientX - n.left,
1213
+ y: t.clientY - n.top
1214
+ };
1215
+ }, k = (e) => {
1216
+ let t = u.value;
1217
+ if (!t) return {
1218
+ x: 0,
1219
+ y: 0
1220
+ };
1221
+ let n = t.getBoundingClientRect(), r = t.viewBox.baseVal;
1222
+ return {
1223
+ x: (e.clientX - n.left) / n.width * r.width + r.x,
1224
+ y: (e.clientY - n.top) / n.height * r.height + r.y
1225
+ };
1226
+ }, A = (e, t) => {
1227
+ if (t.ctrlKey || t.metaKey) {
1228
+ c("select", e, "component", t);
1229
+ return;
1230
+ }
1231
+ if (c("select", e, "component", t), s.connectingMode) return;
1232
+ let n = k(t), r = e.x, i = e.y, a = !1, o = (t) => {
1233
+ let o = k(t), s = o.x - n.x, l = o.y - n.y;
1234
+ (Math.abs(s) > 2 || Math.abs(l) > 2) && (a = !0), c("move-component", e.id, r + s, i + l);
1235
+ }, l = () => {
1236
+ document.removeEventListener("mousemove", o), document.removeEventListener("mouseup", l), a && c("move-component", e.id, e.x, e.y, !0);
1237
+ };
1238
+ document.addEventListener("mousemove", o), document.addEventListener("mouseup", l);
1239
+ }, j = (e, t, n) => {
1240
+ e.width, e.height;
1241
+ let r = (e.points || "").trim().split(/\s+/).map((e) => e.split(",").map(Number)), i = (n) => {
1242
+ let i = k(n);
1243
+ r[t] = [Math.max(0, Math.min(e.width, Math.round(i.x - e.x))), Math.max(0, Math.min(e.height, Math.round(i.y - e.y)))], e.points = r.map((e) => e.join(",")).join(" ");
1244
+ }, a = () => {
1245
+ document.removeEventListener("mousemove", i), document.removeEventListener("mouseup", a), c("drag-polygon-vertex", e);
1246
+ };
1247
+ document.addEventListener("mousemove", i), document.addEventListener("mouseup", a);
1248
+ };
1249
+ return (n, r) => (g(), a("div", {
1250
+ class: "diagram-canvas",
1251
+ ref_key: "containerRef",
1252
+ ref: l
1253
+ }, [(g(), a("svg", {
1254
+ ref_key: "svgRef",
1255
+ ref: u,
1256
+ class: "diagram-svg",
1257
+ viewBox: h.value,
1258
+ onMousedown: r[1] ||= E((e) => n.$emit("clear-selection"), ["self"])
1259
+ }, [
1260
+ o("defs", null, [r[2] ||= o("marker", {
1261
+ id: "arrowhead-end",
1262
+ markerWidth: "10",
1263
+ markerHeight: "7",
1264
+ refX: "9",
1265
+ refY: "3.5",
1266
+ orient: "auto"
1267
+ }, [o("polygon", {
1268
+ points: "0 0, 10 3.5, 0 7",
1269
+ fill: "#666"
1270
+ })], -1), (g(!0), a(e, null, y(_.value, (e) => (g(), a("clipPath", {
1271
+ key: "clip-" + e.id,
1272
+ id: "clip-" + e.id
1273
+ }, [o("rect", {
1274
+ x: e.x,
1275
+ y: e.y,
1276
+ width: e.width,
1277
+ height: e.height,
1278
+ rx: "4"
1279
+ }, null, 8, Ze)], 8, Xe))), 128))]),
1280
+ (g(!0), a(e, null, y(m.value, (s) => (g(), a("g", {
1281
+ key: s.id,
1282
+ transform: `translate(${s.x}, ${s.y})`,
1283
+ onMousedown: E((e) => b(s) ? null : A(s, e), ["stop"]),
1284
+ onDblclick: E((e) => b(s) ? null : n.$emit("edit", s), ["stop"]),
1285
+ onMouseenter: (e) => O(s, e),
1286
+ onMouseleave: r[0] ||= (e) => d.value = null,
1287
+ style: p(b(s) ? "pointer-events:none;opacity:0.7;" : "cursor:move;")
1288
+ }, [
1289
+ s.shape === "image" ? (g(), a("image", {
1290
+ key: 0,
1291
+ href: s.imageUrl,
1292
+ width: s.width,
1293
+ height: s.height,
1294
+ preserveAspectRatio: "xMidYMid meet",
1295
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1296
+ }, null, 12, $e)) : s.shape === "svg" ? (g(), a("g", {
1297
+ key: 1,
1298
+ innerHTML: s.svgContent || "",
1299
+ transform: `scale(${s.width / (s.svgWidth || 100)}, ${s.height / (s.svgHeight || 100)})`,
1300
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1301
+ }, null, 12, et)) : s.shape === "polygon" ? (g(), a("polygon", {
1302
+ key: 2,
1303
+ points: s.points || "",
1304
+ fill: s.fill || "#fff",
1305
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : s.stroke || "#ccc",
1306
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1307
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1308
+ }, null, 12, tt)) : s.shape === "group" && s.id !== t.expandedGroupId ? (g(), a("rect", {
1309
+ key: 3,
1310
+ width: s.width,
1311
+ height: s.height,
1312
+ fill: s.imageUrl ? "none" : "rgba(64,158,255,0.05)",
1313
+ stroke: (t.selectedIds.includes(s.id), "#409EFF"),
1314
+ "stroke-dasharray": "6,3",
1315
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1316
+ style: { "pointer-events": "all" }
1317
+ }, null, 8, nt)) : s.shape === "rect" ? (g(), a("rect", {
1318
+ key: 4,
1319
+ width: s.width,
1320
+ height: s.height,
1321
+ rx: 4,
1322
+ fill: s.fill || "#fff",
1323
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : s.stroke || "#ccc",
1324
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1325
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1326
+ }, null, 12, rt)) : s.shape === "circle" ? (g(), a("ellipse", {
1327
+ key: 5,
1328
+ cx: s.width / 2,
1329
+ cy: s.height / 2,
1330
+ rx: s.width / 2,
1331
+ ry: s.height / 2,
1332
+ fill: s.fill || "#fff",
1333
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : s.stroke || "#ccc",
1334
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1335
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1336
+ }, null, 12, it)) : s.shape === "diamond" ? (g(), a("polygon", {
1337
+ key: 6,
1338
+ points: `${s.width / 2},0 ${s.width},${s.height / 2} ${s.width / 2},${s.height} 0,${s.height / 2}`,
1339
+ fill: s.fill || "#fff",
1340
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : s.stroke || "#ccc",
1341
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1342
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1343
+ }, null, 12, at)) : s.shape === "triangle" ? (g(), a("polygon", {
1344
+ key: 7,
1345
+ points: `${s.width / 2},0 ${s.width},${s.height} 0,${s.height}`,
1346
+ fill: s.fill || "#fff",
1347
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : s.stroke || "#ccc",
1348
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1349
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1350
+ }, null, 12, ot)) : (g(), a("rect", {
1351
+ key: 8,
1352
+ width: s.width,
1353
+ height: s.height,
1354
+ fill: "#fff",
1355
+ stroke: t.selectedIds.includes(s.id) ? "#409EFF" : "#ccc",
1356
+ "stroke-width": t.selectedIds.includes(s.id) ? 2 : 1,
1357
+ style: p({ pointerEvents: b(s) ? "none" : "all" })
1358
+ }, null, 12, st)),
1359
+ s.shape === "image" ? (g(), a(e, { key: 9 }, [o("text", {
1360
+ x: s.width / 2,
1361
+ y: s.height + 10,
1362
+ "text-anchor": "middle",
1363
+ "dominant-baseline": "hanging",
1364
+ fill: s.textColor || "#333",
1365
+ "font-size": s.fontSize || 14,
1366
+ style: { "pointer-events": "none" }
1367
+ }, x(s.label), 9, ct), s.description ? (g(), a("text", {
1368
+ key: 0,
1369
+ x: s.width / 2,
1370
+ y: s.height + 10 + (s.fontSize || 14) + 2,
1371
+ "text-anchor": "middle",
1372
+ "dominant-baseline": "hanging",
1373
+ fill: "#999",
1374
+ "font-size": "11",
1375
+ style: { "pointer-events": "none" }
1376
+ }, x(s.description), 9, lt)) : i("", !0)], 64)) : s.shape === "group" && s.id !== t.expandedGroupId ? (g(), a("text", {
1377
+ key: 10,
1378
+ x: s.width / 2,
1379
+ y: s.height + 10,
1380
+ "text-anchor": "middle",
1381
+ "dominant-baseline": "hanging",
1382
+ fill: s.textColor || "#333",
1383
+ "font-size": s.fontSize || 14,
1384
+ style: { "pointer-events": "none" }
1385
+ }, x(s.label), 9, ut)) : s.shape === "group" ? i("", !0) : (g(), a(e, { key: 11 }, [o("text", {
1386
+ x: s.width / 2,
1387
+ y: s.height / 2 - (s.description ? 6 : 0),
1388
+ "text-anchor": "middle",
1389
+ "dominant-baseline": "central",
1390
+ fill: s.textColor || "#333",
1391
+ "font-size": s.fontSize || 14,
1392
+ style: { "pointer-events": "none" }
1393
+ }, x(s.label), 9, dt), s.description ? (g(), a("text", {
1394
+ key: 0,
1395
+ x: s.width / 2,
1396
+ y: s.height / 2 + 12,
1397
+ "text-anchor": "middle",
1398
+ "dominant-baseline": "central",
1399
+ fill: "#999",
1400
+ "font-size": "11",
1401
+ style: { "pointer-events": "none" }
1402
+ }, x(s.description), 9, ft)) : i("", !0)], 64)),
1403
+ t.selectedIds.includes(s.id) && !b(s) ? (g(), a("g", pt, [
1404
+ o("rect", {
1405
+ x: s.width - 5,
1406
+ y: s.height - 5,
1407
+ width: "10",
1408
+ height: "10",
1409
+ fill: "#409EFF",
1410
+ stroke: "#fff",
1411
+ "stroke-width": "1",
1412
+ style: { cursor: "nwse-resize" },
1413
+ onMousedown: E((e) => n.$emit("start-resize", s, "se", e), ["stop"])
1414
+ }, null, 40, mt),
1415
+ o("rect", {
1416
+ x: -5,
1417
+ y: s.height - 5,
1418
+ width: "10",
1419
+ height: "10",
1420
+ fill: "#409EFF",
1421
+ stroke: "#fff",
1422
+ "stroke-width": "1",
1423
+ style: { cursor: "nesw-resize" },
1424
+ onMousedown: E((e) => n.$emit("start-resize", s, "sw", e), ["stop"])
1425
+ }, null, 40, ht),
1426
+ o("rect", {
1427
+ x: s.width - 5,
1428
+ y: -5,
1429
+ width: "10",
1430
+ height: "10",
1431
+ fill: "#409EFF",
1432
+ stroke: "#fff",
1433
+ "stroke-width": "1",
1434
+ style: { cursor: "nesw-resize" },
1435
+ onMousedown: E((e) => n.$emit("start-resize", s, "ne", e), ["stop"])
1436
+ }, null, 40, gt),
1437
+ o("rect", {
1438
+ x: -5,
1439
+ y: -5,
1440
+ width: "10",
1441
+ height: "10",
1442
+ fill: "#409EFF",
1443
+ stroke: "#fff",
1444
+ "stroke-width": "1",
1445
+ style: { cursor: "nwse-resize" },
1446
+ onMousedown: E((e) => n.$emit("start-resize", s, "nw", e), ["stop"])
1447
+ }, null, 40, _t)
1448
+ ])) : i("", !0),
1449
+ (t.selectedIds.includes(s.id) || t.connectingMode) && !b(s) && !(t.editingPolygon && t.editingPolygon.id === s.id) ? (g(), a("g", vt, [(g(!0), a(e, null, y(w(s), (e, t) => (g(), a("circle", {
1450
+ key: t,
1451
+ cx: e.x,
1452
+ cy: e.y,
1453
+ r: "4",
1454
+ fill: "#409EFF",
1455
+ stroke: "#fff",
1456
+ "stroke-width": "1",
1457
+ style: { cursor: "crosshair" },
1458
+ onMousedown: E((t) => n.$emit("start-connect", s, e, t), ["stop"])
1459
+ }, null, 40, yt))), 128))])) : i("", !0),
1460
+ t.editingPolygon && t.editingPolygon.id === s.id ? (g(), a("text", {
1461
+ key: 14,
1462
+ x: s.width / 2,
1463
+ y: s.height + 16,
1464
+ "text-anchor": "middle",
1465
+ fill: "#409EFF",
1466
+ "font-size": "11",
1467
+ style: { "pointer-events": "none" }
1468
+ }, "双击退出编辑", 8, bt)) : i("", !0)
1469
+ ], 44, Qe))), 128)),
1470
+ (g(!0), a(e, null, y(t.connections, (e) => (g(), a("g", {
1471
+ key: e.id,
1472
+ style: p(S(e) ? "pointer-events:none;opacity:0.5;" : "")
1473
+ }, [o("path", {
1474
+ d: T(e),
1475
+ fill: "none",
1476
+ stroke: t.selectedId === e.id ? "#409EFF" : "#666",
1477
+ "stroke-width": e.lineWidth || 2,
1478
+ "stroke-dasharray": e.dashed ? "6,3" : "none",
1479
+ "marker-end": "url(#arrowhead-end)",
1480
+ "pointer-events": "stroke",
1481
+ style: { cursor: "pointer" },
1482
+ onMousedown: E((t) => n.$emit("select", e, "connection", t), ["stop"])
1483
+ }, null, 40, xt), e.label ? (g(), a("text", {
1484
+ key: 0,
1485
+ x: D(e).x,
1486
+ y: D(e).y - 6,
1487
+ "text-anchor": "middle",
1488
+ fill: "#666",
1489
+ "font-size": "12"
1490
+ }, x(e.label), 9, St)) : i("", !0)], 4))), 128)),
1491
+ t.drawingConn ? (g(), a("line", {
1492
+ key: 0,
1493
+ x1: t.drawingConn.x1,
1494
+ y1: t.drawingConn.y1,
1495
+ x2: t.drawingConn.x2,
1496
+ y2: t.drawingConn.y2,
1497
+ stroke: "#409EFF",
1498
+ "stroke-width": "2",
1499
+ "stroke-dasharray": "4,4"
1500
+ }, null, 8, Ct)) : i("", !0),
1501
+ t.editingPolygon ? (g(), a("g", wt, [(g(!0), a(e, null, y(C.value, (e, n) => (g(), a("circle", {
1502
+ key: "pv-" + n,
1503
+ cx: t.editingPolygon.x + e.x,
1504
+ cy: t.editingPolygon.y + e.y,
1505
+ r: "5",
1506
+ fill: "#409EFF",
1507
+ stroke: "#fff",
1508
+ "stroke-width": "1.5",
1509
+ style: { cursor: "move" },
1510
+ onMousedown: E((e) => j(t.editingPolygon, n, e), ["stop"])
1511
+ }, null, 40, Tt))), 128))])) : i("", !0),
1512
+ (g(!0), a(e, null, y(m.value, (e) => (g(), a("g", { key: "img-" + e.id }, [e.shape === "group" && e.imageUrl && e.id !== t.expandedGroupId ? (g(), a("image", {
1513
+ key: 0,
1514
+ href: e.imageUrl,
1515
+ x: e.x,
1516
+ y: e.y,
1517
+ width: e.width,
1518
+ height: e.height,
1519
+ preserveAspectRatio: "xMidYMid slice",
1520
+ "clip-path": `url(#clip-${e.id})`,
1521
+ style: { "pointer-events": "none" }
1522
+ }, null, 8, Et)) : i("", !0)]))), 128))
1523
+ ], 40, Ye)), d.value && d.value.popupConfig && d.value.popupConfig.length ? (g(), a("div", {
1524
+ key: 0,
1525
+ class: "popup-tooltip",
1526
+ style: p({
1527
+ left: f.value.x + 12 + "px",
1528
+ top: f.value.y + 12 + "px"
1529
+ })
1530
+ }, [(g(!0), a(e, null, y(d.value.popupConfig, (e, t) => (g(), a("div", {
1531
+ key: t,
1532
+ class: "popup-tooltip-row"
1533
+ }, [o("span", Dt, x(e.key) + ":", 1), o("span", Ot, x(e.value), 1)]))), 128))], 4)) : i("", !0)], 512));
1534
+ }
1535
+ }, [["__scopeId", "data-v-f89f4797"]]);
1536
+ //#endregion
1537
+ //#region ../../src/composables/useExplosionCollaboration.js
1538
+ function At(e, { roomPrefix: t, syncKey: n = "_data" } = {}) {
1539
+ let r = new J.Doc(), i = v(!1), a = v(!1), o = v(!1), s = v(!1), c = v([]), l = null, u = null, d = null, f = null, p = !1, m = null, g = `ws://${window.location.hostname || "localhost"}:1234`, _ = `${t}-${e}`, y = () => {
1540
+ b(), m = setInterval(() => {
1541
+ if (l && l.connection && l.connection.ws && l.connection.ws.readyState === WebSocket.CLOSED) try {
1542
+ l.connect();
1543
+ } catch (e) {
1544
+ console.warn("[ExplosionCollab] reconnect failed:", e);
1545
+ }
1546
+ }, 3e4);
1547
+ }, b = () => {
1548
+ m &&= (clearInterval(m), null);
1549
+ };
1550
+ l = new ae({
1551
+ url: g,
1552
+ name: _,
1553
+ document: r,
1554
+ connect: !1,
1555
+ reconnect: !0,
1556
+ onConnect: () => {
1557
+ i.value = !0, y();
1558
+ },
1559
+ onClose: () => {
1560
+ i.value = !1, a.value = !1;
1561
+ },
1562
+ onSynced: ({ state: e }) => {
1563
+ a.value = e;
1564
+ }
1565
+ }), l.awareness.on("change", () => {
1566
+ c.value = Array.from(l.awareness.getStates().entries()).filter(([e, t]) => t.user).map(([e, t]) => ({
1567
+ clientId: e,
1568
+ ...t.user
1569
+ }));
1570
+ }), u = r.getMap(t);
1571
+ let x = r.getMap("_meta");
1572
+ x.observe((e) => {
1573
+ e.keysChanged.has("_closed") && (s.value = x.get("_closed") === !0, s.value && console.log("[ExplosionCollab] collaboration closed by owner"));
1574
+ });
1575
+ let S = () => {
1576
+ l.connect();
1577
+ }, C = () => {
1578
+ if (b(), l) {
1579
+ try {
1580
+ l.disconnect(), l.destroy();
1581
+ } catch (e) {
1582
+ console.warn("[ExplosionCollab] disconnect error:", e);
1583
+ }
1584
+ l = null;
1585
+ }
1586
+ i.value = !1, a.value = !1, c.value = [];
1587
+ }, w = (e = {}) => (p = !1, l.connect(), new Promise((t) => {
1588
+ let n = () => {
1589
+ l && a.value ? (p = !0, e.userInfo && l.awareness.setLocalStateField("user", e.userInfo), t()) : setTimeout(n, 100);
1590
+ };
1591
+ setTimeout(n, 200);
1592
+ })), T = (e) => {
1593
+ !i.value || !u || (d && clearTimeout(d), d = setTimeout(() => {
1594
+ let t = JSON.stringify(e);
1595
+ f = t, r.transact(() => {
1596
+ u.set(n, t);
1597
+ });
1598
+ }, 50));
1599
+ }, E = () => {
1600
+ if (!u) return null;
1601
+ let e = u.get(n);
1602
+ if (!e) return null;
1603
+ f = e;
1604
+ try {
1605
+ return JSON.parse(e);
1606
+ } catch {
1607
+ return null;
1608
+ }
1609
+ }, D = (e) => {
1610
+ l && l.awareness.setLocalStateField("user", {
1611
+ id: e.id || `user-${Date.now()}`,
1612
+ name: e.name || `用户${Math.floor(Math.random() * 1e3)}`,
1613
+ color: e.color || `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`,
1614
+ ...e
1615
+ });
1616
+ }, O = () => {
1617
+ s.value = !0, r.transact(() => {
1618
+ x.set("_closed", !0);
1619
+ }), p = !1, l?.awareness?.setLocalState(null), C(), o.value = !1;
1620
+ }, k = () => x.get("_closed") === !0 ? (s.value = !0, !0) : !1, A = () => {
1621
+ C(), r.destroy();
1622
+ };
1623
+ return h(() => A()), {
1624
+ ydoc: r,
1625
+ provider: l,
1626
+ yMap: u,
1627
+ isConnected: i,
1628
+ isSynced: a,
1629
+ isCollabOwner: o,
1630
+ collaborationClosed: s,
1631
+ onlineUsers: c,
1632
+ connect: S,
1633
+ disconnect: C,
1634
+ init: w,
1635
+ pushToYjs: T,
1636
+ pullFromYjs: E,
1637
+ setLocalUser: D,
1638
+ closeCollaboration: O,
1639
+ checkCollaborationClosed: k,
1640
+ destroy: A,
1641
+ _getSyncReady: () => p,
1642
+ _setSyncReady: (e) => {
1643
+ p = e;
1644
+ },
1645
+ _getLastSyncedValue: () => f,
1646
+ _setLastSyncedValue: (e) => {
1647
+ f = e;
1648
+ }
1649
+ };
1650
+ }
1651
+ //#endregion
1652
+ //#region ../../src/composables/useExplosionDiagramCollaboration.js
1653
+ var jt = (e, { onRemoteChange: t } = {}) => {
1654
+ let n = At(e, {
1655
+ roomPrefix: "explosion-diagram",
1656
+ syncKey: "_data"
1657
+ });
1658
+ t && n.yMap.observe((e) => {
1659
+ if (!n._getSyncReady()) return;
1660
+ let r = n.yMap.get("_data");
1661
+ if (r && r !== n._getLastSyncedValue()) {
1662
+ n._setLastSyncedValue(r);
1663
+ try {
1664
+ t(JSON.parse(r));
1665
+ } catch (e) {
1666
+ console.error("[EV-Diagram] remote data parse error:", e);
1667
+ }
1668
+ }
1669
+ });
1670
+ let r = (e) => {
1671
+ n.pushToYjs({
1672
+ title: e.title,
1673
+ components: e.components,
1674
+ connections: e.connections
1675
+ });
1676
+ }, i = () => n.pullFromYjs();
1677
+ return {
1678
+ ...n,
1679
+ pushToYjs: r,
1680
+ pullFromYjs: i
1681
+ };
1682
+ }, Mt = { class: "explosion-diagram-editor" }, Nt = {
1683
+ key: 0,
1684
+ class: "group-breadcrumb"
1685
+ }, Pt = { class: "editor-body" }, Ft = {
1686
+ key: 0,
1687
+ class: "props-panel"
1688
+ }, It = { class: "prop-row" }, Lt = { class: "prop-row" }, Rt = { class: "prop-row" }, zt = { class: "prop-row" }, Bt = { class: "prop-row" }, Vt = {
1689
+ key: 0,
1690
+ class: "group-image-preview"
1691
+ }, Ht = ["src"], Ut = { class: "prop-row" }, Wt = { class: "prop-row" }, Gt = { class: "prop-row" }, Kt = { class: "prop-row" }, qt = { class: "prop-row" }, Jt = { class: "prop-row" }, Yt = { class: "prop-row" }, Xt = { class: "prop-row" }, Zt = { class: "prop-row" }, Qt = { style: {
1692
+ "margin-bottom": "8px",
1693
+ display: "flex",
1694
+ gap: "8px"
1695
+ } }, $t = "explosion-diagram", en = /*#__PURE__*/ Y({
1696
+ __name: "ExplosionDiagramEditor",
1697
+ setup(l) {
1698
+ let u = O(), d = k(), f = v(null), p = v(!1), C = v(!1), { saveVersion: T } = ke(), E = Ee(), D = _({
1699
+ title: "爆炸图",
1700
+ components: [],
1701
+ connections: []
1702
+ }), M = v(!1), ee = v(!1), N = v(!1), P = null, F = v([]), I = v(-1), L = v(null), R = v([]), z = v(null), B = v(null), V = v(!1), H = v(null), U = v(null), W = v([]), ne = v(null), re = v(null), G = v(!1), ie = v(null), K = v([]), J = n(() => W.value.length ? W.value[W.value.length - 1] : null), ae = n(() => {
1703
+ if (!J.value) return D.components;
1704
+ let e = (t) => {
1705
+ let n = /* @__PURE__ */ new Set([t]);
1706
+ return D.components.filter((e) => e.groupId === t).forEach((t) => {
1707
+ n.add(t.id), t.shape === "group" && e(t.id).forEach((e) => n.add(e));
1708
+ }), n;
1709
+ }, t = e(J.value);
1710
+ return D.components.filter((e) => t.has(e.id));
1711
+ }), Y = n(() => {
1712
+ if (!J.value) return D.connections;
1713
+ let e = new Set(ae.value.map((e) => e.id));
1714
+ return D.connections.filter((t) => e.has(t.fromId) || e.has(t.toId));
1715
+ }), oe = n(() => {
1716
+ if (!J.value) return "0 0 2000 1500";
1717
+ let e = D.components.find((e) => e.id === J.value);
1718
+ if (!e) return "0 0 2000 1500";
1719
+ let t = ae.value.filter((e) => e.id !== J.value);
1720
+ if (!t.length) return `${e.x} ${e.y} ${e.width} ${e.height}`;
1721
+ let n = Infinity, r = Infinity, i = -Infinity, a = -Infinity;
1722
+ return t.forEach((e) => {
1723
+ n = Math.min(n, e.x), r = Math.min(r, e.y), i = Math.max(i, e.x + e.width), a = Math.max(a, e.y + e.height);
1724
+ }), `${n - 40} ${r - 40} ${i - n + 80} ${a - r + 80}`;
1725
+ }), se = (e) => D.components.find((t) => t.id === e), X = () => {
1726
+ F.value = F.value.slice(0, I.value + 1), F.value.push(JSON.stringify({
1727
+ components: D.components,
1728
+ connections: D.connections
1729
+ })), I.value = F.value.length - 1, ce();
1730
+ }, ce = () => {
1731
+ M.value && P && P.pushToYjs(D);
1732
+ }, le = () => {
1733
+ if (I.value > 0) {
1734
+ I.value--;
1735
+ let e = JSON.parse(F.value[I.value]);
1736
+ D.components = e.components, D.connections = e.connections, ce();
1737
+ }
1738
+ }, ue = () => {
1739
+ if (I.value < F.value.length - 1) {
1740
+ I.value++;
1741
+ let e = JSON.parse(F.value[I.value]);
1742
+ D.components = e.components, D.connections = e.connections, ce();
1743
+ }
1744
+ }, de = () => {}, fe = () => {}, pe = 0, Z = () => `comp-${++pe}-${Date.now()}`, me = {
1745
+ rect: [140, 60],
1746
+ circle: [80, 80],
1747
+ diamond: [100, 80],
1748
+ triangle: [100, 80],
1749
+ text: [120, 40],
1750
+ image: [150, 150],
1751
+ polygon: [150, 120],
1752
+ svg: [120, 120],
1753
+ group: [200, 150]
1754
+ }, he = v(null), ge = v(null), Q = null, _e = (e) => {
1755
+ if (e === "image") {
1756
+ Q = "image", he.value?.click();
1757
+ return;
1758
+ }
1759
+ if (e === "svg") {
1760
+ Q = "svg", ge.value?.click();
1761
+ return;
1762
+ }
1763
+ if (e === "polygon") {
1764
+ let e = {
1765
+ id: Z(),
1766
+ shape: "polygon",
1767
+ label: `${D.components.length + 1}`,
1768
+ description: "",
1769
+ x: 300 + Math.random() * 200,
1770
+ y: 200 + Math.random() * 200,
1771
+ width: 150,
1772
+ height: 120,
1773
+ points: "0,60 40,0 110,0 150,60 110,120 40,120",
1774
+ fill: "#fff",
1775
+ stroke: "#ccc",
1776
+ textColor: "#333",
1777
+ fontSize: 14
1778
+ };
1779
+ J.value && (e.groupId = J.value), D.components.push(e), X();
1780
+ return;
1781
+ }
1782
+ if (e === "group") {
1783
+ let e = {
1784
+ id: Z(),
1785
+ shape: "group",
1786
+ label: `${D.components.length + 1}`,
1787
+ description: "",
1788
+ x: 300 + Math.random() * 200,
1789
+ y: 200 + Math.random() * 200,
1790
+ width: 200,
1791
+ height: 150,
1792
+ childIds: [],
1793
+ fill: "transparent",
1794
+ stroke: "#409EFF",
1795
+ textColor: "#333",
1796
+ fontSize: 14
1797
+ };
1798
+ J.value && (e.groupId = J.value), D.components.push(e), X();
1799
+ return;
1800
+ }
1801
+ let [t, n] = me[e] || [120, 60], r = {
1802
+ id: Z(),
1803
+ shape: e,
1804
+ label: `${D.components.length + 1}`,
1805
+ description: "",
1806
+ x: 300 + Math.random() * 200,
1807
+ y: 200 + Math.random() * 200,
1808
+ width: t,
1809
+ height: n,
1810
+ fill: "#fff",
1811
+ stroke: "#ccc",
1812
+ textColor: "#333",
1813
+ fontSize: 14
1814
+ };
1815
+ J.value && (r.groupId = J.value), D.components.push(r), X();
1816
+ }, ve = async (e) => {
1817
+ let t = e.target.files?.[0];
1818
+ if (!t) return;
1819
+ let n = new FormData();
1820
+ n.append("file", t), Q === "image" && n.append("remove_bg", "true");
1821
+ try {
1822
+ let e = await q.post("/api/files/upload/image", n), r = e.data.url || e.data.file_path;
1823
+ if (Q === "image") {
1824
+ let e = {
1825
+ id: Z(),
1826
+ shape: "image",
1827
+ label: `${D.components.length + 1}`,
1828
+ description: "",
1829
+ x: 300 + Math.random() * 200,
1830
+ y: 200 + Math.random() * 200,
1831
+ width: 150,
1832
+ height: 150,
1833
+ imageUrl: r,
1834
+ fill: "transparent",
1835
+ stroke: "#ccc",
1836
+ textColor: "#333",
1837
+ fontSize: 14
1838
+ };
1839
+ J.value && (e.groupId = J.value), D.components.push(e);
1840
+ } else if (Q === "svg") {
1841
+ let e = await t.text(), n = new DOMParser().parseFromString(e, "image/svg+xml").querySelector("svg"), r = n?.getAttribute("width") || 100, i = n?.getAttribute("height") || 100, a = n?.getAttribute("viewBox"), o = parseFloat(r), s = parseFloat(i);
1842
+ if (a) {
1843
+ let e = a.split(/[\s,]+/).map(Number);
1844
+ o = e[2] || o, s = e[3] || s;
1845
+ }
1846
+ let c = n?.innerHTML || "", l = {
1847
+ id: Z(),
1848
+ shape: "svg",
1849
+ label: `${D.components.length + 1}`,
1850
+ description: "",
1851
+ x: 300 + Math.random() * 200,
1852
+ y: 200 + Math.random() * 200,
1853
+ width: o,
1854
+ height: s,
1855
+ svgContent: c,
1856
+ svgWidth: o,
1857
+ svgHeight: s,
1858
+ fill: "#fff",
1859
+ stroke: "#ccc",
1860
+ textColor: "#333",
1861
+ fontSize: 14
1862
+ };
1863
+ J.value && (l.groupId = J.value), D.components.push(l);
1864
+ }
1865
+ X();
1866
+ } catch {
1867
+ A.error("上传失败");
1868
+ }
1869
+ e.target.value = "";
1870
+ }, ye = (e, t, n) => {
1871
+ if (n && (n.ctrlKey || n.metaKey)) {
1872
+ R.value.includes(e.id) ? R.value = R.value.filter((t) => t !== e.id) : R.value.push(e.id), L.value = R.value[R.value.length - 1] || null, B.value = L.value ? D.components.find((e) => e.id === L.value) : null, z.value = "component";
1873
+ return;
1874
+ }
1875
+ L.value = e.id, R.value = [e.id], z.value = t, B.value = e, U.value = null;
1876
+ }, $ = () => {
1877
+ L.value = null, R.value = [], z.value = null, B.value = null, U.value = null;
1878
+ }, be = (e, t, n) => {
1879
+ let r = xe(n), i = e.x, a = e.y, o = e.width, s = e.height, c = e.shape === "polygon" ? (e.points || "").trim().split(/\s+/).map((e) => e.split(",").map(Number)) : null, l = e.shape === "group", u = l ? D.components.filter((t) => t.groupId === e.id && t.id !== e.id) : [], d = u.map((e) => ({
1880
+ id: e.id,
1881
+ x: e.x,
1882
+ y: e.y,
1883
+ w: e.width,
1884
+ h: e.height
1885
+ })), f = new Set(l ? u.map((e) => e.id) : [e.id]), p = D.connections.filter((e) => f.has(e.fromId) || f.has(e.toId)).map((e) => ({
1886
+ conn: e,
1887
+ fromAnchor: e.fromAnchor ? {
1888
+ x: e.fromAnchor.x,
1889
+ y: e.fromAnchor.y
1890
+ } : null,
1891
+ toAnchor: e.toAnchor ? {
1892
+ x: e.toAnchor.x,
1893
+ y: e.toAnchor.y
1894
+ } : null
1895
+ })), m = (n) => {
1896
+ let m = xe(n), h = m.x - r.x, g = m.y - r.y, _ = o, v = s, y = i, b = a;
1897
+ if (t === "se" ? (_ = o + h, v = s + g) : t === "sw" ? (y = i + h, _ = o - h, v = s + g) : t === "ne" ? (_ = o + h, b = a + g, v = s - g) : t === "nw" && (y = i + h, b = a + g, _ = o - h, v = s - g), _ = Math.max(30, _), v = Math.max(20, v), e.x = y, e.y = b, e.width = _, e.height = v, c && o > 0 && s > 0 && (e.points = c.map(([e, t]) => `${Math.round(e * _ / o)},${Math.round(t * v / s)}`).join(" ")), o > 0 && s > 0) {
1898
+ let e = _ / o, t = v / s;
1899
+ l && u.forEach((n, r) => {
1900
+ let o = d[r];
1901
+ if (n.x = y + (o.x - i) * e, n.y = b + (o.y - a) * t, n.width = o.w * e, n.height = o.h * t, n.shape === "polygon" && n.points) {
1902
+ let r = o._origPoints || (n.points || "").trim().split(/\s+/).map((e) => e.split(",").map(Number));
1903
+ o._origPoints ||= r, n.points = r.map(([n, r]) => `${Math.round(n * e)},${Math.round(r * t)}`).join(" ");
1904
+ }
1905
+ }), p.forEach(({ conn: n, fromAnchor: r, toAnchor: i }) => {
1906
+ r && f.has(n.fromId) && (n.fromAnchor = {
1907
+ x: r.x * e,
1908
+ y: r.y * t
1909
+ }), i && f.has(n.toId) && (n.toAnchor = {
1910
+ x: i.x * e,
1911
+ y: i.y * t
1912
+ });
1913
+ });
1914
+ }
1915
+ }, h = () => {
1916
+ document.removeEventListener("mousemove", m), document.removeEventListener("mouseup", h), X();
1917
+ };
1918
+ document.addEventListener("mousemove", m), document.addEventListener("mouseup", h);
1919
+ }, xe = (e) => {
1920
+ let t = document.querySelector(".diagram-svg");
1921
+ if (!t) return {
1922
+ x: 0,
1923
+ y: 0
1924
+ };
1925
+ let n = t.getBoundingClientRect(), r = t.viewBox.baseVal;
1926
+ return {
1927
+ x: (e.clientX - n.left) / n.width * r.width + r.x,
1928
+ y: (e.clientY - n.top) / n.height * r.height + r.y
1929
+ };
1930
+ }, Se = (e, t, n, r = !1) => {
1931
+ let i = D.components.find((t) => t.id === e);
1932
+ if (!i) return;
1933
+ let a = t - i.x, o = n - i.y;
1934
+ i.x = t, i.y = n, i.shape === "group" && i.id && D.components.forEach((e) => {
1935
+ e.groupId === i.id && e.id !== i.id && (e.x += a, e.y += o);
1936
+ }), r && X();
1937
+ }, Ce = (e) => {
1938
+ if (e.shape === "group") {
1939
+ je(e);
1940
+ return;
1941
+ }
1942
+ if (e.shape === "polygon") {
1943
+ U.value && U.value.id === e.id ? U.value = null : U.value = e;
1944
+ return;
1945
+ }
1946
+ j.prompt("编辑标签", "组件", {
1947
+ inputValue: e.label,
1948
+ inputPlaceholder: "标签文字"
1949
+ }).then(({ value: t }) => {
1950
+ t !== null && (e.label = t);
1951
+ }).catch(() => {});
1952
+ }, we = () => {
1953
+ L.value && (z.value === "component" ? (D.components = D.components.filter((e) => e.id !== L.value), D.connections = D.connections.filter((e) => e.fromId !== L.value && e.toId !== L.value)) : D.connections = D.connections.filter((e) => e.id !== L.value), $(), X());
1954
+ }, De = (e, t, n) => {
1955
+ V.value = !0;
1956
+ let r = e.x + t.x, i = e.y + t.y;
1957
+ H.value = {
1958
+ x1: r,
1959
+ y1: i,
1960
+ x2: r,
1961
+ y2: i
1962
+ };
1963
+ let a = n.target.closest("svg"), o = (e) => {
1964
+ if (!a) return;
1965
+ let t = a.getBoundingClientRect(), n = a.viewBox.baseVal;
1966
+ H.value.x2 = (e.clientX - t.left) / t.width * n.width + n.x, H.value.y2 = (e.clientY - t.top) / t.height * n.height + n.y;
1967
+ }, s = (n) => {
1968
+ if (document.removeEventListener("mousemove", o), document.removeEventListener("mouseup", s), H.value = null, !a) {
1969
+ V.value = !1;
1970
+ return;
1971
+ }
1972
+ let r = a.getBoundingClientRect(), i = a.viewBox.baseVal, c = (n.clientX - r.left) / r.width * i.width + i.x, l = (n.clientY - r.top) / r.height * i.height + i.y, u = null, d = 30;
1973
+ for (let t of D.components) {
1974
+ if (t.id === e.id) continue;
1975
+ let n = [
1976
+ {
1977
+ x: t.x + t.width / 2,
1978
+ y: t.y
1979
+ },
1980
+ {
1981
+ x: t.x + t.width,
1982
+ y: t.y + t.height / 2
1983
+ },
1984
+ {
1985
+ x: t.x + t.width / 2,
1986
+ y: t.y + t.height
1987
+ },
1988
+ {
1989
+ x: t.x,
1990
+ y: t.y + t.height / 2
1991
+ }
1992
+ ];
1993
+ for (let e of n) {
1994
+ let n = Math.sqrt((c - e.x) ** 2 + (l - e.y) ** 2);
1995
+ n < d && (d = n, u = t);
1996
+ }
1997
+ }
1998
+ if (!u) {
1999
+ for (let t of D.components) if (t.id !== e.id && c >= t.x && c <= t.x + t.width && l >= t.y && l <= t.y + t.height) {
2000
+ u = t;
2001
+ break;
2002
+ }
2003
+ }
2004
+ u && (D.connections.find((t) => t.fromId === e.id && t.toId === u.id) || (D.connections.push({
2005
+ id: Z(),
2006
+ fromId: e.id,
2007
+ toId: u.id,
2008
+ fromAnchor: {
2009
+ x: t.x,
2010
+ y: t.y
2011
+ },
2012
+ toAnchor: {
2013
+ x: u.width / 2,
2014
+ y: u.height / 2
2015
+ },
2016
+ label: "",
2017
+ lineWidth: 2,
2018
+ dashed: !1
2019
+ }), X())), V.value = !1;
2020
+ };
2021
+ document.addEventListener("mousemove", o), document.addEventListener("mouseup", s);
2022
+ }, Oe = () => {
2023
+ let e = D.components.filter((e) => R.value.includes(e.id));
2024
+ if (e.length < 2) {
2025
+ A.warning("请至少选择2个零件进行组合");
2026
+ return;
2027
+ }
2028
+ let t = Infinity, n = Infinity, r = -Infinity, i = -Infinity;
2029
+ e.forEach((e) => {
2030
+ t = Math.min(t, e.x), n = Math.min(n, e.y), r = Math.max(r, e.x + e.width), i = Math.max(i, e.y + e.height);
2031
+ });
2032
+ let a = Z();
2033
+ e.forEach((e) => {
2034
+ e.groupId = a;
2035
+ });
2036
+ let o = {
2037
+ id: a,
2038
+ shape: "group",
2039
+ label: "组合",
2040
+ description: "",
2041
+ x: t - 10,
2042
+ y: n - 10,
2043
+ width: r - t + 20,
2044
+ height: i - n + 20,
2045
+ fill: "transparent",
2046
+ stroke: "#409EFF",
2047
+ textColor: "#333",
2048
+ fontSize: 14,
2049
+ movable: !1
2050
+ };
2051
+ J.value && (o.groupId = J.value), D.components = [
2052
+ ...D.components.filter((e) => !R.value.includes(e.id)),
2053
+ o,
2054
+ ...e
2055
+ ], R.value = [], X();
2056
+ }, Ae = (e) => {
2057
+ let t = D.components.filter((t) => t.groupId === e.id && t.id !== e.id);
2058
+ if (!t.length) return;
2059
+ let n = Infinity, r = Infinity, i = -Infinity, a = -Infinity;
2060
+ t.forEach((e) => {
2061
+ n = Math.min(n, e.x), r = Math.min(r, e.y), i = Math.max(i, e.x + e.width), a = Math.max(a, e.y + e.height);
2062
+ }), e.x = n - 10, e.y = r - 10, e.width = i - n + 20, e.height = a - r + 20, X();
2063
+ }, je = (e) => {
2064
+ W.value.push(e.id), $();
2065
+ }, Me = () => {
2066
+ W.value.length && (W.value.pop(), $());
2067
+ }, Ne = (e) => {
2068
+ W.value = W.value.slice(0, e + 1), $();
2069
+ }, Pe = async (e) => {
2070
+ let t = e.target.files?.[0];
2071
+ if (!t || !B.value) return;
2072
+ let n = new FormData();
2073
+ n.append("file", t);
2074
+ try {
2075
+ let e = await q.post("/api/files/upload/image", n);
2076
+ B.value.imageUrl = e.data.url || e.data.file_path, Ae(B.value);
2077
+ } catch {
2078
+ A.error("上传失败");
2079
+ }
2080
+ e.target.value = "";
2081
+ }, Fe = () => {
2082
+ let e = D.components;
2083
+ if (!e.length) return;
2084
+ let t = Math.ceil(Math.sqrt(e.length));
2085
+ D.components = e.map((e, n) => ({
2086
+ ...e,
2087
+ x: 100 + n % t * 200,
2088
+ y: 100 + Math.floor(n / t) * 120
2089
+ })), X();
2090
+ }, Ie = () => d.push("/"), Le = [
2091
+ "我可以帮您优化爆炸图布局、检查组件标注,或者提供装配顺序建议。请问有什么需要帮助的?",
2092
+ "这个爆炸图的组件分布很清晰。建议检查连接线是否准确反映了实际装配关系。",
2093
+ "根据当前的爆炸图结构,我建议为关键组件添加编号说明,便于阅读理解。",
2094
+ "我可以帮您检查爆炸图中是否有遗漏的零部件或多余的标注。需要我逐个分析吗?",
2095
+ "建议在爆炸图中添加装配方向指示箭头,这样可以让装配流程更加直观。",
2096
+ "这个爆炸图的层次感不错。如果需要,我可以帮您优化组件间距和标注位置。",
2097
+ "我可以帮您将爆炸图的数据导出为BOM清单格式,方便采购和生产管理。",
2098
+ "文档中的组件信息很详细。建议补充每个组件的规格参数和供应商信息。"
2099
+ ], Re = async (e, t = {}) => {
2100
+ let n = f.value ? `${$t}-${f.value}` : null;
2101
+ await E.sendMessage(e, {
2102
+ ...t,
2103
+ roomId: n
2104
+ });
2105
+ let r = t.mentionedUser, i = r && r.toLowerCase().includes("ai"), a = E.collabUsers.value.filter((e) => e.name !== E.currentUser.value.name);
2106
+ (!r || i || a.length === 0) && (E.loading.value = !0, setTimeout(() => {
2107
+ E.sendAiMessage(Le[Math.floor(Math.random() * Le.length)], n), E.loading.value = !1;
2108
+ }, 800 + Math.random() * 1200));
2109
+ }, ze = () => {
2110
+ let e = f.value ? `${$t}-${f.value}` : null;
2111
+ E.clearMessages(e);
2112
+ }, Be = () => {
2113
+ if (!f.value) {
2114
+ A.warning("请先保存文档");
2115
+ return;
2116
+ }
2117
+ C.value = !0;
2118
+ }, He = (e) => {
2119
+ try {
2120
+ let t = typeof e == "string" ? JSON.parse(e) : e;
2121
+ t.components && (D.components = t.components), t.connections && (D.connections = t.connections), $();
2122
+ } catch (e) {
2123
+ console.error("Version apply error:", e);
2124
+ }
2125
+ }, Ue = async () => {
2126
+ if (M.value && P?.collaborationClosed.value && !N.value) {
2127
+ A.warning("协作已关闭,无法保存");
2128
+ return;
2129
+ }
2130
+ try {
2131
+ let e = {
2132
+ title: D.title,
2133
+ view_type: "diagram",
2134
+ config: JSON.stringify({
2135
+ components: D.components,
2136
+ connections: D.connections
2137
+ })
2138
+ };
2139
+ f.value ? await q.put(`/api/explosion-views/${f.value}`, e) : f.value = (await q.post("/api/explosion-views/", e)).data.id, A.success("保存成功"), T({
2140
+ documentId: f.value,
2141
+ docType: "diagram",
2142
+ content: JSON.stringify({
2143
+ components: D.components,
2144
+ connections: D.connections
2145
+ }),
2146
+ userId: String(E.currentUser.value?.id || ""),
2147
+ userName: E.currentUser.value?.name || "未知"
2148
+ });
2149
+ } catch {
2150
+ A.error("保存失败");
2151
+ }
2152
+ }, We = async () => {
2153
+ if (u.params.id) try {
2154
+ let e = (await q.get(`/api/explosion-views/${u.params.id}`)).data;
2155
+ if (f.value = e.id, D.title = e.title, e.config) {
2156
+ let t = JSON.parse(e.config);
2157
+ D.components = t.components || [], D.connections = t.connections || [];
2158
+ }
2159
+ X();
2160
+ } catch (e) {
2161
+ console.error("load error", e);
2162
+ }
2163
+ else X();
2164
+ }, Ge = async (e) => {
2165
+ try {
2166
+ let t = document.querySelector(".diagram-svg");
2167
+ if (!t) return A.error("未找到SVG元素");
2168
+ let n = new XMLSerializer().serializeToString(t);
2169
+ if (e === "svg") {
2170
+ let e = new Blob([n], { type: "image/svg+xml;charset=utf-8" }), t = URL.createObjectURL(e), r = document.createElement("a");
2171
+ r.href = t, r.download = `${D.title || "爆炸图"}.svg`, r.click(), URL.revokeObjectURL(t);
2172
+ } else if (e === "png") {
2173
+ let e = document.createElement("canvas"), t = e.getContext("2d"), r = new Image(), i = new Blob([n], { type: "image/svg+xml;charset=utf-8" }), a = URL.createObjectURL(i);
2174
+ r.onload = () => {
2175
+ e.width = r.width, e.height = r.height, t.fillStyle = "#fff", t.fillRect(0, 0, e.width, e.height), t.drawImage(r, 0, 0), e.toBlob((e) => {
2176
+ let t = document.createElement("a");
2177
+ t.href = URL.createObjectURL(e), t.download = `${D.title || "爆炸图"}.png`, t.click();
2178
+ }), URL.revokeObjectURL(a);
2179
+ }, r.src = a;
2180
+ } else A.info(`导出 ${e} 开发中`);
2181
+ } catch {
2182
+ A.error("导出失败");
2183
+ }
2184
+ }, Ke = (e) => {
2185
+ P &&= (P.destroy(), null), P = jt(e, { onRemoteChange: (e) => {
2186
+ e.title && (D.title = e.title), e.components && (D.components = e.components), e.connections && (D.connections = e.connections), $();
2187
+ } }), P._setSyncReady(!1);
2188
+ }, qe = async () => {
2189
+ if (M.value) return;
2190
+ if (!f.value && (await Ue(), !f.value)) {
2191
+ A.error("请先保存文档");
2192
+ return;
2193
+ }
2194
+ Ke(String(f.value)), P.connect();
2195
+ let e = {
2196
+ name: `用户${Math.floor(Math.random() * 1e3)}`,
2197
+ color: `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`
2198
+ }, t = () => {
2199
+ if (P.provider && P.provider.synced) {
2200
+ P._setSyncReady(!0), P.setLocalUser(e);
2201
+ let t = P.pullFromYjs();
2202
+ t ? (t.title && (D.title = t.title), t.components && (D.components = t.components), t.connections && (D.connections = t.connections), $()) : D.components.length > 0 && P.pushToYjs(D), M.value = !0, N.value = !0, ee.value = !1, E.setCollabContext({
2203
+ ydoc: P.ydoc,
2204
+ provider: P.provider,
2205
+ onlineUsers: P.onlineUsers
2206
+ }), E.setCurrentUser({
2207
+ id: P.provider.awareness.clientID,
2208
+ name: e.name,
2209
+ color: e.color
2210
+ }), A.success("协作已开启");
2211
+ } else setTimeout(t, 100);
2212
+ };
2213
+ setTimeout(t, 200);
2214
+ }, Ye = () => {
2215
+ P && (P.closeCollaboration(), M.value = !1, N.value = !1, A.info("协作已关闭"));
2216
+ }, Xe = () => {
2217
+ let e = u.params.id;
2218
+ if (!e) return;
2219
+ Ke(e), P.connect();
2220
+ let t = {
2221
+ name: `协作人${Math.floor(Math.random() * 1e3)}`,
2222
+ color: `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")}`
2223
+ }, n = () => {
2224
+ if (P.provider && P.provider.synced) {
2225
+ if (P.checkCollaborationClosed()) {
2226
+ P.disconnect(), M.value = !1, A.warning("该协作已关闭,无法加入");
2227
+ return;
2228
+ }
2229
+ P._setSyncReady(!0), P.setLocalUser(t);
2230
+ let e = P.pullFromYjs();
2231
+ e && (e.title && (D.title = e.title), e.components && (D.components = e.components), e.connections && (D.connections = e.connections), $()), M.value = !0, N.value = !1, E.setCollabContext({
2232
+ ydoc: P.ydoc,
2233
+ provider: P.provider,
2234
+ onlineUsers: P.onlineUsers
2235
+ }), E.setCurrentUser({
2236
+ id: P.provider.awareness.clientID,
2237
+ name: t.name,
2238
+ color: t.color
2239
+ }), A.success("已加入协作");
2240
+ } else setTimeout(n, 100);
2241
+ };
2242
+ setTimeout(n, 200);
2243
+ }, Ze = () => {
2244
+ M.value ? Ye() : qe();
2245
+ }, Qe = async () => {
2246
+ if (M.value || await qe(), !f.value && (await Ue(), !f.value)) {
2247
+ A.warning("请先保存文档后再分享");
2248
+ return;
2249
+ }
2250
+ let e = `${window.location.origin}/explosion-diagram/${f.value}?collab=1`;
2251
+ try {
2252
+ await navigator.clipboard.writeText(e), A.success("协作链接已复制到剪贴板");
2253
+ } catch {
2254
+ A.info("协作链接: " + e);
2255
+ }
2256
+ }, $e = () => {
2257
+ K.value = (B.value?.popupConfig || []).map((e) => ({ ...e })), G.value = !0;
2258
+ }, et = () => {
2259
+ K.value.push({
2260
+ key: "",
2261
+ value: ""
2262
+ });
2263
+ }, tt = () => {
2264
+ B.value.popupConfig = K.value.filter((e) => e.key.trim()), G.value = !1, X();
2265
+ }, nt = (e) => {
2266
+ let t = e.target.files?.[0];
2267
+ if (!t) return;
2268
+ let n = new FileReader();
2269
+ n.onload = () => {
2270
+ try {
2271
+ let e = JSON.parse(n.result);
2272
+ Array.isArray(e) ? K.value = e.map((e) => ({
2273
+ key: String(e.key || ""),
2274
+ value: String(e.value || "")
2275
+ })) : typeof e == "object" && (K.value = Object.entries(e).map(([e, t]) => ({
2276
+ key: e,
2277
+ value: String(t)
2278
+ }))), A.success("导入成功");
2279
+ } catch {
2280
+ A.error("JSON解析失败");
2281
+ }
2282
+ }, n.readAsText(t), e.target.value = "";
2283
+ }, rt = () => {
2284
+ let e = JSON.stringify({
2285
+ title: D.title,
2286
+ components: D.components,
2287
+ connections: D.connections
2288
+ }, null, 2), t = new Blob([e], { type: "application/json" }), n = URL.createObjectURL(t), r = document.createElement("a");
2289
+ r.href = n, r.download = `${D.title || "爆炸图"}.json`, r.click(), URL.revokeObjectURL(n), A.success("导出成功");
2290
+ }, it = (e) => {
2291
+ let t = e.target.files?.[0];
2292
+ if (!t) return;
2293
+ let n = new FileReader();
2294
+ n.onload = () => {
2295
+ try {
2296
+ let e = JSON.parse(n.result);
2297
+ e.title && (D.title = e.title), e.components && (D.components = e.components), e.connections && (D.connections = e.connections), $(), X(), A.success("导入成功");
2298
+ } catch {
2299
+ A.error("JSON解析失败");
2300
+ }
2301
+ }, n.readAsText(t), e.target.value = "";
2302
+ };
2303
+ m(async () => {
2304
+ let e = localStorage.getItem("editor-user-name") || `用户${Math.floor(Math.random() * 1e3)}`;
2305
+ localStorage.setItem("editor-user-name", e), E.setCurrentUser({
2306
+ id: Date.now(),
2307
+ name: e,
2308
+ color: "#409eff"
2309
+ }), await We(), u.params.id && u.query.collab === "1" && Xe();
2310
+ });
2311
+ let at = (e) => {
2312
+ e.key === "Delete" && L.value && we(), (e.ctrlKey || e.metaKey) && e.key === "z" && (e.preventDefault(), le()), (e.ctrlKey || e.metaKey) && e.key === "y" && (e.preventDefault(), ue());
2313
+ };
2314
+ return m(() => document.addEventListener("keydown", at)), h(() => {
2315
+ document.removeEventListener("keydown", at), P &&= (P.destroy(), null);
2316
+ }), (n, l) => {
2317
+ let d = b("el-breadcrumb-item"), m = b("el-breadcrumb"), h = b("el-icon"), _ = b("el-button"), v = b("el-tooltip"), T = b("el-input"), O = b("el-input-number"), k = b("el-color-picker"), A = b("el-switch"), j = b("el-table-column"), ee = b("el-table"), q = b("el-dialog"), ce = b("Monitor");
2318
+ return g(), a("div", Mt, [
2319
+ c(Je, {
2320
+ title: D.title,
2321
+ "onUpdate:title": l[0] ||= (e) => D.title = e,
2322
+ "can-undo": I.value > 0,
2323
+ "can-redo": I.value < F.value.length - 1,
2324
+ "connecting-mode": V.value,
2325
+ "is-connected": M.value,
2326
+ "online-users": S(P) ? S(P).onlineUsers.value : [],
2327
+ "is-join-mode": S(u).query.collab === "1",
2328
+ onBack: Ie,
2329
+ onAddComponent: _e,
2330
+ onToggleConnecting: l[1] ||= (e) => V.value = !V.value,
2331
+ onGroupSelected: Oe,
2332
+ onAutoLayout: Fe,
2333
+ onUndo: le,
2334
+ onRedo: ue,
2335
+ onZoomIn: de,
2336
+ onZoomOut: fe,
2337
+ onExport: Ge,
2338
+ onSave: Ue,
2339
+ onToggleCollab: Ze,
2340
+ onShareCollab: Qe,
2341
+ onExportJson: rt,
2342
+ onImportJson: l[2] ||= (e) => re.value?.click(),
2343
+ "show-history": !!f.value,
2344
+ onHistory: Be
2345
+ }, null, 8, [
2346
+ "title",
2347
+ "can-undo",
2348
+ "can-redo",
2349
+ "connecting-mode",
2350
+ "is-connected",
2351
+ "online-users",
2352
+ "is-join-mode",
2353
+ "show-history"
2354
+ ]),
2355
+ o("input", {
2356
+ ref_key: "fileInputRef",
2357
+ ref: he,
2358
+ type: "file",
2359
+ accept: "image/*,.svg",
2360
+ style: { display: "none" },
2361
+ onChange: ve
2362
+ }, null, 544),
2363
+ o("input", {
2364
+ ref_key: "svgInputRef",
2365
+ ref: ge,
2366
+ type: "file",
2367
+ accept: ".svg",
2368
+ style: { display: "none" },
2369
+ onChange: ve
2370
+ }, null, 544),
2371
+ o("input", {
2372
+ ref_key: "groupImageInputRef",
2373
+ ref: ne,
2374
+ type: "file",
2375
+ accept: "image/*",
2376
+ style: { display: "none" },
2377
+ onChange: Pe
2378
+ }, null, 544),
2379
+ o("input", {
2380
+ ref_key: "importJsonInputRef",
2381
+ ref: re,
2382
+ type: "file",
2383
+ accept: ".json",
2384
+ style: { display: "none" },
2385
+ onChange: it
2386
+ }, null, 544),
2387
+ W.value.length ? (g(), a("div", Nt, [c(m, { separator: "/" }, {
2388
+ default: w(() => [c(d, {
2389
+ onClick: l[3] ||= (e) => Ne(-1),
2390
+ style: { cursor: "pointer" }
2391
+ }, {
2392
+ default: w(() => [...l[27] ||= [s("根目录", -1)]]),
2393
+ _: 1
2394
+ }), (g(!0), a(e, null, y(W.value, (e, t) => (g(), r(d, {
2395
+ key: e,
2396
+ onClick: (e) => Ne(t),
2397
+ style: { cursor: "pointer" }
2398
+ }, {
2399
+ default: w(() => [s(x(se(e)?.label || "组合"), 1)]),
2400
+ _: 2
2401
+ }, 1032, ["onClick"]))), 128))]),
2402
+ _: 1
2403
+ }), c(v, {
2404
+ content: "返回上一层",
2405
+ placement: "bottom"
2406
+ }, {
2407
+ default: w(() => [c(_, {
2408
+ size: "small",
2409
+ circle: "",
2410
+ onClick: Me
2411
+ }, {
2412
+ default: w(() => [c(h, null, {
2413
+ default: w(() => [c(S(te))]),
2414
+ _: 1
2415
+ })]),
2416
+ _: 1
2417
+ })]),
2418
+ _: 1
2419
+ })])) : i("", !0),
2420
+ o("div", Pt, [c(kt, {
2421
+ components: ae.value,
2422
+ connections: Y.value,
2423
+ "selected-id": L.value,
2424
+ "selected-ids": R.value,
2425
+ "connecting-mode": V.value,
2426
+ "drawing-conn": H.value,
2427
+ "editing-polygon": U.value,
2428
+ "view-box": oe.value,
2429
+ "is-expanded": !!J.value,
2430
+ "expanded-group-id": J.value,
2431
+ onSelect: ye,
2432
+ onEdit: Ce,
2433
+ onClearSelection: $,
2434
+ onStartConnect: De,
2435
+ onStartResize: be,
2436
+ onMoveComponent: Se,
2437
+ onDragPolygonVertex: X
2438
+ }, null, 8, [
2439
+ "components",
2440
+ "connections",
2441
+ "selected-id",
2442
+ "selected-ids",
2443
+ "connecting-mode",
2444
+ "drawing-conn",
2445
+ "editing-polygon",
2446
+ "view-box",
2447
+ "is-expanded",
2448
+ "expanded-group-id"
2449
+ ]), c(t, { name: "slide" }, {
2450
+ default: w(() => [B.value ? (g(), a("div", Ft, [o("h4", null, x(z.value === "component" ? "组件属性" : "连线属性"), 1), z.value === "component" ? (g(), a(e, { key: 0 }, [
2451
+ o("div", It, [l[28] ||= o("label", null, "标签", -1), c(T, {
2452
+ modelValue: B.value.label,
2453
+ "onUpdate:modelValue": l[4] ||= (e) => B.value.label = e,
2454
+ size: "small"
2455
+ }, null, 8, ["modelValue"])]),
2456
+ o("div", Lt, [l[29] ||= o("label", null, "描述", -1), c(T, {
2457
+ modelValue: B.value.description,
2458
+ "onUpdate:modelValue": l[5] ||= (e) => B.value.description = e,
2459
+ size: "small"
2460
+ }, null, 8, ["modelValue"])]),
2461
+ B.value.shape === "group" ? (g(), a(e, { key: 0 }, [
2462
+ o("div", Rt, [l[30] ||= o("label", null, "宽度", -1), c(O, {
2463
+ modelValue: B.value.width,
2464
+ "onUpdate:modelValue": l[6] ||= (e) => B.value.width = e,
2465
+ min: 40,
2466
+ max: 2e3,
2467
+ size: "small"
2468
+ }, null, 8, ["modelValue"])]),
2469
+ o("div", zt, [l[31] ||= o("label", null, "高度", -1), c(O, {
2470
+ modelValue: B.value.height,
2471
+ "onUpdate:modelValue": l[7] ||= (e) => B.value.height = e,
2472
+ min: 30,
2473
+ max: 1500,
2474
+ size: "small"
2475
+ }, null, 8, ["modelValue"])]),
2476
+ o("div", Bt, [l[34] ||= o("label", null, "显示图片", -1), B.value.imageUrl ? (g(), a("div", Vt, [o("img", {
2477
+ src: B.value.imageUrl,
2478
+ style: {
2479
+ "max-width": "100%",
2480
+ "max-height": "80px",
2481
+ border: "1px solid #e4e7ed",
2482
+ "border-radius": "4px"
2483
+ }
2484
+ }, null, 8, Ht), c(_, {
2485
+ size: "small",
2486
+ type: "danger",
2487
+ text: "",
2488
+ onClick: l[8] ||= (e) => B.value.imageUrl = ""
2489
+ }, {
2490
+ default: w(() => [...l[32] ||= [s("移除", -1)]]),
2491
+ _: 1
2492
+ })])) : (g(), r(_, {
2493
+ key: 1,
2494
+ size: "small",
2495
+ onClick: l[9] ||= (e) => ne.value?.click()
2496
+ }, {
2497
+ default: w(() => [...l[33] ||= [s("上传图片", -1)]]),
2498
+ _: 1
2499
+ }))]),
2500
+ c(_, {
2501
+ size: "small",
2502
+ onClick: l[10] ||= (e) => Ae(B.value)
2503
+ }, {
2504
+ default: w(() => [...l[35] ||= [s("适配子零件", -1)]]),
2505
+ _: 1
2506
+ })
2507
+ ], 64)) : (g(), a(e, { key: 1 }, [o("div", Ut, [l[36] ||= o("label", null, "宽度", -1), c(O, {
2508
+ modelValue: B.value.width,
2509
+ "onUpdate:modelValue": l[11] ||= (e) => B.value.width = e,
2510
+ min: 40,
2511
+ max: 400,
2512
+ size: "small"
2513
+ }, null, 8, ["modelValue"])]), o("div", Wt, [l[37] ||= o("label", null, "高度", -1), c(O, {
2514
+ modelValue: B.value.height,
2515
+ "onUpdate:modelValue": l[12] ||= (e) => B.value.height = e,
2516
+ min: 30,
2517
+ max: 300,
2518
+ size: "small"
2519
+ }, null, 8, ["modelValue"])])], 64)),
2520
+ o("div", Gt, [l[38] ||= o("label", null, "填充色", -1), c(k, {
2521
+ modelValue: B.value.fill,
2522
+ "onUpdate:modelValue": l[13] ||= (e) => B.value.fill = e,
2523
+ size: "small"
2524
+ }, null, 8, ["modelValue"])]),
2525
+ o("div", Kt, [l[39] ||= o("label", null, "边框色", -1), c(k, {
2526
+ modelValue: B.value.stroke,
2527
+ "onUpdate:modelValue": l[14] ||= (e) => B.value.stroke = e,
2528
+ size: "small"
2529
+ }, null, 8, ["modelValue"])]),
2530
+ o("div", qt, [l[40] ||= o("label", null, "文字色", -1), c(k, {
2531
+ modelValue: B.value.textColor,
2532
+ "onUpdate:modelValue": l[15] ||= (e) => B.value.textColor = e,
2533
+ size: "small"
2534
+ }, null, 8, ["modelValue"])]),
2535
+ o("div", Jt, [l[41] ||= o("label", null, "字号", -1), c(O, {
2536
+ modelValue: B.value.fontSize,
2537
+ "onUpdate:modelValue": l[16] ||= (e) => B.value.fontSize = e,
2538
+ min: 10,
2539
+ max: 32,
2540
+ size: "small"
2541
+ }, null, 8, ["modelValue"])]),
2542
+ c(_, {
2543
+ size: "small",
2544
+ onClick: $e
2545
+ }, {
2546
+ default: w(() => [...l[42] ||= [s("属性弹框设置", -1)]]),
2547
+ _: 1
2548
+ }),
2549
+ c(_, {
2550
+ size: "small",
2551
+ type: "danger",
2552
+ onClick: we
2553
+ }, {
2554
+ default: w(() => [...l[43] ||= [s("删除", -1)]]),
2555
+ _: 1
2556
+ })
2557
+ ], 64)) : z.value === "connection" ? (g(), a(e, { key: 1 }, [
2558
+ o("div", Yt, [l[44] ||= o("label", null, "标签", -1), c(T, {
2559
+ modelValue: B.value.label,
2560
+ "onUpdate:modelValue": l[17] ||= (e) => B.value.label = e,
2561
+ size: "small"
2562
+ }, null, 8, ["modelValue"])]),
2563
+ o("div", Xt, [l[45] ||= o("label", null, "线宽", -1), c(O, {
2564
+ modelValue: B.value.lineWidth,
2565
+ "onUpdate:modelValue": l[18] ||= (e) => B.value.lineWidth = e,
2566
+ min: 1,
2567
+ max: 6,
2568
+ size: "small"
2569
+ }, null, 8, ["modelValue"])]),
2570
+ o("div", Zt, [l[46] ||= o("label", null, "虚线", -1), c(A, {
2571
+ modelValue: B.value.dashed,
2572
+ "onUpdate:modelValue": l[19] ||= (e) => B.value.dashed = e
2573
+ }, null, 8, ["modelValue"])]),
2574
+ c(_, {
2575
+ size: "small",
2576
+ type: "danger",
2577
+ onClick: we
2578
+ }, {
2579
+ default: w(() => [...l[47] ||= [s("删除", -1)]]),
2580
+ _: 1
2581
+ })
2582
+ ], 64)) : i("", !0)])) : i("", !0)]),
2583
+ _: 1
2584
+ })]),
2585
+ c(q, {
2586
+ modelValue: G.value,
2587
+ "onUpdate:modelValue": l[22] ||= (e) => G.value = e,
2588
+ title: "属性弹框设置",
2589
+ width: "500",
2590
+ "append-to-body": ""
2591
+ }, {
2592
+ footer: w(() => [c(_, { onClick: l[21] ||= (e) => G.value = !1 }, {
2593
+ default: w(() => [...l[51] ||= [s("取消", -1)]]),
2594
+ _: 1
2595
+ }), c(_, {
2596
+ type: "primary",
2597
+ onClick: tt
2598
+ }, {
2599
+ default: w(() => [...l[52] ||= [s("保存", -1)]]),
2600
+ _: 1
2601
+ })]),
2602
+ default: w(() => [o("div", Qt, [
2603
+ c(_, {
2604
+ size: "small",
2605
+ onClick: et
2606
+ }, {
2607
+ default: w(() => [...l[48] ||= [s("+ 添加一行", -1)]]),
2608
+ _: 1
2609
+ }),
2610
+ c(_, {
2611
+ size: "small",
2612
+ onClick: l[20] ||= (e) => ie.value?.click()
2613
+ }, {
2614
+ default: w(() => [...l[49] ||= [s("导入JSON", -1)]]),
2615
+ _: 1
2616
+ }),
2617
+ o("input", {
2618
+ ref_key: "popupConfigImportRef",
2619
+ ref: ie,
2620
+ type: "file",
2621
+ accept: ".json",
2622
+ style: { display: "none" },
2623
+ onChange: nt
2624
+ }, null, 544)
2625
+ ]), c(ee, {
2626
+ data: K.value,
2627
+ border: "",
2628
+ size: "small",
2629
+ "max-height": "300"
2630
+ }, {
2631
+ default: w(() => [
2632
+ c(j, {
2633
+ label: "属性名",
2634
+ "min-width": "120"
2635
+ }, {
2636
+ default: w(({ row: e }) => [c(T, {
2637
+ modelValue: e.key,
2638
+ "onUpdate:modelValue": (t) => e.key = t,
2639
+ size: "small",
2640
+ placeholder: "属性名"
2641
+ }, null, 8, ["modelValue", "onUpdate:modelValue"])]),
2642
+ _: 1
2643
+ }),
2644
+ c(j, {
2645
+ label: "悬浮内容",
2646
+ "min-width": "200"
2647
+ }, {
2648
+ default: w(({ row: e }) => [c(T, {
2649
+ modelValue: e.value,
2650
+ "onUpdate:modelValue": (t) => e.value = t,
2651
+ size: "small",
2652
+ placeholder: "悬浮显示内容"
2653
+ }, null, 8, ["modelValue", "onUpdate:modelValue"])]),
2654
+ _: 1
2655
+ }),
2656
+ c(j, {
2657
+ width: "60",
2658
+ label: "操作"
2659
+ }, {
2660
+ default: w(({ $index: e }) => [c(_, {
2661
+ size: "small",
2662
+ type: "danger",
2663
+ text: "",
2664
+ onClick: (t) => K.value.splice(e, 1)
2665
+ }, {
2666
+ default: w(() => [...l[50] ||= [s("删除", -1)]]),
2667
+ _: 1
2668
+ }, 8, ["onClick"])]),
2669
+ _: 1
2670
+ })
2671
+ ]),
2672
+ _: 1
2673
+ }, 8, ["data"])]),
2674
+ _: 1
2675
+ }, 8, ["modelValue"]),
2676
+ c(_, {
2677
+ class: "ai-chat-fab",
2678
+ type: p.value ? "primary" : "default",
2679
+ circle: "",
2680
+ size: "large",
2681
+ onClick: l[23] ||= (e) => p.value = !p.value,
2682
+ title: "AI助手"
2683
+ }, {
2684
+ default: w(() => [c(h, null, {
2685
+ default: w(() => [c(ce)]),
2686
+ _: 1
2687
+ })]),
2688
+ _: 1
2689
+ }, 8, ["type"]),
2690
+ c(Te, {
2691
+ visible: p.value,
2692
+ messages: S(E).messages.value,
2693
+ loading: S(E).loading.value,
2694
+ "is-collab": S(E).isCollabMode.value,
2695
+ "collab-users": S(E).collabUsers.value,
2696
+ "current-user": S(E).currentUser.value,
2697
+ "is-owner": N.value,
2698
+ onSend: Re,
2699
+ onClose: l[24] ||= (e) => p.value = !1,
2700
+ "unread-mention": S(E).unreadMention.value,
2701
+ onClearUnread: l[25] ||= (e) => S(E).clearUnreadMention(),
2702
+ onClear: ze
2703
+ }, null, 8, [
2704
+ "visible",
2705
+ "messages",
2706
+ "loading",
2707
+ "is-collab",
2708
+ "collab-users",
2709
+ "current-user",
2710
+ "is-owner",
2711
+ "unread-mention"
2712
+ ]),
2713
+ c(Ve, {
2714
+ modelValue: C.value,
2715
+ "onUpdate:modelValue": l[26] ||= (e) => C.value = e,
2716
+ "document-id": f.value,
2717
+ onApply: He
2718
+ }, null, 8, ["modelValue", "document-id"])
2719
+ ]);
2720
+ };
2721
+ }
2722
+ }, [["__scopeId", "data-v-f2d3d8e9"]]), tn = l({
2723
+ name: "YourCompanyExplosionDiagram",
2724
+ props: {
2725
+ docId: {
2726
+ type: [Number, String],
2727
+ default: null
2728
+ },
2729
+ apiBase: {
2730
+ type: String,
2731
+ default: "/api"
2732
+ },
2733
+ wsUrl: {
2734
+ type: String,
2735
+ default: ""
2736
+ },
2737
+ user: {
2738
+ type: Object,
2739
+ default: () => ({
2740
+ id: "",
2741
+ name: "",
2742
+ color: ""
2743
+ })
2744
+ },
2745
+ roomId: {
2746
+ type: String,
2747
+ default: ""
2748
+ }
2749
+ },
2750
+ setup(e, { slots: t }) {
2751
+ return () => u("div", {
2752
+ class: "yourcompany-explosion-diagram-wrapper",
2753
+ style: "position:relative"
2754
+ }, [u(en, { ...e }), u(D)]);
2755
+ }
2756
+ });
2757
+ //#endregion
2758
+ export { tn as default };