vue-seat-designer 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.
- package/dist/style.css +1 -0
- package/dist/vue-seat-designer.es.js +333 -0
- package/dist/vue-seat-designer.umd.js +1 -0
- package/package.json +46 -0
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.designer-container[data-v-33b6094b]{display:flex;height:100vh;width:100vw}.toolbar[data-v-33b6094b]{width:200px;background-color:#fff;border-right:1px solid #e8e8e8;padding:20px;overflow-y:auto}.toolbar h3[data-v-33b6094b]{margin-bottom:20px;color:#333}.tool-item[data-v-33b6094b]{display:flex;align-items:center;padding:10px;margin-bottom:10px;background-color:#f5f5f5;border-radius:4px;cursor:move;transition:all .3s ease}.tool-item[data-v-33b6094b]:hover{background-color:#e6f7ff}.tool-icon[data-v-33b6094b]{width:30px;height:30px;margin-right:10px;background-color:#1890ff;border-radius:4px;display:flex;align-items:center;justify-content:center;color:#fff}.canvas-area[data-v-33b6094b]{flex:1;background-color:#fafafa;position:relative;overflow:hidden}.canvas[data-v-33b6094b]{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:#fff;border:2px dashed #d9d9d9;min-width:600px;min-height:400px}.canvas-item[data-v-33b6094b]{position:absolute;cursor:move;border:2px solid transparent;transition:all .3s ease;display:flex;align-items:center;justify-content:center;color:#fff;border-radius:4px}.canvas-item[data-v-33b6094b]:hover{border-color:#1890ff}.canvas-item.selected[data-v-33b6094b]{border-color:#1890ff;box-shadow:0 0 0 2px #1890ff33}.config-panel[data-v-33b6094b]{width:300px;background-color:#fff;border-left:1px solid #e8e8e8;padding:20px;overflow-y:auto}.config-section[data-v-33b6094b]{margin-bottom:30px}.config-section h3[data-v-33b6094b]{margin-bottom:15px;color:#333;font-size:14px}.config-item[data-v-33b6094b]{margin-bottom:15px}.config-label[data-v-33b6094b]{display:block;margin-bottom:5px;font-size:12px;color:#666}.config-input[data-v-33b6094b]{width:100%;padding:8px;border:1px solid #d9d9d9;border-radius:4px;font-size:14px}.config-checkbox[data-v-33b6094b]{margin-right:5px}.color-picker[data-v-33b6094b]{display:flex;align-items:center}.color-preview[data-v-33b6094b]{width:30px;height:30px;margin-right:10px;border:1px solid #d9d9d9;border-radius:4px}.canvas-size[data-v-33b6094b]{display:flex;gap:10px}.canvas-size input[data-v-33b6094b]{flex:1}.action-buttons[data-v-33b6094b]{display:flex;gap:10px;margin-top:20px}.btn[data-v-33b6094b]{padding:8px 16px;border:none;border-radius:4px;cursor:pointer;font-size:14px}.btn-primary[data-v-33b6094b]{background-color:#1890ff;color:#fff}.btn-default[data-v-33b6094b]{background-color:#f5f5f5;color:#333}.btn[data-v-33b6094b]:disabled{opacity:.6;cursor:not-allowed}.preview-container[data-v-b969ea97]{display:flex;align-items:center;justify-content:center;min-height:100vh;background-color:#f0f2f5;padding:20px}.preview-content[data-v-b969ea97]{display:flex;flex-direction:column;align-items:center;max-width:100%}.preview-title[data-v-b969ea97]{margin-bottom:20px;font-size:18px;color:#333}.preview-canvas[data-v-b969ea97]{background-color:#fff;border:1px solid #e8e8e8;box-shadow:0 2px 8px #00000026;position:relative;overflow:hidden;margin:0 auto}.preview-item[data-v-b969ea97]{position:absolute;display:flex;align-items:center;justify-content:center;color:#fff;border-radius:4px;transition:all .3s ease;border:2px solid transparent}.preview-item[data-v-b969ea97]:hover{border-color:#1890ff80}.preview-item.selected[data-v-b969ea97]{border-color:#1890ff;box-shadow:0 0 0 2px #1890ff33}@media (max-width: 768px){.preview-canvas[data-v-b969ea97]{max-width:100%}}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { defineComponent as B, ref as _, watch as z, openBlock as h, createElementBlock as g, createElementVNode as o, Fragment as T, renderList as M, toDisplayString as $, normalizeStyle as C, unref as i, withModifiers as F, normalizeClass as X, withDirectives as w, vModelText as D, vModelCheckbox as H, createTextVNode as W, createCommentVNode as j } from "vue";
|
|
2
|
+
function A() {
|
|
3
|
+
return Math.random().toString(36).substr(2, 9);
|
|
4
|
+
}
|
|
5
|
+
function G(d, p) {
|
|
6
|
+
const c = p.getBoundingClientRect();
|
|
7
|
+
return {
|
|
8
|
+
x: d.clientX - c.left,
|
|
9
|
+
y: d.clientY - c.top
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function V(d, p, c) {
|
|
13
|
+
return {
|
|
14
|
+
...d,
|
|
15
|
+
x: Math.max(0, Math.min(d.x, p - d.width)),
|
|
16
|
+
y: Math.max(0, Math.min(d.y, c - d.height))
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const J = { class: "designer-container" }, K = { class: "toolbar" }, Q = ["onDragstart"], Z = { class: "tool-icon" }, ee = { class: "canvas-area" }, te = ["onClick", "onMousedown"], oe = { class: "config-panel" }, ne = { class: "config-section" }, le = { class: "canvas-size" }, se = { class: "config-item" }, ie = { class: "config-item" }, ae = {
|
|
20
|
+
key: 0,
|
|
21
|
+
class: "config-section"
|
|
22
|
+
}, de = { class: "config-item" }, ce = { class: "config-label" }, re = { class: "config-item" }, ue = { class: "color-picker" }, pe = { class: "config-item" }, ve = { class: "color-picker" }, fe = { class: "action-buttons" }, he = ["disabled"], ge = /* @__PURE__ */ B({
|
|
23
|
+
__name: "SeatDesigner",
|
|
24
|
+
props: {
|
|
25
|
+
modelValue: {}
|
|
26
|
+
},
|
|
27
|
+
emits: ["update:modelValue", "save"],
|
|
28
|
+
setup(d, { emit: p }) {
|
|
29
|
+
const c = d, m = p, n = _({
|
|
30
|
+
width: 800,
|
|
31
|
+
height: 600,
|
|
32
|
+
items: []
|
|
33
|
+
}), l = _(null), b = _(!1), x = _({ x: 0, y: 0 }), k = [
|
|
34
|
+
{ type: "seat", name: "座位", icon: "S" },
|
|
35
|
+
{ type: "bookshelf", name: "书架", icon: "B" },
|
|
36
|
+
{ type: "toilet", name: "卫生间", icon: "T" }
|
|
37
|
+
], u = {
|
|
38
|
+
seat: { width: 40, height: 40, defaultColor: "#52c41a", selectedColor: "#1890ff" },
|
|
39
|
+
bookshelf: { width: 80, height: 120, defaultColor: "#faad14", selectedColor: "#1890ff" },
|
|
40
|
+
toilet: { width: 60, height: 60, defaultColor: "#f5222d", selectedColor: "#1890ff" }
|
|
41
|
+
};
|
|
42
|
+
z(() => c.modelValue, (s) => {
|
|
43
|
+
s && (n.value = { ...s });
|
|
44
|
+
}, { deep: !0 }), z(n, (s) => {
|
|
45
|
+
m("update:modelValue", { ...s });
|
|
46
|
+
}, { deep: !0 });
|
|
47
|
+
function f(s, e) {
|
|
48
|
+
s.dataTransfer && s.dataTransfer.setData("text/plain", e);
|
|
49
|
+
}
|
|
50
|
+
function a(s) {
|
|
51
|
+
if (s.preventDefault(), !s.dataTransfer)
|
|
52
|
+
return;
|
|
53
|
+
const e = s.dataTransfer.getData("text/plain");
|
|
54
|
+
if (!e)
|
|
55
|
+
return;
|
|
56
|
+
const t = s.currentTarget, v = G(s, t), r = u[e], y = {
|
|
57
|
+
id: A(),
|
|
58
|
+
type: e,
|
|
59
|
+
x: v.x - r.width / 2,
|
|
60
|
+
y: v.y - r.height / 2,
|
|
61
|
+
width: r.width,
|
|
62
|
+
height: r.height,
|
|
63
|
+
selectable: !0,
|
|
64
|
+
defaultColor: r.defaultColor,
|
|
65
|
+
selectedColor: r.selectedColor
|
|
66
|
+
}, I = V(y, n.value.width, n.value.height);
|
|
67
|
+
n.value.items.push(I);
|
|
68
|
+
}
|
|
69
|
+
function E(s) {
|
|
70
|
+
l.value = s;
|
|
71
|
+
}
|
|
72
|
+
function N(s, e) {
|
|
73
|
+
s.stopPropagation(), b.value = !0, l.value = e;
|
|
74
|
+
const t = s.currentTarget.getBoundingClientRect();
|
|
75
|
+
x.value = {
|
|
76
|
+
x: s.clientX - t.left,
|
|
77
|
+
y: s.clientY - t.top
|
|
78
|
+
}, document.addEventListener("mousemove", P), document.addEventListener("mouseup", L);
|
|
79
|
+
}
|
|
80
|
+
function P(s) {
|
|
81
|
+
if (!b.value || !l.value)
|
|
82
|
+
return;
|
|
83
|
+
const e = document.querySelector(".canvas");
|
|
84
|
+
if (!e)
|
|
85
|
+
return;
|
|
86
|
+
const t = e.getBoundingClientRect();
|
|
87
|
+
let v = s.clientX - t.left - x.value.x, r = s.clientY - t.top - x.value.y;
|
|
88
|
+
const y = {
|
|
89
|
+
...l.value,
|
|
90
|
+
x: v,
|
|
91
|
+
y: r
|
|
92
|
+
}, I = V(y, n.value.width, n.value.height);
|
|
93
|
+
l.value.x = I.x, l.value.y = I.y;
|
|
94
|
+
}
|
|
95
|
+
function L() {
|
|
96
|
+
b.value = !1, document.removeEventListener("mousemove", P), document.removeEventListener("mouseup", L);
|
|
97
|
+
}
|
|
98
|
+
function U() {
|
|
99
|
+
n.value.width < 200 && (n.value.width = 200), n.value.height < 200 && (n.value.height = 200), n.value.items = n.value.items.map(
|
|
100
|
+
(s) => V(s, n.value.width, n.value.height)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
function S() {
|
|
104
|
+
}
|
|
105
|
+
function O() {
|
|
106
|
+
l.value && (n.value.items = n.value.items.filter(
|
|
107
|
+
(s) => {
|
|
108
|
+
var e;
|
|
109
|
+
return s.id !== ((e = l.value) == null ? void 0 : e.id);
|
|
110
|
+
}
|
|
111
|
+
), l.value = null);
|
|
112
|
+
}
|
|
113
|
+
function R() {
|
|
114
|
+
m("save", { ...n.value });
|
|
115
|
+
}
|
|
116
|
+
function q(s) {
|
|
117
|
+
var e;
|
|
118
|
+
return ((e = k.find((t) => t.type === s)) == null ? void 0 : e.icon) || "";
|
|
119
|
+
}
|
|
120
|
+
return (s, e) => (h(), g("div", J, [
|
|
121
|
+
o("div", K, [
|
|
122
|
+
e[7] || (e[7] = o("h3", null, "工具栏", -1)),
|
|
123
|
+
(h(), g(T, null, M(k, (t) => o("div", {
|
|
124
|
+
key: t.type,
|
|
125
|
+
class: "tool-item",
|
|
126
|
+
draggable: "true",
|
|
127
|
+
onDragstart: (v) => f(v, t.type)
|
|
128
|
+
}, [
|
|
129
|
+
o("div", Z, $(t.icon), 1),
|
|
130
|
+
o("span", null, $(t.name), 1)
|
|
131
|
+
], 40, Q)), 64))
|
|
132
|
+
]),
|
|
133
|
+
o("div", ee, [
|
|
134
|
+
o("div", {
|
|
135
|
+
class: "canvas",
|
|
136
|
+
style: C({ width: `${i(n).width}px`, height: `${i(n).height}px` }),
|
|
137
|
+
onDragover: e[0] || (e[0] = F(() => {
|
|
138
|
+
}, ["prevent"])),
|
|
139
|
+
onDrop: e[1] || (e[1] = (t) => a(t))
|
|
140
|
+
}, [
|
|
141
|
+
(h(!0), g(T, null, M(i(n).items, (t) => {
|
|
142
|
+
var v, r;
|
|
143
|
+
return h(), g("div", {
|
|
144
|
+
key: t.id,
|
|
145
|
+
class: X(["canvas-item", { selected: ((v = i(l)) == null ? void 0 : v.id) === t.id, [t.type]: !0 }]),
|
|
146
|
+
style: C({
|
|
147
|
+
left: `${t.x}px`,
|
|
148
|
+
top: `${t.y}px`,
|
|
149
|
+
width: `${t.width}px`,
|
|
150
|
+
height: `${t.height}px`,
|
|
151
|
+
backgroundColor: ((r = i(l)) == null ? void 0 : r.id) === t.id ? t.selectedColor : t.defaultColor
|
|
152
|
+
}),
|
|
153
|
+
onClick: (y) => E(t),
|
|
154
|
+
onMousedown: (y) => N(y, t)
|
|
155
|
+
}, $(q(t.type)), 47, te);
|
|
156
|
+
}), 128))
|
|
157
|
+
], 36)
|
|
158
|
+
]),
|
|
159
|
+
o("div", oe, [
|
|
160
|
+
o("div", ne, [
|
|
161
|
+
e[10] || (e[10] = o("h3", null, "画布设置", -1)),
|
|
162
|
+
o("div", le, [
|
|
163
|
+
o("div", se, [
|
|
164
|
+
e[8] || (e[8] = o("label", { class: "config-label" }, "宽度", -1)),
|
|
165
|
+
w(o("input", {
|
|
166
|
+
type: "number",
|
|
167
|
+
class: "config-input",
|
|
168
|
+
"onUpdate:modelValue": e[2] || (e[2] = (t) => i(n).width = t),
|
|
169
|
+
onChange: U
|
|
170
|
+
}, null, 544), [
|
|
171
|
+
[
|
|
172
|
+
D,
|
|
173
|
+
i(n).width,
|
|
174
|
+
void 0,
|
|
175
|
+
{ number: !0 }
|
|
176
|
+
]
|
|
177
|
+
])
|
|
178
|
+
]),
|
|
179
|
+
o("div", ie, [
|
|
180
|
+
e[9] || (e[9] = o("label", { class: "config-label" }, "高度", -1)),
|
|
181
|
+
w(o("input", {
|
|
182
|
+
type: "number",
|
|
183
|
+
class: "config-input",
|
|
184
|
+
"onUpdate:modelValue": e[3] || (e[3] = (t) => i(n).height = t),
|
|
185
|
+
onChange: U
|
|
186
|
+
}, null, 544), [
|
|
187
|
+
[
|
|
188
|
+
D,
|
|
189
|
+
i(n).height,
|
|
190
|
+
void 0,
|
|
191
|
+
{ number: !0 }
|
|
192
|
+
]
|
|
193
|
+
])
|
|
194
|
+
])
|
|
195
|
+
])
|
|
196
|
+
]),
|
|
197
|
+
i(l) ? (h(), g("div", ae, [
|
|
198
|
+
e[14] || (e[14] = o("h3", null, "元素配置", -1)),
|
|
199
|
+
o("div", de, [
|
|
200
|
+
o("label", ce, [
|
|
201
|
+
w(o("input", {
|
|
202
|
+
type: "checkbox",
|
|
203
|
+
class: "config-checkbox",
|
|
204
|
+
"onUpdate:modelValue": e[4] || (e[4] = (t) => i(l).selectable = t),
|
|
205
|
+
onChange: S
|
|
206
|
+
}, null, 544), [
|
|
207
|
+
[H, i(l).selectable]
|
|
208
|
+
]),
|
|
209
|
+
e[11] || (e[11] = W(" 可选择 ", -1))
|
|
210
|
+
])
|
|
211
|
+
]),
|
|
212
|
+
o("div", re, [
|
|
213
|
+
e[12] || (e[12] = o("label", { class: "config-label" }, "默认颜色", -1)),
|
|
214
|
+
o("div", ue, [
|
|
215
|
+
o("div", {
|
|
216
|
+
class: "color-preview",
|
|
217
|
+
style: C({ backgroundColor: i(l).defaultColor })
|
|
218
|
+
}, null, 4),
|
|
219
|
+
w(o("input", {
|
|
220
|
+
type: "color",
|
|
221
|
+
class: "config-input",
|
|
222
|
+
"onUpdate:modelValue": e[5] || (e[5] = (t) => i(l).defaultColor = t),
|
|
223
|
+
onChange: S
|
|
224
|
+
}, null, 544), [
|
|
225
|
+
[D, i(l).defaultColor]
|
|
226
|
+
])
|
|
227
|
+
])
|
|
228
|
+
]),
|
|
229
|
+
o("div", pe, [
|
|
230
|
+
e[13] || (e[13] = o("label", { class: "config-label" }, "选择后颜色", -1)),
|
|
231
|
+
o("div", ve, [
|
|
232
|
+
o("div", {
|
|
233
|
+
class: "color-preview",
|
|
234
|
+
style: C({ backgroundColor: i(l).selectedColor })
|
|
235
|
+
}, null, 4),
|
|
236
|
+
w(o("input", {
|
|
237
|
+
type: "color",
|
|
238
|
+
class: "config-input",
|
|
239
|
+
"onUpdate:modelValue": e[6] || (e[6] = (t) => i(l).selectedColor = t),
|
|
240
|
+
onChange: S
|
|
241
|
+
}, null, 544), [
|
|
242
|
+
[D, i(l).selectedColor]
|
|
243
|
+
])
|
|
244
|
+
])
|
|
245
|
+
])
|
|
246
|
+
])) : j("", !0),
|
|
247
|
+
o("div", fe, [
|
|
248
|
+
o("button", {
|
|
249
|
+
class: "btn btn-primary",
|
|
250
|
+
onClick: R
|
|
251
|
+
}, "保存"),
|
|
252
|
+
o("button", {
|
|
253
|
+
class: "btn btn-default",
|
|
254
|
+
onClick: O,
|
|
255
|
+
disabled: !i(l)
|
|
256
|
+
}, " 删除选中 ", 8, he)
|
|
257
|
+
])
|
|
258
|
+
])
|
|
259
|
+
]));
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const Y = (d, p) => {
|
|
263
|
+
const c = d.__vccOpts || d;
|
|
264
|
+
for (const [m, n] of p)
|
|
265
|
+
c[m] = n;
|
|
266
|
+
return c;
|
|
267
|
+
}, me = /* @__PURE__ */ Y(ge, [["__scopeId", "data-v-33b6094b"]]), ye = { class: "preview-container" }, _e = { class: "preview-content" }, Ce = ["onClick"], be = /* @__PURE__ */ B({
|
|
268
|
+
__name: "SeatPreview",
|
|
269
|
+
props: {
|
|
270
|
+
modelValue: {},
|
|
271
|
+
selectedItems: {}
|
|
272
|
+
},
|
|
273
|
+
emits: ["update:selectedItems", "itemClick"],
|
|
274
|
+
setup(d, { emit: p }) {
|
|
275
|
+
const c = d, m = p, n = _({
|
|
276
|
+
width: 800,
|
|
277
|
+
height: 600,
|
|
278
|
+
items: []
|
|
279
|
+
}), l = _(c.selectedItems || []), b = [
|
|
280
|
+
{ type: "seat", name: "座位", icon: "S" },
|
|
281
|
+
{ type: "bookshelf", name: "书架", icon: "B" },
|
|
282
|
+
{ type: "toilet", name: "卫生间", icon: "T" }
|
|
283
|
+
];
|
|
284
|
+
c.modelValue && (n.value = { ...c.modelValue }), c.selectedItems && (l.value = [...c.selectedItems]);
|
|
285
|
+
function x(u) {
|
|
286
|
+
if (!u.selectable)
|
|
287
|
+
return;
|
|
288
|
+
l.value.indexOf(u.id) > -1 ? l.value = l.value.filter((a) => a !== u.id) : l.value.push(u.id), m("update:selectedItems", [...l.value]), m("itemClick", u);
|
|
289
|
+
}
|
|
290
|
+
function k(u) {
|
|
291
|
+
var f;
|
|
292
|
+
return ((f = b.find((a) => a.type === u)) == null ? void 0 : f.icon) || "";
|
|
293
|
+
}
|
|
294
|
+
return (u, f) => (h(), g("div", ye, [
|
|
295
|
+
o("div", _e, [
|
|
296
|
+
f[0] || (f[0] = o("h2", { class: "preview-title" }, "预览", -1)),
|
|
297
|
+
o("div", {
|
|
298
|
+
class: "preview-canvas",
|
|
299
|
+
style: C({
|
|
300
|
+
width: `${i(n).width}px`,
|
|
301
|
+
height: `${i(n).height}px`,
|
|
302
|
+
maxWidth: "100%",
|
|
303
|
+
maxHeight: "80vh"
|
|
304
|
+
})
|
|
305
|
+
}, [
|
|
306
|
+
(h(!0), g(T, null, M(i(n).items, (a) => (h(), g("div", {
|
|
307
|
+
key: a.id,
|
|
308
|
+
class: X(["preview-item", { [a.type]: !0, selected: i(l).includes(a.id) }]),
|
|
309
|
+
style: C({
|
|
310
|
+
left: `${a.x}px`,
|
|
311
|
+
top: `${a.y}px`,
|
|
312
|
+
width: `${a.width}px`,
|
|
313
|
+
height: `${a.height}px`,
|
|
314
|
+
backgroundColor: i(l).includes(a.id) ? a.selectedColor : a.defaultColor,
|
|
315
|
+
cursor: a.selectable ? "pointer" : "default"
|
|
316
|
+
}),
|
|
317
|
+
onClick: (E) => x(a)
|
|
318
|
+
}, $(k(a.type)), 15, Ce))), 128))
|
|
319
|
+
], 4)
|
|
320
|
+
])
|
|
321
|
+
]));
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
const xe = /* @__PURE__ */ Y(be, [["__scopeId", "data-v-b969ea97"]]), ke = B({
|
|
325
|
+
install: (d) => {
|
|
326
|
+
d.component("SeatDesigner", me), d.component("SeatPreview", xe);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
export {
|
|
330
|
+
me as SeatDesigner,
|
|
331
|
+
xe as SeatPreview,
|
|
332
|
+
ke as default
|
|
333
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(f,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(f=typeof globalThis<"u"?globalThis:f||self,e(f.VueSeatDesigner={},f.Vue))})(this,function(f,e){"use strict";function B(){return Math.random().toString(36).substr(2,9)}function $(a,m){const r=m.getBoundingClientRect();return{x:a.clientX-r.left,y:a.clientY-r.top}}function b(a,m,r){return{...a,x:Math.max(0,Math.min(a.x,m-a.width)),y:Math.max(0,Math.min(a.y,r-a.height))}}const T={class:"designer-container"},M={class:"toolbar"},z=["onDragstart"],P={class:"tool-icon"},L={class:"canvas-area"},U=["onClick","onMousedown"],O={class:"config-panel"},X={class:"config-section"},Y={class:"canvas-size"},F={class:"config-item"},R={class:"config-item"},j={key:0,class:"config-section"},q={class:"config-item"},v={class:"config-label"},H={class:"config-item"},W={class:"color-picker"},A={class:"config-item"},G={class:"color-picker"},J={class:"action-buttons"},K=["disabled"],Q=e.defineComponent({__name:"SeatDesigner",props:{modelValue:{}},emits:["update:modelValue","save"],setup(a,{emit:m}){const r=a,h=m,o=e.ref({width:800,height:600,items:[]}),l=e.ref(null),y=e.ref(!1),_=e.ref({x:0,y:0}),C=[{type:"seat",name:"座位",icon:"S"},{type:"bookshelf",name:"书架",icon:"B"},{type:"toilet",name:"卫生间",icon:"T"}],d={seat:{width:40,height:40,defaultColor:"#52c41a",selectedColor:"#1890ff"},bookshelf:{width:80,height:120,defaultColor:"#faad14",selectedColor:"#1890ff"},toilet:{width:60,height:60,defaultColor:"#f5222d",selectedColor:"#1890ff"}};e.watch(()=>r.modelValue,s=>{s&&(o.value={...s})},{deep:!0}),e.watch(o,s=>{h("update:modelValue",{...s})},{deep:!0});function u(s,t){s.dataTransfer&&s.dataTransfer.setData("text/plain",t)}function i(s){if(s.preventDefault(),!s.dataTransfer)return;const t=s.dataTransfer.getData("text/plain");if(!t)return;const n=s.currentTarget,p=$(s,n),c=d[t],g={id:B(),type:t,x:p.x-c.width/2,y:p.y-c.height/2,width:c.width,height:c.height,selectable:!0,defaultColor:c.defaultColor,selectedColor:c.selectedColor},V=b(g,o.value.width,o.value.height);o.value.items.push(V)}function N(s){l.value=s}function le(s,t){s.stopPropagation(),y.value=!0,l.value=t;const n=s.currentTarget.getBoundingClientRect();_.value={x:s.clientX-n.left,y:s.clientY-n.top},document.addEventListener("mousemove",S),document.addEventListener("mouseup",D)}function S(s){if(!y.value||!l.value)return;const t=document.querySelector(".canvas");if(!t)return;const n=t.getBoundingClientRect();let p=s.clientX-n.left-_.value.x,c=s.clientY-n.top-_.value.y;const g={...l.value,x:p,y:c},V=b(g,o.value.width,o.value.height);l.value.x=V.x,l.value.y=V.y}function D(){y.value=!1,document.removeEventListener("mousemove",S),document.removeEventListener("mouseup",D)}function I(){o.value.width<200&&(o.value.width=200),o.value.height<200&&(o.value.height=200),o.value.items=o.value.items.map(s=>b(s,o.value.width,o.value.height))}function E(){}function se(){l.value&&(o.value.items=o.value.items.filter(s=>{var t;return s.id!==((t=l.value)==null?void 0:t.id)}),l.value=null)}function ie(){h("save",{...o.value})}function ae(s){var t;return((t=C.find(n=>n.type===s))==null?void 0:t.icon)||""}return(s,t)=>(e.openBlock(),e.createElementBlock("div",T,[e.createElementVNode("div",M,[t[7]||(t[7]=e.createElementVNode("h3",null,"工具栏",-1)),(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(C,n=>e.createElementVNode("div",{key:n.type,class:"tool-item",draggable:"true",onDragstart:p=>u(p,n.type)},[e.createElementVNode("div",P,e.toDisplayString(n.icon),1),e.createElementVNode("span",null,e.toDisplayString(n.name),1)],40,z)),64))]),e.createElementVNode("div",L,[e.createElementVNode("div",{class:"canvas",style:e.normalizeStyle({width:`${e.unref(o).width}px`,height:`${e.unref(o).height}px`}),onDragover:t[0]||(t[0]=e.withModifiers(()=>{},["prevent"])),onDrop:t[1]||(t[1]=n=>i(n))},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(o).items,n=>{var p,c;return e.openBlock(),e.createElementBlock("div",{key:n.id,class:e.normalizeClass(["canvas-item",{selected:((p=e.unref(l))==null?void 0:p.id)===n.id,[n.type]:!0}]),style:e.normalizeStyle({left:`${n.x}px`,top:`${n.y}px`,width:`${n.width}px`,height:`${n.height}px`,backgroundColor:((c=e.unref(l))==null?void 0:c.id)===n.id?n.selectedColor:n.defaultColor}),onClick:g=>N(n),onMousedown:g=>le(g,n)},e.toDisplayString(ae(n.type)),47,U)}),128))],36)]),e.createElementVNode("div",O,[e.createElementVNode("div",X,[t[10]||(t[10]=e.createElementVNode("h3",null,"画布设置",-1)),e.createElementVNode("div",Y,[e.createElementVNode("div",F,[t[8]||(t[8]=e.createElementVNode("label",{class:"config-label"},"宽度",-1)),e.withDirectives(e.createElementVNode("input",{type:"number",class:"config-input","onUpdate:modelValue":t[2]||(t[2]=n=>e.unref(o).width=n),onChange:I},null,544),[[e.vModelText,e.unref(o).width,void 0,{number:!0}]])]),e.createElementVNode("div",R,[t[9]||(t[9]=e.createElementVNode("label",{class:"config-label"},"高度",-1)),e.withDirectives(e.createElementVNode("input",{type:"number",class:"config-input","onUpdate:modelValue":t[3]||(t[3]=n=>e.unref(o).height=n),onChange:I},null,544),[[e.vModelText,e.unref(o).height,void 0,{number:!0}]])])])]),e.unref(l)?(e.openBlock(),e.createElementBlock("div",j,[t[14]||(t[14]=e.createElementVNode("h3",null,"元素配置",-1)),e.createElementVNode("div",q,[e.createElementVNode("label",v,[e.withDirectives(e.createElementVNode("input",{type:"checkbox",class:"config-checkbox","onUpdate:modelValue":t[4]||(t[4]=n=>e.unref(l).selectable=n),onChange:E},null,544),[[e.vModelCheckbox,e.unref(l).selectable]]),t[11]||(t[11]=e.createTextVNode(" 可选择 ",-1))])]),e.createElementVNode("div",H,[t[12]||(t[12]=e.createElementVNode("label",{class:"config-label"},"默认颜色",-1)),e.createElementVNode("div",W,[e.createElementVNode("div",{class:"color-preview",style:e.normalizeStyle({backgroundColor:e.unref(l).defaultColor})},null,4),e.withDirectives(e.createElementVNode("input",{type:"color",class:"config-input","onUpdate:modelValue":t[5]||(t[5]=n=>e.unref(l).defaultColor=n),onChange:E},null,544),[[e.vModelText,e.unref(l).defaultColor]])])]),e.createElementVNode("div",A,[t[13]||(t[13]=e.createElementVNode("label",{class:"config-label"},"选择后颜色",-1)),e.createElementVNode("div",G,[e.createElementVNode("div",{class:"color-preview",style:e.normalizeStyle({backgroundColor:e.unref(l).selectedColor})},null,4),e.withDirectives(e.createElementVNode("input",{type:"color",class:"config-input","onUpdate:modelValue":t[6]||(t[6]=n=>e.unref(l).selectedColor=n),onChange:E},null,544),[[e.vModelText,e.unref(l).selectedColor]])])])])):e.createCommentVNode("",!0),e.createElementVNode("div",J,[e.createElementVNode("button",{class:"btn btn-primary",onClick:ie},"保存"),e.createElementVNode("button",{class:"btn btn-default",onClick:se,disabled:!e.unref(l)}," 删除选中 ",8,K)])])]))}}),re="",w=(a,m)=>{const r=a.__vccOpts||a;for(const[h,o]of m)r[h]=o;return r},x=w(Q,[["__scopeId","data-v-33b6094b"]]),Z={class:"preview-container"},ee={class:"preview-content"},te=["onClick"],ne=e.defineComponent({__name:"SeatPreview",props:{modelValue:{},selectedItems:{}},emits:["update:selectedItems","itemClick"],setup(a,{emit:m}){const r=a,h=m,o=e.ref({width:800,height:600,items:[]}),l=e.ref(r.selectedItems||[]),y=[{type:"seat",name:"座位",icon:"S"},{type:"bookshelf",name:"书架",icon:"B"},{type:"toilet",name:"卫生间",icon:"T"}];r.modelValue&&(o.value={...r.modelValue}),r.selectedItems&&(l.value=[...r.selectedItems]);function _(d){if(!d.selectable)return;l.value.indexOf(d.id)>-1?l.value=l.value.filter(i=>i!==d.id):l.value.push(d.id),h("update:selectedItems",[...l.value]),h("itemClick",d)}function C(d){var u;return((u=y.find(i=>i.type===d))==null?void 0:u.icon)||""}return(d,u)=>(e.openBlock(),e.createElementBlock("div",Z,[e.createElementVNode("div",ee,[u[0]||(u[0]=e.createElementVNode("h2",{class:"preview-title"},"预览",-1)),e.createElementVNode("div",{class:"preview-canvas",style:e.normalizeStyle({width:`${e.unref(o).width}px`,height:`${e.unref(o).height}px`,maxWidth:"100%",maxHeight:"80vh"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(o).items,i=>(e.openBlock(),e.createElementBlock("div",{key:i.id,class:e.normalizeClass(["preview-item",{[i.type]:!0,selected:e.unref(l).includes(i.id)}]),style:e.normalizeStyle({left:`${i.x}px`,top:`${i.y}px`,width:`${i.width}px`,height:`${i.height}px`,backgroundColor:e.unref(l).includes(i.id)?i.selectedColor:i.defaultColor,cursor:i.selectable?"pointer":"default"}),onClick:N=>_(i)},e.toDisplayString(C(i.type)),15,te))),128))],4)])]))}}),ce="",k=w(ne,[["__scopeId","data-v-b969ea97"]]),oe=e.defineComponent({install:a=>{a.component("SeatDesigner",x),a.component("SeatPreview",k)}});f.SeatDesigner=x,f.SeatPreview=k,f.default=oe,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vue-seat-designer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Vue component for designing seat layouts with drag-and-drop functionality",
|
|
5
|
+
"main": "dist/vue-seat-designer.umd.js",
|
|
6
|
+
"module": "dist/vue-seat-designer.es.js",
|
|
7
|
+
"unpkg": "dist/vue-seat-designer.umd.js",
|
|
8
|
+
"types": "dist/types/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "vite",
|
|
14
|
+
"build": "vite build --mode lib",
|
|
15
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
16
|
+
"preview": "vite preview",
|
|
17
|
+
"test": "vitest",
|
|
18
|
+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@vueuse/core": "^14.2.1",
|
|
22
|
+
"vue-demi": "^0.14.7"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"vue": ">=2.6.12 || >=3.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@vitejs/plugin-vue": "^4.2.3",
|
|
29
|
+
"@vue/compiler-sfc": "^3.3.4",
|
|
30
|
+
"eslint": "^8.46.0",
|
|
31
|
+
"eslint-plugin-vue": "^9.16.1",
|
|
32
|
+
"typescript": "^5.1.6",
|
|
33
|
+
"vite": "^4.4.9",
|
|
34
|
+
"vitest": "^0.34.3",
|
|
35
|
+
"vue": "^3.3.4"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"vue",
|
|
39
|
+
"seat",
|
|
40
|
+
"designer",
|
|
41
|
+
"drag-and-drop",
|
|
42
|
+
"layout"
|
|
43
|
+
],
|
|
44
|
+
"author": "",
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|