leisure-core 1.0.2 → 1.0.4

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.
Files changed (94) hide show
  1. package/index.js +223 -0
  2. package/le-area/index.js +7 -0
  3. package/le-area/src/main.vue +112 -0
  4. package/le-button/index.js +7 -0
  5. package/le-button/src/main.vue +47 -0
  6. package/le-button-attach/index.js +6 -0
  7. package/le-button-attach/src/main.vue +171 -0
  8. package/le-button-msg/index.js +7 -0
  9. package/le-button-msg/src/main.vue +65 -0
  10. package/le-button-qr/index.js +7 -0
  11. package/le-button-qr/src/main.vue +96 -0
  12. package/le-date-picker/index.js +7 -0
  13. package/le-date-picker/src/main.vue +67 -0
  14. package/le-date-picker-auto/index.js +6 -0
  15. package/le-date-picker-auto/src/main.vue +131 -0
  16. package/le-dialog-container/index.js +7 -0
  17. package/le-dialog-container/src/main.vue +80 -0
  18. package/le-form/index.js +7 -0
  19. package/le-form/src/main.vue +13 -0
  20. package/le-form-item/index.js +7 -0
  21. package/le-form-item/src/main.vue +13 -0
  22. package/le-home/index.js +7 -0
  23. package/le-home/src/LeHeaderMenu.vue +60 -0
  24. package/le-home/src/main.vue +1307 -0
  25. package/le-home/src/sub.vue +82 -0
  26. package/le-image/index.js +7 -0
  27. package/le-image/src/main.vue +53 -0
  28. package/le-input/index.js +7 -0
  29. package/le-input/src/main.vue +15 -0
  30. package/le-input-advanced/index.js +7 -0
  31. package/le-input-advanced/src/main.vue +71 -0
  32. package/le-input-number/index.js +7 -0
  33. package/le-input-number/src/main.vue +15 -0
  34. package/le-input-validate/index.js +6 -0
  35. package/le-input-validate/src/main.vue +469 -0
  36. package/le-libs/js/drag.js +78 -0
  37. package/le-libs/js/event.js +3 -0
  38. package/le-libs/js/hrequest.js +76 -0
  39. package/le-libs/js/hrequestFile.js +151 -0
  40. package/le-libs/js/info.js +7 -0
  41. package/le-libs/js/tokens.js +13 -0
  42. package/le-libs/mixins/main.js +48 -0
  43. package/le-list/index.js +7 -0
  44. package/le-list/src/main.vue +645 -0
  45. package/le-list-form/index.js +7 -0
  46. package/le-list-form/src/main.vue +474 -0
  47. package/le-login/index.js +7 -0
  48. package/le-login/src/ForgotPassword.vue +613 -0
  49. package/le-login/src/main.vue +982 -0
  50. package/le-media/index.js +7 -0
  51. package/le-media/src/main.vue +298 -0
  52. package/le-media-list/index.js +7 -0
  53. package/le-media-list/src/main.vue +178 -0
  54. package/le-media-upload/index.js +7 -0
  55. package/le-media-upload/src/main.vue +329 -0
  56. package/le-menu/index.js +7 -0
  57. package/le-menu/src/main.vue +248 -0
  58. package/le-report/index.js +6 -0
  59. package/le-report/src/main.vue +1747 -0
  60. package/le-report/src/rmixins.js +30 -0
  61. package/le-role/index.js +7 -0
  62. package/le-role/src/main.vue +183 -0
  63. package/le-role/src/sub.vue +79 -0
  64. package/le-role-user/index.js +7 -0
  65. package/le-role-user/src/main.vue +160 -0
  66. package/le-role-user/src/sub.vue +90 -0
  67. package/le-select/index.js +7 -0
  68. package/le-select/src/main.vue +49 -0
  69. package/le-select-multi/index.js +6 -0
  70. package/le-select-multi/src/main.vue +816 -0
  71. package/le-select-option/index.js +7 -0
  72. package/le-select-option/src/main.vue +69 -0
  73. package/le-select-search/index.js +7 -0
  74. package/le-select-search/src/main.vue +46 -0
  75. package/le-span/index.js +7 -0
  76. package/le-span/src/main.vue +29 -0
  77. package/le-table-edit/index.js +6 -0
  78. package/le-table-edit/src/main.vue +689 -0
  79. package/le-theme/common/vars.css +131 -0
  80. package/le-theme/iconfont/iconfont.css +125 -0
  81. package/le-theme/iconfont/iconfont.ttf +0 -0
  82. package/le-theme/iconfont/iconfont.woff +0 -0
  83. package/le-theme/iconfont/iconfont.woff2 +0 -0
  84. package/le-theme/index.js +189 -0
  85. package/le-theme/pages/index.css +15 -0
  86. package/le-upload/index.js +7 -0
  87. package/le-upload/src/main.vue +134 -0
  88. package/le-upload-table/index.js +6 -0
  89. package/le-upload-table/src/main.vue +648 -0
  90. package/le-url/index.js +7 -0
  91. package/le-url/src/main.vue +27 -0
  92. package/le-video/index.js +7 -0
  93. package/le-video/src/main.vue +42 -0
  94. package/package.json +1 -6
