tree-upload-vue3 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/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Tree Upload Component (Vue 3 + Element Plus)
2
+
3
+ 一个基于 Schema 驱动的低代码树形文件管理组件。
4
+
5
+ ## 特性
6
+
7
+ - **声明式配置**: 通过 JSON Schema 定义树、上传、表格、预览和权限。
8
+ - **左侧树**: 支持静态/API数据源,支持节点增删改(Context Menu)。
9
+ - **右侧上传**: 支持多文件、拖拽、自动上传,支持自定义 Headers 和额外参数。
10
+ - **右侧表格**: 支持静态/API数据源,分页,自定义列,格式化器。
11
+ - **文件预览**: 集成 `file-preview-vue3-ts`,支持多种文件格式。
12
+ - **模板下载**: 支持节点级模板配置。
13
+ - **权限控制**: 细粒度的权限规则引擎。
14
+ - **上下文**: 支持 `$currentNode.id` 等动态变量替换。
15
+
16
+ ## 目录结构
17
+
18
+ ```
19
+ src/
20
+ ├── components/
21
+ │ ├── TreeUpload.vue # 主组件(入口)
22
+ │ ├── SchemaTree.vue # 左侧树
23
+ │ ├── SchemaUpload.vue # 上传区
24
+ │ ├── SchemaTable.vue # 文件列表
25
+ │ ├── SchemaTemplate.vue # 模板下载
26
+ │ └── SchemaPreview.vue # 预览弹窗
27
+ ├── types/
28
+ │ └── index.ts # Schema 类型定义
29
+ ├── utils/
30
+ │ └── schema-helper.ts # 权限校验与变量替换工具
31
+ ├── App.vue # 示例应用
32
+ └── main.ts # 入口文件
33
+ ```
34
+
35
+ ## 快速开始
36
+
37
+ 1. 安装依赖: `npm install`
38
+ 2. 启动开发服务器: `npm run dev`
39
+
40
+ ## Schema 示例
41
+
42
+ 请参考 `src/App.vue` 中的完整示例配置。
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
2
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import { PreviewSchema, FileItem } from '../types';
2
+ type __VLS_Props = {
3
+ schema: PreviewSchema;
4
+ modelValue: boolean;
5
+ file: FileItem | null;
6
+ };
7
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
8
+ "update:modelValue": (...args: any[]) => void;
9
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
12
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import { TableSchema, FileItem } from '../types';
2
+ type __VLS_Props = {
3
+ schema: TableSchema;
4
+ files?: FileItem[];
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
7
+ action: (...args: any[]) => void;
8
+ refresh: (...args: any[]) => void;
9
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ onAction?: ((...args: any[]) => any) | undefined;
11
+ onRefresh?: ((...args: any[]) => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
13
+ export default _default;
@@ -0,0 +1,9 @@
1
+ interface TemplateItem {
2
+ name: string;
3
+ url: string;
4
+ }
5
+ type __VLS_Props = {
6
+ templates: TemplateItem[];
7
+ };
8
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
9
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { TreeSchema } from '../types';
2
+ type __VLS_Props = {
3
+ schema: TreeSchema;
4
+ };
5
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
6
+ "node-click": (...args: any[]) => void;
7
+ action: (...args: any[]) => void;
8
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ "onNode-click"?: ((...args: any[]) => any) | undefined;
10
+ onAction?: ((...args: any[]) => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
12
+ treeRef: unknown;
13
+ }, HTMLDivElement>;
14
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import { UploadSchema } from '../types';
2
+ type __VLS_Props = {
3
+ schema: UploadSchema;
4
+ disabled?: boolean;
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
7
+ "upload-success": (...args: any[]) => void;
8
+ "upload-error": (...args: any[]) => void;
9
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ "onUpload-success"?: ((...args: any[]) => any) | undefined;
11
+ "onUpload-error"?: ((...args: any[]) => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
13
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { TreeUploadSchema } from '../types';
2
+ type __VLS_Props = {
3
+ schema: TreeUploadSchema;
4
+ mode?: 'view' | 'edit';
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ mode: "view" | "edit";
8
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
9
+ nodeFormRef: unknown;
10
+ }, HTMLDivElement>;
11
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { default as TreeUpload } from './components/TreeUpload.vue';
2
+ import { TreeUploadSchema, CategoryNode, FileItem } from './types';
3
+ export { TreeUpload };
4
+ export type { TreeUploadSchema, CategoryNode, FileItem };
5
+ export default TreeUpload;
package/dist/main.d.ts ADDED
File without changes
@@ -0,0 +1 @@
1
+ .schema-tree[data-v-493d816e]{height:100%;position:relative;display:flex;flex-direction:column}.tree-toolbar[data-v-493d816e]{padding:8px;border-bottom:1px solid #f0f2f5;display:flex;gap:8px}.custom-tree-node[data-v-493d816e]{flex:1;display:flex;align-items:center;justify-content:space-between;font-size:14px;padding-right:8px}.custom-tree-node .actions[data-v-493d816e]{display:none}.custom-tree-node:hover .actions[data-v-493d816e]{display:inline-flex}.context-menu[data-v-493d816e]{position:fixed;z-index:1000;background:#fff;border:1px solid #dcdfe6;box-shadow:0 2px 12px #0000001a;border-radius:4px;padding:5px 0;min-width:120px}.context-menu-item[data-v-493d816e]{padding:8px 16px;cursor:pointer;display:flex;align-items:center;gap:8px;font-size:13px;color:#606266}.context-menu-item[data-v-493d816e]:hover{background-color:#f5f7fa;color:#409eff}.schema-upload[data-v-b2da1f5f]{width:100%}.schema-table[data-v-d92346a5]{height:100%;display:flex;flex-direction:column}.table-toolbar[data-v-d92346a5]{margin-bottom:12px}.pagination-wrapper[data-v-d92346a5]{margin-top:12px;display:flex;justify-content:flex-end}.schema-template[data-v-5468ee4e]{margin-bottom:12px;background-color:#f4f4f5;padding:8px 12px;border-radius:4px;border:1px solid #e9e9eb}.template-container[data-v-5468ee4e]{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.label[data-v-5468ee4e]{font-size:13px;color:#909399;white-space:nowrap}.tags-wrapper[data-v-5468ee4e]{display:flex;flex-wrap:wrap;gap:8px}.template-tag[data-v-5468ee4e]{cursor:pointer;border:none;background-color:#fff;transition:all .2s}.template-tag[data-v-5468ee4e]:hover{color:#409eff;transform:translateY(-1px);box-shadow:0 2px 4px #0000000d}.tag-content[data-v-5468ee4e]{display:flex;align-items:center;gap:4px}.tpl-name[data-v-5468ee4e]{line-height:1}.preview-content[data-v-caf5bb4b]{height:100%;min-height:500px;display:flex;flex-direction:column}.custom-header[data-v-caf5bb4b]{display:flex;justify-content:space-between;align-items:center;padding-right:0}.header-controls[data-v-caf5bb4b]{display:flex;align-items:center;gap:8px}.tree-upload-container[data-v-346b7c9b]{display:flex;height:100%;border:1px solid #dcdfe6;background:#fff}.tree-pane[data-v-346b7c9b]{border-right:1px solid #dcdfe6;height:100%;overflow-y:auto;padding:10px;box-sizing:border-box}.content-pane[data-v-346b7c9b]{flex:1;display:flex;flex-direction:column;padding:16px;overflow:hidden}.top-section[data-v-346b7c9b]{margin-bottom:16px}.table-section[data-v-346b7c9b]{flex:1;overflow:hidden}
@@ -0,0 +1,748 @@
1
+ import { defineComponent as j, ref as C, computed as D, onMounted as ae, onUnmounted as le, resolveComponent as h, createElementBlock as S, openBlock as a, createCommentVNode as w, createVNode as y, Fragment as E, renderList as K, createBlock as p, withCtx as d, createTextVNode as R, resolveDynamicComponent as O, toDisplayString as F, createElementVNode as $, withModifiers as ne, normalizeStyle as Q, inject as Z, createSlots as oe, watch as ee, resolveDirective as ie, withDirectives as se, unref as X, normalizeClass as ce, reactive as G, provide as re, nextTick as ue } from "vue";
2
+ import { ElMessage as H } from "element-plus";
3
+ import { Download as de, Close as me } from "@element-plus/icons-vue";
4
+ import J from "file-preview-vue3-ts";
5
+ const fe = { class: "schema-tree" }, pe = {
6
+ key: 0,
7
+ class: "tree-toolbar"
8
+ }, he = { class: "custom-tree-node" }, ve = {
9
+ key: 0,
10
+ class: "actions"
11
+ }, be = ["onClick"], ge = /* @__PURE__ */ j({
12
+ __name: "SchemaTree",
13
+ props: {
14
+ schema: {}
15
+ },
16
+ emits: ["node-click", "action"],
17
+ setup(e, { emit: r }) {
18
+ const t = e, v = r, b = C(), s = C(!1), k = C({ x: 0, y: 0 }), g = C(null), V = D(() => t.schema.dataSource.type === "static" ? t.schema.dataSource.data : []), N = {
19
+ label: t.schema.labelKey || "label",
20
+ children: t.schema.childrenKey || "children"
21
+ }, U = D(() => t.schema.actions?.filter((n) => n.position === "toolbar") || []), T = D(() => t.schema.actions?.filter((n) => n.position === "node") || []), A = D(() => t.schema.actions?.filter((n) => n.position === "contextMenu") || []), l = (n) => {
22
+ s.value = !1, v("node-click", n);
23
+ }, _ = (n, x) => {
24
+ A.value.length !== 0 && (n.preventDefault(), s.value = !0, k.value = { x: n.clientX, y: n.clientY }, g.value = x);
25
+ }, z = (n, x) => {
26
+ s.value = !1, !(n.confirm && !confirm(n.confirm.message || "Are you sure?")) && v("action", n.key, x);
27
+ }, c = () => {
28
+ s.value = !1;
29
+ };
30
+ return ae(() => {
31
+ document.addEventListener("click", c);
32
+ }), le(() => {
33
+ document.removeEventListener("click", c);
34
+ }), (n, x) => {
35
+ const B = h("el-icon"), L = h("el-button"), u = h("el-tooltip"), i = h("el-tree");
36
+ return a(), S("div", fe, [
37
+ U.value.length ? (a(), S("div", pe, [
38
+ (a(!0), S(E, null, K(U.value, (m) => (a(), p(L, {
39
+ key: m.key,
40
+ type: "primary",
41
+ link: "",
42
+ onClick: (o) => z(m, null)
43
+ }, {
44
+ default: d(() => [
45
+ m.icon ? (a(), p(B, { key: 0 }, {
46
+ default: d(() => [
47
+ (a(), p(O(m.icon)))
48
+ ]),
49
+ _: 2
50
+ }, 1024)) : w("", !0),
51
+ R(" " + F(m.label), 1)
52
+ ]),
53
+ _: 2
54
+ }, 1032, ["onClick"]))), 128))
55
+ ])) : w("", !0),
56
+ y(i, {
57
+ ref_key: "treeRef",
58
+ ref: b,
59
+ data: V.value,
60
+ "node-key": e.schema.nodeKey || "id",
61
+ props: N,
62
+ "default-expand-all": e.schema.ui?.defaultExpandAll,
63
+ "highlight-current": e.schema.ui?.highlightCurrent,
64
+ "expand-on-click-node": !1,
65
+ onNodeClick: l,
66
+ onNodeContextmenu: _
67
+ }, {
68
+ default: d(({ node: m, data: o }) => [
69
+ $("span", he, [
70
+ $("span", null, F(m.label), 1),
71
+ T.value.length ? (a(), S("span", ve, [
72
+ (a(!0), S(E, null, K(T.value, (f) => (a(), p(u, {
73
+ key: f.key,
74
+ content: f.label,
75
+ placement: "top",
76
+ "show-after": 200
77
+ }, {
78
+ default: d(() => [
79
+ y(L, {
80
+ link: "",
81
+ type: "primary",
82
+ onClick: ne((M) => z(f, o), ["stop"])
83
+ }, {
84
+ default: d(() => [
85
+ f.icon ? (a(), p(B, { key: 0 }, {
86
+ default: d(() => [
87
+ (a(), p(O(f.icon)))
88
+ ]),
89
+ _: 2
90
+ }, 1024)) : w("", !0)
91
+ ]),
92
+ _: 2
93
+ }, 1032, ["onClick"])
94
+ ]),
95
+ _: 2
96
+ }, 1032, ["content"]))), 128))
97
+ ])) : w("", !0)
98
+ ])
99
+ ]),
100
+ _: 1
101
+ }, 8, ["data", "node-key", "default-expand-all", "highlight-current"]),
102
+ s.value ? (a(), S("div", {
103
+ key: 1,
104
+ class: "context-menu",
105
+ style: Q({ left: k.value.x + "px", top: k.value.y + "px" })
106
+ }, [
107
+ (a(!0), S(E, null, K(A.value, (m) => (a(), S("div", {
108
+ key: m.key,
109
+ class: "context-menu-item",
110
+ onClick: (o) => z(m, g.value)
111
+ }, [
112
+ m.icon ? (a(), p(B, { key: 0 }, {
113
+ default: d(() => [
114
+ (a(), p(O(m.icon)))
115
+ ]),
116
+ _: 2
117
+ }, 1024)) : w("", !0),
118
+ R(" " + F(m.label), 1)
119
+ ], 8, be))), 128))
120
+ ], 4)) : w("", !0)
121
+ ]);
122
+ };
123
+ }
124
+ }), q = (e, r) => {
125
+ const t = e.__vccOpts || e;
126
+ for (const [v, b] of r)
127
+ t[v] = b;
128
+ return t;
129
+ }, _e = /* @__PURE__ */ q(ge, [["__scopeId", "data-v-493d816e"]]);
130
+ function Y(e, r, t) {
131
+ return r.permissions ? r.permissions.default?.[e] !== !1 : !0;
132
+ }
133
+ function te(e, r) {
134
+ if (!e) return e;
135
+ let t = e;
136
+ const v = r.variables || {};
137
+ return v.currentNode && (t = t.replace(/\$currentNode\.id/g, String(v.currentNode.id)), t = t.replace(/\$currentNode\.label/g, v.currentNode.label)), t;
138
+ }
139
+ const ye = {
140
+ key: 0,
141
+ class: "schema-upload"
142
+ }, ke = { class: "el-upload__text" }, xe = { class: "el-upload__tip" }, Se = /* @__PURE__ */ j({
143
+ __name: "SchemaUpload",
144
+ props: {
145
+ schema: {},
146
+ disabled: { type: Boolean }
147
+ },
148
+ emits: ["upload-success", "upload-error"],
149
+ setup(e, { emit: r }) {
150
+ const t = e, v = r, b = Z("schemaContext", {}), s = D(() => {
151
+ const l = b.variables?.currentNode?.meta?.upload || {};
152
+ return {
153
+ ...t.schema,
154
+ ...l,
155
+ // Override with node-level config
156
+ // Explicitly handle fields that might be in meta
157
+ limit: l.limit ?? t.schema.limit,
158
+ maxSize: l.maxSize,
159
+ // Custom field: bytes
160
+ minLimit: l.minLimit,
161
+ // Custom field
162
+ accept: l.accept ?? t.schema.accept,
163
+ multiple: l.multiple ?? t.schema.multiple,
164
+ drag: l.drag ?? t.schema.drag,
165
+ autoUpload: l.autoUpload ?? t.schema.autoUpload
166
+ };
167
+ }), k = D(() => t.schema.headers || {}), g = D(() => {
168
+ const l = t.schema.data || {}, _ = {};
169
+ for (const z in l) {
170
+ const c = l[z];
171
+ typeof c == "string" ? _[z] = te(c, b) : _[z] = c;
172
+ }
173
+ return _;
174
+ }), V = D(() => {
175
+ let l = t.schema.ui?.tipText || "";
176
+ const _ = [];
177
+ if (s.value.maxSize) {
178
+ const z = (s.value.maxSize / 1024 / 1024).toFixed(1);
179
+ _.push(`大小限制 ${z}MB`);
180
+ }
181
+ return s.value.limit && _.push(`数量限制 ${s.value.limit}个`), s.value.accept && _.push(`格式 ${s.value.accept}`), _.length ? `${l} (${_.join(", ")})` : l;
182
+ }), N = (l) => {
183
+ const _ = s.value.maxSize;
184
+ return _ && l.size > _ ? (H.error(`文件大小不能超过 ${(_ / 1024 / 1024).toFixed(1)}MB!`), !1) : !0;
185
+ }, U = () => {
186
+ H.warning(`当前限制选择 ${s.value.limit} 个文件`);
187
+ }, T = (l) => {
188
+ v("upload-success", l);
189
+ }, A = (l) => {
190
+ v("upload-error", l);
191
+ };
192
+ return (l, _) => {
193
+ const z = h("upload-filled"), c = h("el-icon"), n = h("el-button"), x = h("el-upload");
194
+ return e.schema.enabled ? (a(), S("div", ye, [
195
+ y(x, {
196
+ class: "upload-demo",
197
+ action: e.schema.action,
198
+ method: e.schema.method || "post",
199
+ headers: k.value,
200
+ data: g.value,
201
+ multiple: s.value.multiple,
202
+ drag: s.value.drag,
203
+ accept: s.value.accept,
204
+ limit: s.value.limit,
205
+ "auto-upload": s.value.autoUpload !== !1,
206
+ disabled: e.disabled,
207
+ "show-file-list": e.schema.ui?.showFileList,
208
+ "before-upload": N,
209
+ "on-exceed": U,
210
+ onSuccess: T,
211
+ onError: A
212
+ }, oe({
213
+ default: d(() => [
214
+ s.value.drag ? (a(), S(E, { key: 0 }, [
215
+ y(c, { class: "el-icon--upload" }, {
216
+ default: d(() => [
217
+ y(z)
218
+ ]),
219
+ _: 1
220
+ }),
221
+ $("div", ke, F(e.schema.ui?.buttonText || "Drop file here or click to upload"), 1)
222
+ ], 64)) : w("", !0)
223
+ ]),
224
+ _: 2
225
+ }, [
226
+ s.value.drag ? void 0 : {
227
+ name: "trigger",
228
+ fn: d(() => [
229
+ y(n, { type: "primary" }, {
230
+ default: d(() => [
231
+ R(F(e.schema.ui?.buttonText || "Click to upload"), 1)
232
+ ]),
233
+ _: 1
234
+ })
235
+ ]),
236
+ key: "0"
237
+ },
238
+ e.schema.ui?.showTip ? {
239
+ name: "tip",
240
+ fn: d(() => [
241
+ $("div", xe, F(V.value), 1)
242
+ ]),
243
+ key: "1"
244
+ } : void 0
245
+ ]), 1032, ["action", "method", "headers", "data", "multiple", "drag", "accept", "limit", "auto-upload", "disabled", "show-file-list"])
246
+ ])) : w("", !0);
247
+ };
248
+ }
249
+ }), we = /* @__PURE__ */ q(Se, [["__scopeId", "data-v-b2da1f5f"]]), Ce = { class: "schema-table" }, $e = {
250
+ key: 0,
251
+ class: "table-toolbar"
252
+ }, Ve = {
253
+ key: 1,
254
+ class: "pagination-wrapper"
255
+ }, ze = /* @__PURE__ */ j({
256
+ __name: "SchemaTable",
257
+ props: {
258
+ schema: {},
259
+ files: {}
260
+ },
261
+ emits: ["action", "refresh"],
262
+ setup(e, { emit: r }) {
263
+ const t = e, v = r, b = Z("schemaContext", {}), s = C(!1), k = C(1), g = C(t.schema.ui?.pagination?.pageSize || 20), V = C(0), N = C([]), U = D(() => t.files ? t.files : t.schema.dataSource.type === "static" ? t.schema.dataSource.data : N.value), T = (c, n) => {
264
+ if (!n) return c;
265
+ if (n === "fileSize") {
266
+ const x = Number(c);
267
+ return isNaN(x) ? c : x < 1024 ? x + " B" : x < 1024 * 1024 ? (x / 1024).toFixed(2) + " KB" : (x / 1024 / 1024).toFixed(2) + " MB";
268
+ }
269
+ return c;
270
+ }, A = (c, n) => {
271
+ c.confirm && !confirm(c.confirm.message || "Are you sure?") || v("action", c.key, n);
272
+ }, l = async () => {
273
+ if (t.schema.dataSource.type === "api") {
274
+ s.value = !0;
275
+ try {
276
+ const c = t.schema.dataSource, n = { ...c.params };
277
+ t.schema.ui?.pagination?.enabled && (n.page = k.value, n.pageSize = g.value);
278
+ for (const x in n)
279
+ typeof n[x] == "string" && (n[x] = te(n[x], b));
280
+ console.log("Fetching Table Data:", c.url, n), c.url;
281
+ } catch (c) {
282
+ console.error(c);
283
+ } finally {
284
+ s.value = !1;
285
+ }
286
+ }
287
+ }, _ = (c) => {
288
+ g.value = c, l();
289
+ }, z = (c) => {
290
+ k.value = c, l();
291
+ };
292
+ return ee(() => b.variables?.currentNode, (c) => {
293
+ c && t.schema.dataSource.type === "api" && l();
294
+ }, { deep: !0 }), (c, n) => {
295
+ const x = h("el-icon"), B = h("el-button"), L = h("el-table-column"), u = h("el-table"), i = h("el-pagination"), m = ie("loading");
296
+ return a(), S("div", Ce, [
297
+ e.schema.toolbarActions?.length ? (a(), S("div", $e, [
298
+ (a(!0), S(E, null, K(e.schema.toolbarActions, (o) => (a(), p(B, {
299
+ key: o.key,
300
+ type: o.type || "default",
301
+ onClick: (f) => A(o, null)
302
+ }, {
303
+ default: d(() => [
304
+ o.icon ? (a(), p(x, { key: 0 }, {
305
+ default: d(() => [
306
+ (a(), p(O(o.icon)))
307
+ ]),
308
+ _: 2
309
+ }, 1024)) : w("", !0),
310
+ R(" " + F(o.label), 1)
311
+ ]),
312
+ _: 2
313
+ }, 1032, ["type", "onClick"]))), 128))
314
+ ])) : w("", !0),
315
+ se((a(), p(u, {
316
+ data: U.value,
317
+ stripe: e.schema.ui?.stripe,
318
+ border: e.schema.ui?.border,
319
+ size: e.schema.ui?.size,
320
+ style: { width: "100%", height: "100%", flex: "1" }
321
+ }, {
322
+ default: d(() => [
323
+ (a(!0), S(E, null, K(e.schema.columns, (o) => (a(), p(L, {
324
+ key: o.prop,
325
+ prop: o.prop,
326
+ label: o.label,
327
+ width: o.width,
328
+ align: o.align,
329
+ fixed: o.fixed,
330
+ sortable: o.sortable
331
+ }, {
332
+ default: d((f) => [
333
+ R(F(T(f.row[o.prop], o.formatter)), 1)
334
+ ]),
335
+ _: 2
336
+ }, 1032, ["prop", "label", "width", "align", "fixed", "sortable"]))), 128)),
337
+ e.schema.actions?.length ? (a(), p(L, {
338
+ key: 0,
339
+ label: "操作",
340
+ fixed: "right",
341
+ width: "200"
342
+ }, {
343
+ default: d((o) => [
344
+ (a(!0), S(E, null, K(e.schema.actions, (f) => (a(), p(B, {
345
+ key: f.key,
346
+ type: f.type || "primary",
347
+ link: "",
348
+ onClick: (M) => A(f, o.row)
349
+ }, {
350
+ default: d(() => [
351
+ R(F(f.label), 1)
352
+ ]),
353
+ _: 2
354
+ }, 1032, ["type", "onClick"]))), 128))
355
+ ]),
356
+ _: 1
357
+ })) : w("", !0)
358
+ ]),
359
+ _: 1
360
+ }, 8, ["data", "stripe", "border", "size"])), [
361
+ [m, s.value]
362
+ ]),
363
+ e.schema.ui?.pagination?.enabled ? (a(), S("div", Ve, [
364
+ y(i, {
365
+ "current-page": k.value,
366
+ "onUpdate:currentPage": n[0] || (n[0] = (o) => k.value = o),
367
+ "page-size": g.value,
368
+ "onUpdate:pageSize": n[1] || (n[1] = (o) => g.value = o),
369
+ "page-sizes": [10, 20, 50, 100],
370
+ layout: e.schema.ui?.pagination?.layout || "total, sizes, prev, pager, next, jumper",
371
+ total: V.value,
372
+ onSizeChange: _,
373
+ onCurrentChange: z
374
+ }, null, 8, ["current-page", "page-size", "layout", "total"])
375
+ ])) : w("", !0)
376
+ ]);
377
+ };
378
+ }
379
+ }), Te = /* @__PURE__ */ q(ze, [["__scopeId", "data-v-d92346a5"]]), De = { class: "schema-template" }, Ne = { class: "template-container" }, Ue = { class: "tags-wrapper" }, Ae = { class: "tag-content" }, Fe = { class: "tpl-name" }, Me = /* @__PURE__ */ j({
380
+ __name: "SchemaTemplate",
381
+ props: {
382
+ templates: {}
383
+ },
384
+ setup(e) {
385
+ const r = (t) => {
386
+ window.open(t.url, "_blank");
387
+ };
388
+ return (t, v) => {
389
+ const b = h("el-icon"), s = h("el-tag");
390
+ return a(), S("div", De, [
391
+ $("div", Ne, [
392
+ v[0] || (v[0] = $("span", { class: "label" }, "可用模板:", -1)),
393
+ $("div", Ue, [
394
+ (a(!0), S(E, null, K(e.templates, (k, g) => (a(), p(s, {
395
+ key: g,
396
+ class: "template-tag",
397
+ type: "primary",
398
+ effect: "light",
399
+ onClick: (V) => r(k)
400
+ }, {
401
+ default: d(() => [
402
+ $("span", Ae, [
403
+ y(b, null, {
404
+ default: d(() => [
405
+ y(X(de))
406
+ ]),
407
+ _: 1
408
+ }),
409
+ $("span", Fe, F(k.name), 1)
410
+ ])
411
+ ]),
412
+ _: 2
413
+ }, 1032, ["onClick"]))), 128))
414
+ ])
415
+ ])
416
+ ]);
417
+ };
418
+ }
419
+ }), Pe = /* @__PURE__ */ q(Me, [["__scopeId", "data-v-5468ee4e"]]), Ie = {
420
+ key: 0,
421
+ class: "schema-preview-container"
422
+ }, Be = { class: "custom-header" }, Ee = ["id"], Re = { class: "header-controls" }, Le = { class: "preview-content" }, Ke = { class: "preview-content" }, je = /* @__PURE__ */ j({
423
+ __name: "SchemaPreview",
424
+ props: {
425
+ schema: {},
426
+ modelValue: { type: Boolean },
427
+ file: {}
428
+ },
429
+ emits: ["update:modelValue"],
430
+ setup(e, { emit: r }) {
431
+ const t = e, v = r, b = C(!1), s = D({
432
+ get: () => t.modelValue,
433
+ set: (g) => {
434
+ v("update:modelValue", g), g || setTimeout(() => {
435
+ b.value = !1;
436
+ }, 300);
437
+ }
438
+ }), k = () => {
439
+ b.value = !b.value;
440
+ };
441
+ return ee(() => t.schema.fullscreen, (g) => {
442
+ g !== void 0 && (b.value = g);
443
+ }, { immediate: !0 }), (g, V) => {
444
+ const N = h("el-icon"), U = h("el-button"), T = h("el-dialog"), A = h("el-drawer");
445
+ return s.value ? (a(), S("div", Ie, [
446
+ e.schema.mode === "dialog" ? (a(), p(T, {
447
+ key: 0,
448
+ modelValue: s.value,
449
+ "onUpdate:modelValue": V[0] || (V[0] = (l) => s.value = l),
450
+ width: e.schema.width,
451
+ fullscreen: b.value || e.schema.fullscreen,
452
+ draggable: "",
453
+ "destroy-on-close": "",
454
+ "append-to-body": "",
455
+ class: "preview-dialog",
456
+ "show-close": !1
457
+ }, {
458
+ header: d(({ close: l, titleId: _, titleClass: z }) => [
459
+ $("div", Be, [
460
+ $("span", {
461
+ id: _,
462
+ class: ce(z)
463
+ }, F(e.schema.dialogTitle || "预览"), 11, Ee),
464
+ $("div", Re, [
465
+ y(U, {
466
+ link: "",
467
+ onClick: k
468
+ }, {
469
+ default: d(() => [
470
+ y(N, null, {
471
+ default: d(() => [
472
+ (a(), p(O(b.value ? "CopyDocument" : "FullScreen")))
473
+ ]),
474
+ _: 1
475
+ })
476
+ ]),
477
+ _: 1
478
+ }),
479
+ y(U, {
480
+ link: "",
481
+ onClick: l
482
+ }, {
483
+ default: d(() => [
484
+ y(N, null, {
485
+ default: d(() => [
486
+ y(X(me))
487
+ ]),
488
+ _: 1
489
+ })
490
+ ]),
491
+ _: 1
492
+ }, 8, ["onClick"])
493
+ ])
494
+ ])
495
+ ]),
496
+ default: d(() => [
497
+ $("div", Le, [
498
+ e.file ? (a(), p(X(J), {
499
+ key: 0,
500
+ url: e.file.url,
501
+ type: e.file.type,
502
+ name: e.file.name
503
+ }, null, 8, ["url", "type", "name"])) : w("", !0)
504
+ ])
505
+ ]),
506
+ _: 1
507
+ }, 8, ["modelValue", "width", "fullscreen"])) : (a(), p(A, {
508
+ key: 1,
509
+ modelValue: s.value,
510
+ "onUpdate:modelValue": V[1] || (V[1] = (l) => s.value = l),
511
+ title: e.schema.dialogTitle || "预览",
512
+ size: e.schema.width,
513
+ "destroy-on-close": "",
514
+ "append-to-body": ""
515
+ }, {
516
+ default: d(() => [
517
+ $("div", Ke, [
518
+ e.file ? (a(), p(X(J), {
519
+ key: 0,
520
+ url: e.file.url,
521
+ type: e.file.type,
522
+ name: e.file.name
523
+ }, null, 8, ["url", "type", "name"])) : w("", !0)
524
+ ])
525
+ ]),
526
+ _: 1
527
+ }, 8, ["modelValue", "title", "size"]))
528
+ ])) : w("", !0);
529
+ };
530
+ }
531
+ }), qe = /* @__PURE__ */ q(je, [["__scopeId", "data-v-caf5bb4b"]]), Oe = { class: "tree-upload-container" }, We = { class: "content-pane" }, Xe = {
532
+ key: 0,
533
+ class: "top-section"
534
+ }, Ye = { class: "table-section" }, Ge = { class: "dialog-footer" }, He = /* @__PURE__ */ j({
535
+ __name: "TreeUpload",
536
+ props: {
537
+ schema: {},
538
+ mode: { default: "edit" }
539
+ },
540
+ setup(e) {
541
+ const r = e, t = C(null), v = C([]), b = C(!1), s = C(null), k = C(!1), g = C("addRoot"), V = G({ label: "" }), N = C(), U = C(null), T = G({
542
+ variables: {
543
+ ...r.schema.context?.variables,
544
+ currentNode: void 0,
545
+ currentFile: void 0
546
+ }
547
+ });
548
+ re("schemaContext", T);
549
+ const A = D(() => {
550
+ const u = r.schema.tree.ui?.width;
551
+ return typeof u == "number" ? `${u}px` : u || "260px";
552
+ }), l = D(() => t.value?.meta?.templates || []), _ = D(() => t.value ? Y("upload", r.schema) : !1), z = D(() => {
553
+ switch (g.value) {
554
+ case "addRoot":
555
+ return "添加根节点";
556
+ case "addChild":
557
+ return "添加子节点";
558
+ case "addSibling":
559
+ return "添加本级节点";
560
+ case "edit":
561
+ return "编辑节点";
562
+ default:
563
+ return "节点操作";
564
+ }
565
+ }), c = (u) => {
566
+ if (console.log("Node Selected:", u), t.value = u, T.variables && (T.variables.currentNode = u), r.schema.table.dataSource.type === "static") {
567
+ const i = r.schema.table.dataSource.data;
568
+ v.value = i.filter((m) => m.meta?.nodeId === String(u.id));
569
+ }
570
+ }, n = (u, i) => {
571
+ if (console.log("Tree Action:", u, i), !Y(u, r.schema)) {
572
+ alert("Permission Denied");
573
+ return;
574
+ }
575
+ if (r.schema.tree.dataSource.type !== "static") {
576
+ alert(`Action ${u} triggered (API implementation required)`);
577
+ return;
578
+ }
579
+ if (u === "delete") {
580
+ if (!i || !confirm(`确定删除节点 "${i.label}" 吗?`)) return;
581
+ const m = r.schema.tree.dataSource.data, o = (f) => {
582
+ const M = f.findIndex((P) => P.id === i.id);
583
+ if (M > -1)
584
+ return f.splice(M, 1), !0;
585
+ for (const P of f)
586
+ if (P.children && o(P.children)) return !0;
587
+ return !1;
588
+ };
589
+ o(m) && t.value?.id === i.id && (t.value = null);
590
+ return;
591
+ }
592
+ (u === "addRoot" || u === "addChild" || u === "addSibling" || u === "edit") && (g.value = u, U.value = i, V.label = u === "edit" && i ? i.label : "", k.value = !0, ue(() => {
593
+ N.value?.clearValidate();
594
+ }));
595
+ }, x = () => {
596
+ N.value?.validate((u) => {
597
+ if (!u || r.schema.tree.dataSource.type !== "static")
598
+ return;
599
+ const i = r.schema.tree.dataSource.data, m = V.label, o = g.value, f = U.value;
600
+ if (o === "addRoot")
601
+ i.push({ id: String(Date.now()), label: m, children: [] });
602
+ else if (o === "addChild")
603
+ f && (f.children || (f.children = []), f.children.push({ id: String(Date.now()), label: m, children: [] }));
604
+ else if (o === "addSibling") {
605
+ if (f) {
606
+ const M = (P) => {
607
+ const I = P.findIndex((W) => W.id === f.id);
608
+ if (I > -1)
609
+ return P.splice(I + 1, 0, { id: String(Date.now()), label: m, children: [] }), !0;
610
+ for (const W of P)
611
+ if (W.children && M(W.children)) return !0;
612
+ return !1;
613
+ };
614
+ M(i);
615
+ }
616
+ } else o === "edit" && f && (f.label = m);
617
+ k.value = !1;
618
+ });
619
+ }, B = (u) => {
620
+ if (console.log("Upload Success:", u), r.schema.table.dataSource.type === "static" && t.value) {
621
+ const i = {
622
+ id: Date.now(),
623
+ name: "Uploaded File.png",
624
+ size: 1024,
625
+ url: "#",
626
+ type: "png",
627
+ meta: { nodeId: String(t.value.id) }
628
+ };
629
+ r.schema.table.dataSource.data.push(i), c(t.value);
630
+ }
631
+ }, L = (u, i) => {
632
+ if (console.log("Table Action:", u, i), T.variables && (T.variables.currentFile = i), !Y(u, r.schema)) {
633
+ alert("Permission Denied");
634
+ return;
635
+ }
636
+ if (u === "preview")
637
+ s.value = i, b.value = !0;
638
+ else if (u === "delete" && r.schema.table.dataSource.type === "static") {
639
+ const m = r.schema.table.dataSource.data.findIndex((o) => o.id === i.id);
640
+ m > -1 && (r.schema.table.dataSource.data.splice(m, 1), t.value && c(t.value));
641
+ }
642
+ };
643
+ return (u, i) => {
644
+ const m = h("el-input"), o = h("el-form-item"), f = h("el-form"), M = h("el-button"), P = h("el-dialog");
645
+ return a(), S("div", Oe, [
646
+ $("div", {
647
+ class: "tree-pane",
648
+ style: Q({ width: A.value })
649
+ }, [
650
+ y(_e, {
651
+ schema: e.schema.tree,
652
+ onNodeClick: c,
653
+ onAction: n
654
+ }, null, 8, ["schema"])
655
+ ], 4),
656
+ $("div", We, [
657
+ e.mode === "edit" ? (a(), S("div", Xe, [
658
+ l.value && l.value.length > 0 ? (a(), p(Pe, {
659
+ key: 0,
660
+ templates: l.value
661
+ }, null, 8, ["templates"])) : w("", !0),
662
+ e.schema.upload ? (a(), p(we, {
663
+ key: 1,
664
+ schema: e.schema.upload,
665
+ disabled: !_.value,
666
+ onUploadSuccess: B
667
+ }, null, 8, ["schema", "disabled"])) : w("", !0)
668
+ ])) : w("", !0),
669
+ $("div", Ye, [
670
+ y(Te, {
671
+ schema: e.schema.table,
672
+ files: v.value,
673
+ onAction: L
674
+ }, null, 8, ["schema", "files"])
675
+ ])
676
+ ]),
677
+ e.schema.preview ? (a(), p(qe, {
678
+ key: 0,
679
+ modelValue: b.value,
680
+ "onUpdate:modelValue": i[0] || (i[0] = (I) => b.value = I),
681
+ schema: e.schema.preview,
682
+ file: s.value
683
+ }, null, 8, ["modelValue", "schema", "file"])) : w("", !0),
684
+ y(P, {
685
+ modelValue: k.value,
686
+ "onUpdate:modelValue": i[3] || (i[3] = (I) => k.value = I),
687
+ title: z.value,
688
+ width: "400px",
689
+ "append-to-body": "",
690
+ "destroy-on-close": ""
691
+ }, {
692
+ footer: d(() => [
693
+ $("span", Ge, [
694
+ y(M, {
695
+ onClick: i[2] || (i[2] = (I) => k.value = !1)
696
+ }, {
697
+ default: d(() => [...i[4] || (i[4] = [
698
+ R("取消", -1)
699
+ ])]),
700
+ _: 1
701
+ }),
702
+ y(M, {
703
+ type: "primary",
704
+ onClick: x
705
+ }, {
706
+ default: d(() => [...i[5] || (i[5] = [
707
+ R("确定", -1)
708
+ ])]),
709
+ _: 1
710
+ })
711
+ ])
712
+ ]),
713
+ default: d(() => [
714
+ y(f, {
715
+ model: V,
716
+ ref_key: "nodeFormRef",
717
+ ref: N,
718
+ "label-width": "80px"
719
+ }, {
720
+ default: d(() => [
721
+ y(o, {
722
+ label: "节点名称",
723
+ prop: "label",
724
+ rules: [{ required: !0, message: "请输入节点名称", trigger: "blur" }]
725
+ }, {
726
+ default: d(() => [
727
+ y(m, {
728
+ modelValue: V.label,
729
+ "onUpdate:modelValue": i[1] || (i[1] = (I) => V.label = I),
730
+ placeholder: "请输入节点名称"
731
+ }, null, 8, ["modelValue"])
732
+ ]),
733
+ _: 1
734
+ })
735
+ ]),
736
+ _: 1
737
+ }, 8, ["model"])
738
+ ]),
739
+ _: 1
740
+ }, 8, ["modelValue", "title"])
741
+ ]);
742
+ };
743
+ }
744
+ }), tt = /* @__PURE__ */ q(He, [["__scopeId", "data-v-346b7c9b"]]);
745
+ export {
746
+ tt as TreeUpload,
747
+ tt as default
748
+ };
@@ -0,0 +1 @@
1
+ (function(V,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("element-plus"),require("@element-plus/icons-vue"),require("file-preview-vue3-ts")):typeof define=="function"&&define.amd?define(["exports","vue","element-plus","@element-plus/icons-vue","file-preview-vue3-ts"],e):(V=typeof globalThis<"u"?globalThis:V||self,e(V.TreeUploadVue3={},V.Vue,V.ElementPlus,V.ElementPlusIconsVue,V.FilePreviewVue3Ts))})(this,(function(V,e,U,A,M){"use strict";const L={class:"schema-tree"},R={key:0,class:"tree-toolbar"},j={class:"custom-tree-node"},q={key:0,class:"actions"},K=["onClick"],O=e.defineComponent({__name:"SchemaTree",props:{schema:{}},emits:["node-click","action"],setup(t,{emit:s}){const o=t,f=s,h=e.ref(),r=e.ref(!1),g=e.ref({x:0,y:0}),u=e.ref(null),C=e.computed(()=>o.schema.dataSource.type==="static"?o.schema.dataSource.data:[]),x={label:o.schema.labelKey||"label",children:o.schema.childrenKey||"children"},B=e.computed(()=>o.schema.actions?.filter(n=>n.position==="toolbar")||[]),b=e.computed(()=>o.schema.actions?.filter(n=>n.position==="node")||[]),N=e.computed(()=>o.schema.actions?.filter(n=>n.position==="contextMenu")||[]),l=n=>{r.value=!1,f("node-click",n)},k=(n,y)=>{N.value.length!==0&&(n.preventDefault(),r.value=!0,g.value={x:n.clientX,y:n.clientY},u.value=y)},_=(n,y)=>{r.value=!1,!(n.confirm&&!confirm(n.confirm.message||"Are you sure?"))&&f("action",n.key,y)},i=()=>{r.value=!1};return e.onMounted(()=>{document.addEventListener("click",i)}),e.onUnmounted(()=>{document.removeEventListener("click",i)}),(n,y)=>{const $=e.resolveComponent("el-icon"),D=e.resolveComponent("el-button"),d=e.resolveComponent("el-tooltip"),c=e.resolveComponent("el-tree");return e.openBlock(),e.createElementBlock("div",L,[B.value.length?(e.openBlock(),e.createElementBlock("div",R,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(B.value,m=>(e.openBlock(),e.createBlock(D,{key:m.key,type:"primary",link:"",onClick:a=>_(m,null)},{default:e.withCtx(()=>[m.icon?(e.openBlock(),e.createBlock($,{key:0},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(m.icon)))]),_:2},1024)):e.createCommentVNode("",!0),e.createTextVNode(" "+e.toDisplayString(m.label),1)]),_:2},1032,["onClick"]))),128))])):e.createCommentVNode("",!0),e.createVNode(c,{ref_key:"treeRef",ref:h,data:C.value,"node-key":t.schema.nodeKey||"id",props:x,"default-expand-all":t.schema.ui?.defaultExpandAll,"highlight-current":t.schema.ui?.highlightCurrent,"expand-on-click-node":!1,onNodeClick:l,onNodeContextmenu:k},{default:e.withCtx(({node:m,data:a})=>[e.createElementVNode("span",j,[e.createElementVNode("span",null,e.toDisplayString(m.label),1),b.value.length?(e.openBlock(),e.createElementBlock("span",q,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(b.value,p=>(e.openBlock(),e.createBlock(d,{key:p.key,content:p.label,placement:"top","show-after":200},{default:e.withCtx(()=>[e.createVNode(D,{link:"",type:"primary",onClick:e.withModifiers(w=>_(p,a),["stop"])},{default:e.withCtx(()=>[p.icon?(e.openBlock(),e.createBlock($,{key:0},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(p.icon)))]),_:2},1024)):e.createCommentVNode("",!0)]),_:2},1032,["onClick"])]),_:2},1032,["content"]))),128))])):e.createCommentVNode("",!0)])]),_:1},8,["data","node-key","default-expand-all","highlight-current"]),r.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"context-menu",style:e.normalizeStyle({left:g.value.x+"px",top:g.value.y+"px"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(N.value,m=>(e.openBlock(),e.createElementBlock("div",{key:m.key,class:"context-menu-item",onClick:a=>_(m,u.value)},[m.icon?(e.openBlock(),e.createBlock($,{key:0},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(m.icon)))]),_:2},1024)):e.createCommentVNode("",!0),e.createTextVNode(" "+e.toDisplayString(m.label),1)],8,K))),128))],4)):e.createCommentVNode("",!0)])}}}),T=(t,s)=>{const o=t.__vccOpts||t;for(const[f,h]of s)o[f]=h;return o},W=T(O,[["__scopeId","data-v-493d816e"]]);function F(t,s,o){return s.permissions?s.permissions.default?.[t]!==!1:!0}function P(t,s){if(!t)return t;let o=t;const f=s.variables||{};return f.currentNode&&(o=o.replace(/\$currentNode\.id/g,String(f.currentNode.id)),o=o.replace(/\$currentNode\.label/g,f.currentNode.label)),o}const X={key:0,class:"schema-upload"},Y={class:"el-upload__text"},G={class:"el-upload__tip"},H=T(e.defineComponent({__name:"SchemaUpload",props:{schema:{},disabled:{type:Boolean}},emits:["upload-success","upload-error"],setup(t,{emit:s}){const o=t,f=s,h=e.inject("schemaContext",{}),r=e.computed(()=>{const l=h.variables?.currentNode?.meta?.upload||{};return{...o.schema,...l,limit:l.limit??o.schema.limit,maxSize:l.maxSize,minLimit:l.minLimit,accept:l.accept??o.schema.accept,multiple:l.multiple??o.schema.multiple,drag:l.drag??o.schema.drag,autoUpload:l.autoUpload??o.schema.autoUpload}}),g=e.computed(()=>o.schema.headers||{}),u=e.computed(()=>{const l=o.schema.data||{},k={};for(const _ in l){const i=l[_];typeof i=="string"?k[_]=P(i,h):k[_]=i}return k}),C=e.computed(()=>{let l=o.schema.ui?.tipText||"";const k=[];if(r.value.maxSize){const _=(r.value.maxSize/1024/1024).toFixed(1);k.push(`大小限制 ${_}MB`)}return r.value.limit&&k.push(`数量限制 ${r.value.limit}个`),r.value.accept&&k.push(`格式 ${r.value.accept}`),k.length?`${l} (${k.join(", ")})`:l}),x=l=>{const k=r.value.maxSize;return k&&l.size>k?(U.ElMessage.error(`文件大小不能超过 ${(k/1024/1024).toFixed(1)}MB!`),!1):!0},B=()=>{U.ElMessage.warning(`当前限制选择 ${r.value.limit} 个文件`)},b=l=>{f("upload-success",l)},N=l=>{f("upload-error",l)};return(l,k)=>{const _=e.resolveComponent("upload-filled"),i=e.resolveComponent("el-icon"),n=e.resolveComponent("el-button"),y=e.resolveComponent("el-upload");return t.schema.enabled?(e.openBlock(),e.createElementBlock("div",X,[e.createVNode(y,{class:"upload-demo",action:t.schema.action,method:t.schema.method||"post",headers:g.value,data:u.value,multiple:r.value.multiple,drag:r.value.drag,accept:r.value.accept,limit:r.value.limit,"auto-upload":r.value.autoUpload!==!1,disabled:t.disabled,"show-file-list":t.schema.ui?.showFileList,"before-upload":x,"on-exceed":B,onSuccess:b,onError:N},e.createSlots({default:e.withCtx(()=>[r.value.drag?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createVNode(i,{class:"el-icon--upload"},{default:e.withCtx(()=>[e.createVNode(_)]),_:1}),e.createElementVNode("div",Y,e.toDisplayString(t.schema.ui?.buttonText||"Drop file here or click to upload"),1)],64)):e.createCommentVNode("",!0)]),_:2},[r.value.drag?void 0:{name:"trigger",fn:e.withCtx(()=>[e.createVNode(n,{type:"primary"},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(t.schema.ui?.buttonText||"Click to upload"),1)]),_:1})]),key:"0"},t.schema.ui?.showTip?{name:"tip",fn:e.withCtx(()=>[e.createElementVNode("div",G,e.toDisplayString(C.value),1)]),key:"1"}:void 0]),1032,["action","method","headers","data","multiple","drag","accept","limit","auto-upload","disabled","show-file-list"])])):e.createCommentVNode("",!0)}}}),[["__scopeId","data-v-b2da1f5f"]]),J={class:"schema-table"},Q={key:0,class:"table-toolbar"},Z={key:1,class:"pagination-wrapper"},v=T(e.defineComponent({__name:"SchemaTable",props:{schema:{},files:{}},emits:["action","refresh"],setup(t,{emit:s}){const o=t,f=s,h=e.inject("schemaContext",{}),r=e.ref(!1),g=e.ref(1),u=e.ref(o.schema.ui?.pagination?.pageSize||20),C=e.ref(0),x=e.ref([]),B=e.computed(()=>o.files?o.files:o.schema.dataSource.type==="static"?o.schema.dataSource.data:x.value),b=(i,n)=>{if(!n)return i;if(n==="fileSize"){const y=Number(i);return isNaN(y)?i:y<1024?y+" B":y<1024*1024?(y/1024).toFixed(2)+" KB":(y/1024/1024).toFixed(2)+" MB"}return i},N=(i,n)=>{i.confirm&&!confirm(i.confirm.message||"Are you sure?")||f("action",i.key,n)},l=async()=>{if(o.schema.dataSource.type==="api"){r.value=!0;try{const i=o.schema.dataSource,n={...i.params};o.schema.ui?.pagination?.enabled&&(n.page=g.value,n.pageSize=u.value);for(const y in n)typeof n[y]=="string"&&(n[y]=P(n[y],h));console.log("Fetching Table Data:",i.url,n),i.url}catch(i){console.error(i)}finally{r.value=!1}}},k=i=>{u.value=i,l()},_=i=>{g.value=i,l()};return e.watch(()=>h.variables?.currentNode,i=>{i&&o.schema.dataSource.type==="api"&&l()},{deep:!0}),(i,n)=>{const y=e.resolveComponent("el-icon"),$=e.resolveComponent("el-button"),D=e.resolveComponent("el-table-column"),d=e.resolveComponent("el-table"),c=e.resolveComponent("el-pagination"),m=e.resolveDirective("loading");return e.openBlock(),e.createElementBlock("div",J,[t.schema.toolbarActions?.length?(e.openBlock(),e.createElementBlock("div",Q,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.schema.toolbarActions,a=>(e.openBlock(),e.createBlock($,{key:a.key,type:a.type||"default",onClick:p=>N(a,null)},{default:e.withCtx(()=>[a.icon?(e.openBlock(),e.createBlock(y,{key:0},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(a.icon)))]),_:2},1024)):e.createCommentVNode("",!0),e.createTextVNode(" "+e.toDisplayString(a.label),1)]),_:2},1032,["type","onClick"]))),128))])):e.createCommentVNode("",!0),e.withDirectives((e.openBlock(),e.createBlock(d,{data:B.value,stripe:t.schema.ui?.stripe,border:t.schema.ui?.border,size:t.schema.ui?.size,style:{width:"100%",height:"100%",flex:"1"}},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.schema.columns,a=>(e.openBlock(),e.createBlock(D,{key:a.prop,prop:a.prop,label:a.label,width:a.width,align:a.align,fixed:a.fixed,sortable:a.sortable},{default:e.withCtx(p=>[e.createTextVNode(e.toDisplayString(b(p.row[a.prop],a.formatter)),1)]),_:2},1032,["prop","label","width","align","fixed","sortable"]))),128)),t.schema.actions?.length?(e.openBlock(),e.createBlock(D,{key:0,label:"操作",fixed:"right",width:"200"},{default:e.withCtx(a=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.schema.actions,p=>(e.openBlock(),e.createBlock($,{key:p.key,type:p.type||"primary",link:"",onClick:w=>N(p,a.row)},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(p.label),1)]),_:2},1032,["type","onClick"]))),128))]),_:1})):e.createCommentVNode("",!0)]),_:1},8,["data","stripe","border","size"])),[[m,r.value]]),t.schema.ui?.pagination?.enabled?(e.openBlock(),e.createElementBlock("div",Z,[e.createVNode(c,{"current-page":g.value,"onUpdate:currentPage":n[0]||(n[0]=a=>g.value=a),"page-size":u.value,"onUpdate:pageSize":n[1]||(n[1]=a=>u.value=a),"page-sizes":[10,20,50,100],layout:t.schema.ui?.pagination?.layout||"total, sizes, prev, pager, next, jumper",total:C.value,onSizeChange:k,onCurrentChange:_},null,8,["current-page","page-size","layout","total"])])):e.createCommentVNode("",!0)])}}}),[["__scopeId","data-v-d92346a5"]]),ee={class:"schema-template"},te={class:"template-container"},oe={class:"tags-wrapper"},le={class:"tag-content"},ne={class:"tpl-name"},ae=T(e.defineComponent({__name:"SchemaTemplate",props:{templates:{}},setup(t){const s=o=>{window.open(o.url,"_blank")};return(o,f)=>{const h=e.resolveComponent("el-icon"),r=e.resolveComponent("el-tag");return e.openBlock(),e.createElementBlock("div",ee,[e.createElementVNode("div",te,[f[0]||(f[0]=e.createElementVNode("span",{class:"label"},"可用模板:",-1)),e.createElementVNode("div",oe,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.templates,(g,u)=>(e.openBlock(),e.createBlock(r,{key:u,class:"template-tag",type:"primary",effect:"light",onClick:C=>s(g)},{default:e.withCtx(()=>[e.createElementVNode("span",le,[e.createVNode(h,null,{default:e.withCtx(()=>[e.createVNode(e.unref(A.Download))]),_:1}),e.createElementVNode("span",ne,e.toDisplayString(g.name),1)])]),_:2},1032,["onClick"]))),128))])])])}}}),[["__scopeId","data-v-5468ee4e"]]),ce={key:0,class:"schema-preview-container"},re={class:"custom-header"},ie=["id"],se={class:"header-controls"},de={class:"preview-content"},me={class:"preview-content"},pe=T(e.defineComponent({__name:"SchemaPreview",props:{schema:{},modelValue:{type:Boolean},file:{}},emits:["update:modelValue"],setup(t,{emit:s}){const o=t,f=s,h=e.ref(!1),r=e.computed({get:()=>o.modelValue,set:u=>{f("update:modelValue",u),u||setTimeout(()=>{h.value=!1},300)}}),g=()=>{h.value=!h.value};return e.watch(()=>o.schema.fullscreen,u=>{u!==void 0&&(h.value=u)},{immediate:!0}),(u,C)=>{const x=e.resolveComponent("el-icon"),B=e.resolveComponent("el-button"),b=e.resolveComponent("el-dialog"),N=e.resolveComponent("el-drawer");return r.value?(e.openBlock(),e.createElementBlock("div",ce,[t.schema.mode==="dialog"?(e.openBlock(),e.createBlock(b,{key:0,modelValue:r.value,"onUpdate:modelValue":C[0]||(C[0]=l=>r.value=l),width:t.schema.width,fullscreen:h.value||t.schema.fullscreen,draggable:"","destroy-on-close":"","append-to-body":"",class:"preview-dialog","show-close":!1},{header:e.withCtx(({close:l,titleId:k,titleClass:_})=>[e.createElementVNode("div",re,[e.createElementVNode("span",{id:k,class:e.normalizeClass(_)},e.toDisplayString(t.schema.dialogTitle||"预览"),11,ie),e.createElementVNode("div",se,[e.createVNode(B,{link:"",onClick:g},{default:e.withCtx(()=>[e.createVNode(x,null,{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(h.value?"CopyDocument":"FullScreen")))]),_:1})]),_:1}),e.createVNode(B,{link:"",onClick:l},{default:e.withCtx(()=>[e.createVNode(x,null,{default:e.withCtx(()=>[e.createVNode(e.unref(A.Close))]),_:1})]),_:1},8,["onClick"])])])]),default:e.withCtx(()=>[e.createElementVNode("div",de,[t.file?(e.openBlock(),e.createBlock(e.unref(M),{key:0,url:t.file.url,type:t.file.type,name:t.file.name},null,8,["url","type","name"])):e.createCommentVNode("",!0)])]),_:1},8,["modelValue","width","fullscreen"])):(e.openBlock(),e.createBlock(N,{key:1,modelValue:r.value,"onUpdate:modelValue":C[1]||(C[1]=l=>r.value=l),title:t.schema.dialogTitle||"预览",size:t.schema.width,"destroy-on-close":"","append-to-body":""},{default:e.withCtx(()=>[e.createElementVNode("div",me,[t.file?(e.openBlock(),e.createBlock(e.unref(M),{key:0,url:t.file.url,type:t.file.type,name:t.file.name},null,8,["url","type","name"])):e.createCommentVNode("",!0)])]),_:1},8,["modelValue","title","size"]))])):e.createCommentVNode("",!0)}}}),[["__scopeId","data-v-caf5bb4b"]]),fe={class:"tree-upload-container"},he={class:"content-pane"},ue={key:0,class:"top-section"},ke={class:"table-section"},ge={class:"dialog-footer"},I=T(e.defineComponent({__name:"TreeUpload",props:{schema:{},mode:{default:"edit"}},setup(t){const s=t,o=e.ref(null),f=e.ref([]),h=e.ref(!1),r=e.ref(null),g=e.ref(!1),u=e.ref("addRoot"),C=e.reactive({label:""}),x=e.ref(),B=e.ref(null),b=e.reactive({variables:{...s.schema.context?.variables,currentNode:void 0,currentFile:void 0}});e.provide("schemaContext",b);const N=e.computed(()=>{const d=s.schema.tree.ui?.width;return typeof d=="number"?`${d}px`:d||"260px"}),l=e.computed(()=>o.value?.meta?.templates||[]),k=e.computed(()=>o.value?F("upload",s.schema):!1),_=e.computed(()=>{switch(u.value){case"addRoot":return"添加根节点";case"addChild":return"添加子节点";case"addSibling":return"添加本级节点";case"edit":return"编辑节点";default:return"节点操作"}}),i=d=>{if(console.log("Node Selected:",d),o.value=d,b.variables&&(b.variables.currentNode=d),s.schema.table.dataSource.type==="static"){const c=s.schema.table.dataSource.data;f.value=c.filter(m=>m.meta?.nodeId===String(d.id))}},n=(d,c)=>{if(console.log("Tree Action:",d,c),!F(d,s.schema)){alert("Permission Denied");return}if(s.schema.tree.dataSource.type!=="static"){alert(`Action ${d} triggered (API implementation required)`);return}if(d==="delete"){if(!c||!confirm(`确定删除节点 "${c.label}" 吗?`))return;const m=s.schema.tree.dataSource.data,a=p=>{const w=p.findIndex(S=>S.id===c.id);if(w>-1)return p.splice(w,1),!0;for(const S of p)if(S.children&&a(S.children))return!0;return!1};a(m)&&o.value?.id===c.id&&(o.value=null);return}(d==="addRoot"||d==="addChild"||d==="addSibling"||d==="edit")&&(u.value=d,B.value=c,C.label=d==="edit"&&c?c.label:"",g.value=!0,e.nextTick(()=>{x.value?.clearValidate()}))},y=()=>{x.value?.validate(d=>{if(!d||s.schema.tree.dataSource.type!=="static")return;const c=s.schema.tree.dataSource.data,m=C.label,a=u.value,p=B.value;if(a==="addRoot")c.push({id:String(Date.now()),label:m,children:[]});else if(a==="addChild")p&&(p.children||(p.children=[]),p.children.push({id:String(Date.now()),label:m,children:[]}));else if(a==="addSibling"){if(p){const w=S=>{const E=S.findIndex(z=>z.id===p.id);if(E>-1)return S.splice(E+1,0,{id:String(Date.now()),label:m,children:[]}),!0;for(const z of S)if(z.children&&w(z.children))return!0;return!1};w(c)}}else a==="edit"&&p&&(p.label=m);g.value=!1})},$=d=>{if(console.log("Upload Success:",d),s.schema.table.dataSource.type==="static"&&o.value){const c={id:Date.now(),name:"Uploaded File.png",size:1024,url:"#",type:"png",meta:{nodeId:String(o.value.id)}};s.schema.table.dataSource.data.push(c),i(o.value)}},D=(d,c)=>{if(console.log("Table Action:",d,c),b.variables&&(b.variables.currentFile=c),!F(d,s.schema)){alert("Permission Denied");return}if(d==="preview")r.value=c,h.value=!0;else if(d==="delete"&&s.schema.table.dataSource.type==="static"){const m=s.schema.table.dataSource.data.findIndex(a=>a.id===c.id);m>-1&&(s.schema.table.dataSource.data.splice(m,1),o.value&&i(o.value))}};return(d,c)=>{const m=e.resolveComponent("el-input"),a=e.resolveComponent("el-form-item"),p=e.resolveComponent("el-form"),w=e.resolveComponent("el-button"),S=e.resolveComponent("el-dialog");return e.openBlock(),e.createElementBlock("div",fe,[e.createElementVNode("div",{class:"tree-pane",style:e.normalizeStyle({width:N.value})},[e.createVNode(W,{schema:t.schema.tree,onNodeClick:i,onAction:n},null,8,["schema"])],4),e.createElementVNode("div",he,[t.mode==="edit"?(e.openBlock(),e.createElementBlock("div",ue,[l.value&&l.value.length>0?(e.openBlock(),e.createBlock(ae,{key:0,templates:l.value},null,8,["templates"])):e.createCommentVNode("",!0),t.schema.upload?(e.openBlock(),e.createBlock(H,{key:1,schema:t.schema.upload,disabled:!k.value,onUploadSuccess:$},null,8,["schema","disabled"])):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.createElementVNode("div",ke,[e.createVNode(v,{schema:t.schema.table,files:f.value,onAction:D},null,8,["schema","files"])])]),t.schema.preview?(e.openBlock(),e.createBlock(pe,{key:0,modelValue:h.value,"onUpdate:modelValue":c[0]||(c[0]=E=>h.value=E),schema:t.schema.preview,file:r.value},null,8,["modelValue","schema","file"])):e.createCommentVNode("",!0),e.createVNode(S,{modelValue:g.value,"onUpdate:modelValue":c[3]||(c[3]=E=>g.value=E),title:_.value,width:"400px","append-to-body":"","destroy-on-close":""},{footer:e.withCtx(()=>[e.createElementVNode("span",ge,[e.createVNode(w,{onClick:c[2]||(c[2]=E=>g.value=!1)},{default:e.withCtx(()=>[...c[4]||(c[4]=[e.createTextVNode("取消",-1)])]),_:1}),e.createVNode(w,{type:"primary",onClick:y},{default:e.withCtx(()=>[...c[5]||(c[5]=[e.createTextVNode("确定",-1)])]),_:1})])]),default:e.withCtx(()=>[e.createVNode(p,{model:C,ref_key:"nodeFormRef",ref:x,"label-width":"80px"},{default:e.withCtx(()=>[e.createVNode(a,{label:"节点名称",prop:"label",rules:[{required:!0,message:"请输入节点名称",trigger:"blur"}]},{default:e.withCtx(()=>[e.createVNode(m,{modelValue:C.label,"onUpdate:modelValue":c[1]||(c[1]=E=>C.label=E),placeholder:"请输入节点名称"},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}}),[["__scopeId","data-v-346b7c9b"]]);V.TreeUpload=I,V.default=I,Object.defineProperties(V,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
@@ -0,0 +1,158 @@
1
+ export interface TreeUploadSchema {
2
+ version: string;
3
+ context?: SchemaContext;
4
+ tree: TreeSchema;
5
+ upload?: UploadSchema;
6
+ table: TableSchema;
7
+ preview?: PreviewSchema;
8
+ permissions?: PermissionSchema;
9
+ }
10
+ export interface SchemaContext {
11
+ variables?: {
12
+ currentNode?: CategoryNode;
13
+ currentFile?: FileItem;
14
+ [key: string]: any;
15
+ };
16
+ }
17
+ export interface TreeSchema {
18
+ nodeKey?: string;
19
+ labelKey?: string;
20
+ childrenKey?: string;
21
+ dataSource: TreeDataSource;
22
+ ui?: TreeUISchema;
23
+ actions?: TreeActionSchema[];
24
+ }
25
+ export type TreeDataSource = {
26
+ type: 'static';
27
+ data: CategoryNode[];
28
+ } | ({
29
+ type: 'api';
30
+ } & ApiDataSourceBase);
31
+ export interface TreeUISchema {
32
+ showRoot?: boolean;
33
+ defaultExpandAll?: boolean;
34
+ highlightCurrent?: boolean;
35
+ width?: number | string;
36
+ lazy?: boolean;
37
+ }
38
+ export interface CategoryNode {
39
+ id: string | number;
40
+ label: string;
41
+ children?: CategoryNode[];
42
+ meta?: Record<string, any>;
43
+ }
44
+ export type BuiltinTreeAction = 'add' | 'addRoot' | 'addChild' | 'addSibling' | 'delete' | 'edit' | 'upload' | 'download' | 'preview';
45
+ export type TreeAction = BuiltinTreeAction | `custom:${string}`;
46
+ export interface TreeActionSchema {
47
+ key: TreeAction;
48
+ label: string;
49
+ icon?: string;
50
+ position?: 'node' | 'contextMenu' | 'toolbar';
51
+ confirm?: {
52
+ title?: string;
53
+ message?: string;
54
+ };
55
+ }
56
+ export interface UploadSchema {
57
+ enabled?: boolean;
58
+ action: string;
59
+ method?: 'post' | 'put';
60
+ headers?: Record<string, string>;
61
+ data?: Record<string, any>;
62
+ multiple?: boolean;
63
+ limit?: number;
64
+ accept?: string;
65
+ drag?: boolean;
66
+ autoUpload?: boolean;
67
+ ui?: UploadUISchema;
68
+ }
69
+ export interface UploadUISchema {
70
+ showTip?: boolean;
71
+ tipText?: string;
72
+ buttonText?: string;
73
+ showFileList?: boolean;
74
+ }
75
+ export interface TableSchema {
76
+ rowKey?: string;
77
+ dataSource: TableDataSource;
78
+ columns: TableColumnSchema[];
79
+ actions?: TableActionSchema[];
80
+ toolbarActions?: TableActionSchema[];
81
+ ui?: TableUISchema;
82
+ }
83
+ export type TableDataSource = {
84
+ type: 'static';
85
+ data: FileItem[];
86
+ } | ({
87
+ type: 'api';
88
+ } & ApiDataSourceBase);
89
+ export interface FileItem {
90
+ id: string | number;
91
+ name: string;
92
+ url: string;
93
+ type?: string;
94
+ size?: number;
95
+ meta?: Record<string, any>;
96
+ }
97
+ export interface TableColumnSchema {
98
+ prop: string;
99
+ label: string;
100
+ width?: number | string;
101
+ align?: 'left' | 'center' | 'right';
102
+ formatter?: string;
103
+ sortable?: boolean;
104
+ fixed?: 'left' | 'right';
105
+ }
106
+ export interface TableActionSchema {
107
+ key: TreeAction;
108
+ label: string;
109
+ icon?: string;
110
+ type?: 'primary' | 'success' | 'warning' | 'danger' | 'info';
111
+ confirm?: {
112
+ title?: string;
113
+ message?: string;
114
+ };
115
+ }
116
+ export interface TableUISchema {
117
+ stripe?: boolean;
118
+ border?: boolean;
119
+ size?: 'small' | 'default' | 'large';
120
+ pagination?: {
121
+ enabled: boolean;
122
+ pageSize?: number;
123
+ layout?: string;
124
+ };
125
+ }
126
+ export interface PreviewSchema {
127
+ enabled?: boolean;
128
+ mode?: 'dialog' | 'drawer';
129
+ dialogTitle?: string;
130
+ width?: string | number;
131
+ height?: string | number;
132
+ fullscreen?: boolean;
133
+ }
134
+ export interface PermissionSchema {
135
+ default?: Partial<Record<TreeAction, boolean>>;
136
+ rules?: PermissionRuleSchema[];
137
+ }
138
+ export interface PermissionRuleSchema {
139
+ action: TreeAction;
140
+ when?: {
141
+ conditions?: ConditionSchema[];
142
+ mode?: 'view' | 'edit';
143
+ };
144
+ allow: boolean;
145
+ }
146
+ export interface ConditionSchema {
147
+ field: string;
148
+ operator: 'eq' | 'neq' | 'in' | 'notIn' | 'exists';
149
+ value?: any;
150
+ }
151
+ export interface ApiDataSourceBase {
152
+ url: string;
153
+ method?: 'get' | 'post';
154
+ params?: Record<string, any>;
155
+ responsePath?: string;
156
+ onError?: 'silent' | 'message' | 'throw';
157
+ loadingKey?: string;
158
+ }
@@ -0,0 +1,3 @@
1
+ import { TreeUploadSchema, TreeAction, SchemaContext } from '../types';
2
+ export declare function checkPermission(action: TreeAction, schema: TreeUploadSchema, context: SchemaContext): boolean;
3
+ export declare function replaceVariables(text: string, context: SchemaContext): string;
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "tree-upload-vue3",
3
+ "version": "1.0.0",
4
+ "description": "基于 Vue 3 + Element Plus 实现的树形文件管理与上传组件。",
5
+ "main": "dist/tree-upload-vue3.umd.js",
6
+ "module": "dist/tree-upload-vue3.es.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "dev": "vite",
13
+ "build": "vue-tsc --noEmit && vite build",
14
+ "preview": "vite preview"
15
+ },
16
+ "peerDependencies": {
17
+ "element-plus": "^2.0.0",
18
+ "vue": "^3.2.0",
19
+ "@element-plus/icons-vue": "^2.0.0",
20
+ "file-preview-vue3-ts": "*"
21
+ },
22
+ "devDependencies": {
23
+ "@element-plus/icons-vue": "^2.3.2",
24
+ "@types/node": "^25.0.3",
25
+ "@vitejs/plugin-vue": "^6.0.3",
26
+ "element-plus": "^2.12.0",
27
+ "file-preview-vue3-ts": "^0.0.1",
28
+ "sass": "^1.97.0",
29
+ "typescript": "^5.9.3",
30
+ "vite": "^7.3.0",
31
+ "vite-plugin-dts": "^4.5.4",
32
+ "vue": "^3.5.25",
33
+ "vue-tsc": "^3.1.8"
34
+ }
35
+ }