@@ -0,0 +1,648 @@
1
+ <template>
2
+ <div>
3
+ <le-button type="primary" size="small" @click="showPopClick"
4
+ >附件</le-button
5
+ >
6
+ <le-dialog-container
7
+ v-if="showWindow"
8
+ title="附件管理"
9
+ width="80%"
10
+ :showDialog="showWindow"
11
+ :showFooter="true"
12
+ :showCloseBtnTop="true"
13
+ saveBtnText="确定"
14
+ :showSaveBtn="false"
15
+ @close="closeBtn"
16
+ >
17
+ <div class="attachment-management">
18
+ <!-- 头部标题和上传按钮 -->
19
+ <div class="header">
20
+ <span class="title">{{ title }}</span>
21
+ <span class="count" v-if="localAttachments.length > 0"
22
+ >({{ localAttachments.length }})</span
23
+ >
24
+ <el-upload
25
+ action=""
26
+ :http-request="uploadFile"
27
+ :before-upload="beforeUpload"
28
+ :show-file-list="false"
29
+ :multiple="true"
30
+ :accept="acceptTypes"
31
+ >
32
+ <el-button
33
+ type="primary"
34
+ size="small"
35
+ icon="el-icon-upload"
36
+ v-if="dispUpload"
37
+ >
38
+ 上传文件
39
+ </el-button>
40
+ </el-upload>
41
+ </div>
42
+
43
+ <!-- 文件列表表格 -->
44
+ <el-table :data="localAttachments" class="file-table">
45
+ <el-table-column
46
+ prop="mtype_name"
47
+ label="业务类型"
48
+ align="center"
49
+ ></el-table-column>
50
+ <el-table-column label="原始文件名称" align="center">
51
+ <template slot-scope="scope">
52
+ <div class="file-info">
53
+ <i :class="getFileIcon(scope.row)" class="file-icon"></i>
54
+ <span>{{ scope.row.attach_name_ori }}</span>
55
+ </div>
56
+ </template>
57
+ </el-table-column>
58
+ <el-table-column
59
+ prop="attach_name"
60
+ label="文件名称"
61
+ align="center"
62
+ ></el-table-column>
63
+ <el-table-column
64
+ prop="attach_path"
65
+ label="存储路径"
66
+ align="center"
67
+ ></el-table-column>
68
+
69
+ <el-table-column label="文件大小" align="center">
70
+ <template slot-scope="scope">
71
+ {{ formatFileSize(scope.row.attach_size) }}
72
+ </template>
73
+ </el-table-column>
74
+
75
+ <el-table-column label="上传时间" align="center">
76
+ <template slot-scope="scope">
77
+ {{ formatTime(scope.row.create_at) }}
78
+ </template>
79
+ </el-table-column>
80
+
81
+ <el-table-column label="操作" width="120" align="center">
82
+ <template slot-scope="scope">
83
+ <el-button
84
+ type="text"
85
+ size="mini"
86
+ @click="handleDownLoad(scope.row)"
87
+ >
88
+ 下载
89
+ </el-button>
90
+ <el-button
91
+ type="text"
92
+ size="mini"
93
+ @click="handleRemove(scope.$index)"
94
+ class="delete-btn"
95
+ v-if="dispDele"
96
+ >
97
+ 删除
98
+ </el-button>
99
+ </template>
100
+ </el-table-column>
101
+ </el-table>
102
+
103
+ <!-- 空状态 -->
104
+ <div
105
+ v-if="!localAttachments || localAttachments.length === 0"
106
+ class="empty-state"
107
+ >
108
+ <i class="el-icon-document"></i>
109
+ <p>暂无附件</p>
110
+ </div>
111
+ </div>
112
+ </le-dialog-container>
113
+ </div>
114
+ </template>
115
+
116
+ <script>
117
+ // import {
118
+ // upload,
119
+ // create,
120
+ // del,
121
+ // list,
122
+ // download,
123
+ // } from "@/api/attachment/attachment.js";
124
+ // import { downLoadSimple } from "@/utils/downLoadFile.js";
125
+
126
+ export default {
127
+ name: "le-upload-table",
128
+ props: {
129
+ showPop: {
130
+ type: Boolean,
131
+ default: false,
132
+ },
133
+ value: {
134
+ type: Array,
135
+ default: () => [],
136
+ },
137
+ mname: {
138
+ type: String,
139
+ default: "",
140
+ },
141
+ mtype: {
142
+ type: String,
143
+ default: "",
144
+ },
145
+ mid: {
146
+ type: String,
147
+ default: "",
148
+ },
149
+
150
+ title: {
151
+ type: String,
152
+ default: "附件管理",
153
+ },
154
+ disabled: {
155
+ type: Boolean,
156
+ default: false,
157
+ },
158
+ maxSize: {
159
+ type: Number,
160
+ default: 10,
161
+ },
162
+ maxTotalSize: {
163
+ type: Number,
164
+ default: 100,
165
+ },
166
+ maxFileCount: {
167
+ type: Number,
168
+ default: 20,
169
+ },
170
+ dir: {
171
+ type: String,
172
+ default: "",
173
+ },
174
+ acceptTypes: {
175
+ type: String,
176
+ default: "*",
177
+ },
178
+ dispUpload: {
179
+ type: Boolean,
180
+ default: true,
181
+ },
182
+ dispDele: {
183
+ type: Boolean,
184
+ default: true,
185
+ },
186
+ uploadApi: {
187
+ type: Function,
188
+ required: true, // 强制父组件提供
189
+ },
190
+ // 批量创建附件记录(接收参数数组,返回 Promise<{ data: { data: [...] } }>)
191
+ createApi: {
192
+ type: Function,
193
+ required: true,
194
+ },
195
+ // 删除附件(接收 { id },返回 Promise)
196
+ deleteApi: {
197
+ type: Function,
198
+ required: true,
199
+ },
200
+ // 查询附件列表(接收 { mid, mtype },返回 Promise<{ data: { data: [...] } }>)
201
+ listApi: {
202
+ type: Function,
203
+ required: true,
204
+ },
205
+ // 下载文件(接收参数,通常为 fileName 等,返回 void 或 Promise)
206
+ downloadApi: {
207
+ type: Function,
208
+ required: true,
209
+ },
210
+ },
211
+ watch: {
212
+ showPop: {
213
+ handler(val) {
214
+ this.showWindow = val;
215
+ },
216
+ immediate: true,
217
+ },
218
+ // 监听父组件传入的value变化,同步到本地
219
+ value: {
220
+ handler(newVal) {
221
+ this.localAttachments = [...newVal];
222
+ },
223
+ immediate: true,
224
+ deep: true,
225
+ },
226
+ },
227
+ data() {
228
+ return {
229
+ showWindow: false,
230
+ uploading: false,
231
+ selectedFiles: [],
232
+ localAttachments: [], // 本地管理的附件列表
233
+ };
234
+ },
235
+ computed: {
236
+ currentTotalSize() {
237
+ return this.localAttachments.reduce(
238
+ (total, file) => total + (file.size || 0),
239
+ 0,
240
+ );
241
+ },
242
+ // currentTotalSize() {
243
+ // return this.localAttachments.reduce(
244
+ // (total, file) => total + (file.attach_size || 0),
245
+ // 0
246
+ // );
247
+ // },
248
+ },
249
+ mounted() {},
250
+ methods: {
251
+ // getList(callback) {
252
+ // let param = {};
253
+ // param.mid = this.mid;
254
+ // param.mtype = this.mtype;
255
+ // const formData = new URLSearchParams(param);
256
+ // list(formData).then((res) => {
257
+ // this.localAttachments = res.data.data;
258
+ // if (callback) {
259
+ // callback();
260
+ // }
261
+ // });
262
+ // },
263
+ getList(callback) {
264
+ const param = { mid: this.mid, mtype: this.mtype };
265
+ const formData = new URLSearchParams(param);
266
+ this.listApi(formData)
267
+ .then((res) => {
268
+ this.localAttachments = res.data.data || [];
269
+ if (callback) callback();
270
+ })
271
+ .catch(() => {
272
+ this.$message.error("获取附件列表失败");
273
+ });
274
+ },
275
+ // 上传前校验
276
+ beforeUpload(file) {
277
+ // 检查文件大小
278
+ if (file.size / 1024 / 1024 > this.maxSize) {
279
+ this.$message.error(
280
+ `文件 "${file.name}" 大小不能超过 ${this.maxSize}MB`,
281
+ );
282
+ return false;
283
+ }
284
+
285
+ // 检查文件数量
286
+ if (this.localAttachments.length >= this.maxFileCount) {
287
+ this.$message.error(`最多只能上传 ${this.maxFileCount} 个文件`);
288
+ return false;
289
+ }
290
+
291
+ // 检查总大小
292
+ const newTotalSize = this.currentTotalSize + file.size;
293
+ if (newTotalSize / 1024 / 1024 > this.maxTotalSize) {
294
+ this.$message.error(`所有文件总大小不能超过 ${this.maxTotalSize}MB`);
295
+ return false;
296
+ }
297
+
298
+ return true;
299
+ },
300
+
301
+ // 上传文件
302
+ // async uploadFile(param) {
303
+ // if (this.uploading) {
304
+ // this.$message.warning("正在上传中,请稍候...");
305
+ // return;
306
+ // }
307
+
308
+ // this.uploading = true;
309
+
310
+ // try {
311
+ // const formData = new FormData();
312
+ // formData.append("files", param.file);
313
+
314
+ // if (this.dir) {
315
+ // formData.append("dir", this.dir);
316
+ // }
317
+
318
+ // const res = await upload(formData);
319
+
320
+ // if (res.data && res.data.data) {
321
+ // const urlList = res.data.data;
322
+
323
+ // if (urlList && urlList.length > 0) {
324
+ // let newFiles = [];
325
+ // urlList.forEach((ele) => {
326
+ // const newFile = {
327
+ // id: Date.now(),
328
+ // mid: this.mid,
329
+ // mtype: this.mtype,
330
+ // mtype_name: this.mname,
331
+ // attach_name_ori: ele.filesOriginal,
332
+ // attach_name: ele.filesNew,
333
+ // attach_size: ele.fileSize,
334
+ // attach_path: ele.filesUrlPath,
335
+ // create_at: new Date(),
336
+ // };
337
+ // newFiles.push(newFile);
338
+ // });
339
+
340
+ // this._saveData(newFiles, (res) => {
341
+ // const uploadFiles = res.data.data;
342
+ // const localData = [...this.localAttachments, ...uploadFiles];
343
+ // this.localAttachments = localData;
344
+ // this.$message.success(`文件上传成功`);
345
+ // });
346
+ // } else {
347
+ // this.$message.error("上传成功但未返回文件URL");
348
+ // }
349
+ // } else {
350
+ // this.$message.error(res.data?.msg || "上传失败");
351
+ // }
352
+ // } catch (error) {
353
+ // this.$message.error(`文件上传失败`);
354
+ // } finally {
355
+ // this.uploading = false;
356
+ // }
357
+ // },
358
+
359
+ async uploadFile(param) {
360
+ if (this.uploading) {
361
+ this.$message.warning("正在上传中,请稍候...");
362
+ return;
363
+ }
364
+ this.uploading = true;
365
+ try {
366
+ const formData = new FormData();
367
+ formData.append("files", param.file);
368
+ if (this.dir) formData.append("dir", this.dir);
369
+
370
+ const res = await this.uploadApi(formData);
371
+ const urlList = res?.data?.data;
372
+ if (!urlList || urlList.length === 0) {
373
+ this.$message.error("上传成功但未返回文件URL");
374
+ return;
375
+ }
376
+ const newFiles = urlList.map((ele) => ({
377
+ id: Date.now(),
378
+ mid: this.mid,
379
+ mtype: this.mtype,
380
+ mtype_name: this.mname,
381
+ attach_name_ori: ele.filesOriginal,
382
+ attach_name: ele.filesNew,
383
+ attach_size: ele.fileSize,
384
+ attach_path: ele.filesUrlPath,
385
+ create_at: new Date(),
386
+ }));
387
+ // 调用创建 API
388
+ await this._createRecords(newFiles);
389
+ // 刷新列表
390
+ await this.getList();
391
+ this.$message.success("文件上传成功");
392
+ } catch (error) {
393
+ this.$message.error(error.message || "文件上传失败");
394
+ } finally {
395
+ this.uploading = false;
396
+ }
397
+ },
398
+
399
+ // 删除文件
400
+ handleRemove(index) {
401
+ const file = this.localAttachments[index];
402
+ this.$confirm(`确定删除文件 "${file.attach_name_ori}" 吗?`, "提示", {
403
+ confirmButtonText: "确定",
404
+ cancelButtonText: "取消",
405
+ type: "warning",
406
+ }).then(() => {
407
+ // 直接更新本地数据
408
+ let param = { id: file.id };
409
+ const formData = new URLSearchParams(param);
410
+ this.deleteApi(formData).then(() => {
411
+ const updatedAttachments = [...this.localAttachments];
412
+ updatedAttachments.splice(index, 1);
413
+ this.localAttachments = updatedAttachments;
414
+ this.$message.success("删除成功");
415
+ });
416
+ });
417
+ },
418
+
419
+ // 根据文件名获取文件类型
420
+ getFileTypeFromName(filename) {
421
+ if (!filename) return "";
422
+ const ext = filename.split(".").pop().toLowerCase();
423
+ const typeMap = {
424
+ jpg: "image/jpeg",
425
+ jpeg: "image/jpeg",
426
+ png: "image/png",
427
+ gif: "image/gif",
428
+ bmp: "image/bmp",
429
+ webp: "image/webp",
430
+ pdf: "application/pdf",
431
+ doc: "application/msword",
432
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
433
+ xls: "application/vnd.ms-excel",
434
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
435
+ ppt: "application/vnd.ms-powerpoint",
436
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
437
+ zip: "application/zip",
438
+ rar: "application/x-rar-compressed",
439
+ txt: "text/plain",
440
+ md: "text/markdown",
441
+ };
442
+ return typeMap[ext] || "application/octet-stream";
443
+ },
444
+
445
+ // 下载文件
446
+ handleDownLoad(row) {
447
+ let params = {};
448
+ params.fileName = row.attach_name;
449
+ // downLoadSimple(
450
+ // "/system-attachment/download",
451
+ // row.attach_name_ori,
452
+ // params,
453
+ // ).catch((error) => {
454
+ // this.$message.error(error);
455
+ // });
456
+ this.downloadApi(row.attach_name_ori, params).catch((err) => {
457
+ this.$message.error(err.message || "下载失败");
458
+ });
459
+ },
460
+
461
+ // 检查文件是否可预览
462
+ isPreviewable(file) {
463
+ const previewableTypes = ["image/", "application/pdf", "text/"];
464
+ return previewableTypes.some((type) => file.type?.includes(type));
465
+ },
466
+
467
+ // 获取文件图标
468
+ getFileIcon(file) {
469
+ const type = file.type || "";
470
+ const name = file.attach_name_ori || "";
471
+
472
+ if (type.startsWith("image/")) return "el-icon-picture";
473
+ if (type.includes("pdf") || name.toLowerCase().endsWith(".pdf"))
474
+ return "el-icon-document";
475
+ if (type.includes("word") || name.toLowerCase().match(/\.docx?$/))
476
+ return "el-icon-document";
477
+ if (type.includes("excel") || name.toLowerCase().match(/\.xlsx?$/))
478
+ return "el-icon-document";
479
+ if (type.includes("zip") || name.toLowerCase().match(/\.(zip|rar|7z)$/))
480
+ return "el-icon-folder";
481
+ if (type.includes("text") || name.toLowerCase().match(/\.(txt|md)$/))
482
+ return "el-icon-document";
483
+ return "el-icon-document";
484
+ },
485
+
486
+ // 格式化文件大小
487
+ formatFileSize(bytes) {
488
+ if (!bytes || bytes === 0) return "0 B";
489
+ const k = 1024;
490
+ const sizes = ["B", "KB", "MB", "GB"];
491
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
492
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
493
+ },
494
+
495
+ // 格式化时间
496
+ formatTime(time) {
497
+ if (!time) return "";
498
+ const date = new Date(time * 1000);
499
+ return `${date.getFullYear()}-${(date.getMonth() + 1)
500
+ .toString()
501
+ .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")} ${date
502
+ .getHours()
503
+ .toString()
504
+ .padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
505
+ },
506
+
507
+ saveData() {
508
+ // 在保存时将本地数据同步给父组件
509
+ this.closeBtn();
510
+ },
511
+
512
+ // _saveData(datas, callBack) {
513
+ // if (datas && datas.length > 0) {
514
+ // let params = [];
515
+ // datas.forEach((ele) => {
516
+ // let param = {};
517
+ // param.mid = ele.mid;
518
+ // param.mtype = ele.mtype;
519
+ // param.mtype_name = ele.mtype_name;
520
+ // param.attach_name = ele.attach_name;
521
+ // param.attach_name_ori = ele.attach_name_ori;
522
+ // param.attach_size = ele.attach_size;
523
+ // param.attach_path = ele.attach_path;
524
+ // params.push(param);
525
+ // });
526
+ // create(params)
527
+ // .then((res) => {
528
+ // if (callBack) callBack(res);
529
+ // this.$message.success("上传服务器成功");
530
+ // })
531
+ // .catch((err) => {
532
+ // this.$message.error("上传失败");
533
+ // });
534
+ // }
535
+ // },
536
+
537
+ _createRecords(datas) {
538
+ if (!datas || datas.length === 0) return Promise.resolve();
539
+ const params = datas.map((ele) => ({
540
+ mid: ele.mid,
541
+ mtype: ele.mtype,
542
+ mtype_name: ele.mtype_name,
543
+ attach_name: ele.attach_name,
544
+ attach_name_ori: ele.attach_name_ori,
545
+ attach_size: ele.attach_size,
546
+ attach_path: ele.attach_path,
547
+ }));
548
+ return this.createApi(params);
549
+ },
550
+
551
+ closeBtn() {
552
+ this.showWindow = false;
553
+ this.$emit("update:showPop", false);
554
+ this.$emit("close");
555
+ },
556
+
557
+ showPopClick() {
558
+ this.getList(() => {
559
+ this.showWindow = true;
560
+ });
561
+ },
562
+ },
563
+ };
564
+ </script>
565
+
566
+ <style scoped>
567
+ .attachment-management {
568
+ padding: 16px;
569
+ background: #fff;
570
+ border-radius: 4px;
571
+ }
572
+
573
+ .header {
574
+ display: flex;
575
+ align-items: center;
576
+ margin-bottom: 16px;
577
+ gap: 12px;
578
+ }
579
+
580
+ .title {
581
+ font-size: 16px;
582
+ font-weight: 500;
583
+ color: #303133;
584
+ }
585
+
586
+ .count {
587
+ color: #909399;
588
+ font-size: 14px;
589
+ }
590
+
591
+ .file-table {
592
+ width: 100%;
593
+ border: 1px solid #ebeef5;
594
+ }
595
+
596
+ .file-info {
597
+ display: flex;
598
+ align-items: center;
599
+ gap: 8px;
600
+ }
601
+
602
+ .file-icon {
603
+ color: #409eff;
604
+ font-size: 18px;
605
+ }
606
+
607
+ .delete-btn {
608
+ color: #f56c6c;
609
+ }
610
+
611
+ .delete-btn:hover {
612
+ color: #f78989;
613
+ }
614
+
615
+ .empty-state {
616
+ text-align: center;
617
+ padding: 40px;
618
+ color: #909399;
619
+ }
620
+
621
+ .empty-state i {
622
+ font-size: 48px;
623
+ margin-bottom: 12px;
624
+ display: block;
625
+ color: #c0c4cc;
626
+ }
627
+
628
+ .empty-state p {
629
+ margin: 0;
630
+ font-size: 14px;
631
+ }
632
+
633
+ /* 上传按钮禁用状态 */
634
+ :deep(.el-upload) {
635
+ display: inline-block;
636
+ }
637
+
638
+ :deep(.el-upload[disabled]) {
639
+ cursor: not-allowed;
640
+ }
641
+
642
+ :deep(.el-upload[disabled] .el-button) {
643
+ background-color: #f5f7fa;
644
+ border-color: #e4e7ed;
645
+ color: #c0c4cc;
646
+ cursor: not-allowed;
647
+ }
648
+ </style>
@@ -0,0 +1,7 @@
1
+ import LeUrl from "./src/main.vue";
2
+
3
+ LeUrl.install = function (Vue) {
4
+ Vue.component(LeUrl.name, LeUrl);
5
+ };
6
+
7
+ export default LeUrl;
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <a :href="value" target="_blank" rel="noopener noreferrer">
3
+ {{ value }}
4
+ </a>
5
+ </template>
6
+ <script>
7
+ export default {
8
+ name: "le-url",
9
+ props: {
10
+ value: {
11
+ type: String,
12
+ required: true,
13
+ },
14
+ },
15
+ methods: {},
16
+ };
17
+ </script>
18
+ <style lang="scss" scoped>
19
+ a {
20
+ color: #007bff;
21
+ text-decoration: none;
22
+ }
23
+
24
+ a:hover {
25
+ text-decoration: underline;
26
+ }
27
+ </style>
@@ -0,0 +1,7 @@
1
+ import LeVideo from "./src/main.vue";
2
+
3
+ LeVideo.install = function (Vue) {
4
+ Vue.component(LeVideo.name, LeVideo);
5
+ };
6
+
7
+ export default LeVideo;