@sl-material/sl-import 1.0.0 → 1.1.0-beta1

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/sl-import.es.js CHANGED
@@ -1388,7 +1388,6 @@ function getImportDialogStyles() {
1388
1388
  overflow-y: hidden;
1389
1389
  padding: 0px 0px 12px 0px;
1390
1390
  scrollbar-width: thin;
1391
- // scrollbar-color: #d9d9d9 transparent;
1392
1391
  }
1393
1392
 
1394
1393
  .import-dialog-vanilla-file-list::-webkit-scrollbar {
@@ -1428,22 +1427,10 @@ function getImportDialogStyles() {
1428
1427
  width:100%;
1429
1428
  }
1430
1429
 
1431
- // .import-dialog-vanilla-file-item:hover {
1432
- // background: #FFF7E6;
1433
- // }
1434
-
1435
- // .import-dialog-vanilla-file-item.status-success {
1436
- // background: #FFFBF0;
1437
- // }
1438
-
1439
1430
  .import-dialog-vanilla-file-item.status-error {
1440
- background: #FFF2F0;
1441
- }
1442
-
1443
- .import-dialog-vanilla-file-item.status-uploading {
1444
- background: #FFFBF0;
1431
+ background: var(--sl-color-danger-light-9);
1432
+ border:1px solid var(--sl-color-error);
1445
1433
  }
1446
-
1447
1434
  .import-dialog-vanilla-file-icon {
1448
1435
  width: 18px;
1449
1436
  height: 18px;
@@ -1479,19 +1466,64 @@ function getImportDialogStyles() {
1479
1466
  align-items: center;
1480
1467
  gap: 4px;
1481
1468
  font-size: 12px;
1482
- color: var(--sl-text-color-secondary);
1469
+ color: var(--sl-text-color-thridary);
1483
1470
  }
1484
1471
 
1485
- .import-dialog-vanilla-file-progress-text {
1486
- font-size: 12px;
1487
- color: #1890FF;
1488
- }
1489
1472
 
1490
1473
  .import-dialog-vanilla-file-error-text {
1491
1474
  font-size: 12px;
1492
1475
  color: var(--sl-color-error);
1493
1476
  }
1494
1477
 
1478
+ /* 上传中状态的 loading 图标 */
1479
+ .import-dialog-vanilla-file-loading-icon {
1480
+ position: absolute;
1481
+ top: 8px;
1482
+ left: 8px;
1483
+ width: 32px;
1484
+ height: 32px;
1485
+ display: flex;
1486
+ align-items: center;
1487
+ justify-content: center;
1488
+ }
1489
+
1490
+ .loading-spinner {
1491
+ width: 24px;
1492
+ height: 24px;
1493
+ border-radius: 50%;
1494
+ background: conic-gradient(from 0deg at 50% 50%, rgba(24, 144, 255, 0.1) 0%, #1890ff 75%, rgba(24, 144, 255, 0) 100%);
1495
+ animation: spin 1s linear infinite;
1496
+ display: flex;
1497
+ align-items: center;
1498
+ justify-content: center;
1499
+ position: relative;
1500
+ opacity: 0;
1501
+ transition: opacity 0.3s ease;
1502
+ }
1503
+
1504
+ .loading-spinner::before {
1505
+ content: '';
1506
+ width: 18px;
1507
+ height: 18px;
1508
+ border-radius: 50%;
1509
+ background-color: #fff;
1510
+ position: absolute;
1511
+ }
1512
+
1513
+ .loading-spinner.active {
1514
+ opacity: 1;
1515
+ }
1516
+
1517
+ @keyframes spin {
1518
+ 0% { transform: rotate(0deg); }
1519
+ 100% { transform: rotate(360deg); }
1520
+ }
1521
+
1522
+ /* 上传中状态的文件信息向右偏移 */
1523
+ .import-dialog-vanilla-file-item.status-uploading .import-dialog-vanilla-file-info {
1524
+ margin-left: 32px;
1525
+ }
1526
+
1495
1527
  /* 删除按钮 - 默认隐藏,hover时显示 */
1496
1528
  .import-dialog-vanilla-file-remove-btn {
1497
1529
  position: absolute;
@@ -2816,10 +2848,31 @@ class ImportDialogRenderer {
2816
2848
  if (isError) {
2817
2849
  metaContent = `<span class="import-dialog-vanilla-file-error-text">${t("uploadFailed")}</span>`;
2818
2850
  } else if (isUploading) {
2819
- metaContent = `<span class="import-dialog-vanilla-file-progress-text">${t("uploading")}...</span><span>·</span><span>${fileSize}</span>`;
2851
+ metaContent = `<span>${t("uploading")}...</span><span>·</span><span>${fileSize}</span>`;
2820
2852
  } else {
2821
2853
  metaContent = `<span>${fileExt}</span><span>·</span><span>${fileSize}</span>`;
2822
2854
  }
2855
+ if (isUploading) {
2856
+ return `
2857
+ <div class="import-dialog-vanilla-file-item ${statusClass} ${widthClass}" data-file-id="${fileItem.id}">
2858
+ <div class="import-dialog-vanilla-file-loading-icon">
2859
+ <div class="loading-spinner active"></div>
2860
+ </div>
2861
+ <div class="import-dialog-vanilla-file-remove-btn" data-file-index="${index}" title="删除">
2862
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2863
+ <circle cx="8" cy="8" r="8" fill="rgba(0,0,0)"/>
2864
+ <path d="M5 5L11 11M11 5L5 11" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
2865
+ </svg>
2866
+ </div>
2867
+ <div class="import-dialog-vanilla-file-info">
2868
+ <div class="import-dialog-vanilla-file-name" title="${fileItem.name}">${fileItem.name}</div>
2869
+ <div class="import-dialog-vanilla-file-meta">
2870
+ ${metaContent}
2871
+ </div>
2872
+ </div>
2873
+ </div>
2874
+ `;
2875
+ }
2823
2876
  return `
2824
2877
  <div class="import-dialog-vanilla-file-item ${statusClass} ${widthClass}" data-file-id="${fileItem.id}">
2825
2878
  <div class="import-dialog-vanilla-file-icon">
@@ -2918,6 +2971,7 @@ class ChunkedUploader {
2918
2971
  fileItem.file.name,
2919
2972
  fileItem.file.size
2920
2973
  );
2974
+ console.info("upload>>>分片结果", initResult);
2921
2975
  fileItem.uploadSessionId = initResult.uploadSessionId;
2922
2976
  this.currentFileItem = fileItem;
2923
2977
  this.initResumable(initResult);
@@ -2941,6 +2995,7 @@ class ChunkedUploader {
2941
2995
  * 初始化Resumable实例
2942
2996
  */
2943
2997
  initResumable(initResult) {
2998
+ console.log("[分片上传] 初始化分片上传...", initResult);
2944
2999
  if (this.resumable) {
2945
3000
  this.resumable.cancel();
2946
3001
  }
@@ -2959,6 +3014,7 @@ class ChunkedUploader {
2959
3014
  forceChunkSize: true
2960
3015
  };
2961
3016
  const finalConfig = { ...defaultConfig, ...customConfig };
3017
+ console.info("finalConfig>>>分片上传配置", finalConfig);
2962
3018
  this.resumable = new Resumable(finalConfig);
2963
3019
  this.bindResumableEvents();
2964
3020
  }
@@ -2969,6 +3025,7 @@ class ChunkedUploader {
2969
3025
  this.resumable.on("progress", () => {
2970
3026
  var _a, _b, _c, _d;
2971
3027
  const progress = Math.floor(this.resumable.progress() * 100);
3028
+ console.log(`[Resumable分片上传] 进度: ${progress}%`);
2972
3029
  if (this.currentFileItem) {
2973
3030
  this.currentFileItem.progress = Math.min(progress, 90);
2974
3031
  (_b = (_a = this.callbacks).onProgress) == null ? void 0 : _b.call(
@@ -2980,6 +3037,7 @@ class ChunkedUploader {
2980
3037
  (_d = (_c = this.callbacks).onUpdate) == null ? void 0 : _d.call(_c);
2981
3038
  });
2982
3039
  this.resumable.on("fileSuccess", () => {
3040
+ console.log("[Resumable分片上传] 文件上传成功");
2983
3041
  this.handleResumableComplete();
2984
3042
  });
2985
3043
  this.resumable.on("error", (message) => {
@@ -2987,6 +3045,7 @@ class ChunkedUploader {
2987
3045
  this.handleResumableError(message);
2988
3046
  });
2989
3047
  this.resumable.on("fileAdded", () => {
3048
+ console.info("fileAdded>>>开始上传");
2990
3049
  this.resumable.upload();
2991
3050
  });
2992
3051
  }
@@ -3005,6 +3064,7 @@ class ChunkedUploader {
3005
3064
  this.currentFileItem.progress = 100;
3006
3065
  }
3007
3066
  this.uploadCompleteResolve(mergeResult);
3067
+ console.log("合并分片成功>>>uploadCompleteResolve", mergeResult);
3008
3068
  this.cleanup();
3009
3069
  } catch (error) {
3010
3070
  const err = error instanceof Error ? error : new Error(String(error));
@@ -3070,9 +3130,6 @@ class ImportDialogUploader {
3070
3130
  __publicField(this, "callbacks");
3071
3131
  // 分片上传器实例
3072
3132
  __publicField(this, "chunkedUploader", null);
3073
- // 并发上传队列
3074
- __publicField(this, "uploadQueue", []);
3075
- __publicField(this, "activeUploads", 0);
3076
3133
  // 上传状态
3077
3134
  __publicField(this, "uploadFileList", []);
3078
3135
  //上传文件列表
@@ -3105,12 +3162,6 @@ class ImportDialogUploader {
3105
3162
  });
3106
3163
  }
3107
3164
  }
3108
- /**
3109
- * 获取并发限制数
3110
- */
3111
- get concurrentLimit() {
3112
- return this.config.concurrentLimit != null ? this.config.concurrentLimit : 3;
3113
- }
3114
3165
  /**
3115
3166
  * 判断是否应该使用分片上传
3116
3167
  * 条件:配置了chunkedUpload 且 是单文件模式
@@ -3134,14 +3185,12 @@ class ImportDialogUploader {
3134
3185
  this.isUploading = false;
3135
3186
  this.uploadMessage = "";
3136
3187
  this.uploadMessageType = "info";
3137
- this.uploadQueue = [];
3138
- this.activeUploads = 0;
3139
3188
  }
3140
3189
  /**
3141
3190
  * 文件上传之前的校验 选择文件时调用
3142
3191
  */
3143
3192
  beforeUpload(files) {
3144
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3193
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3145
3194
  const fileArray = Array.isArray(files) ? files : [files];
3146
3195
  if (!fileArray.length) {
3147
3196
  (_b = (_a = this.callbacks).onMessage) == null ? void 0 : _b.call(_a, "请选择文件", "warning");
@@ -3187,9 +3236,27 @@ class ImportDialogUploader {
3187
3236
  }
3188
3237
  (_h = (_g = this.callbacks).onUpdate) == null ? void 0 : _h.call(_g);
3189
3238
  (_j = (_i = this.callbacks).onFileChange) == null ? void 0 : _j.call(_i, this.uploadFileList);
3190
- this.processFilesWithCustomUpload();
3239
+ if (this.shouldUseChunkedUpload()) {
3240
+ if (((_k = this.config.uploadConfig) == null ? void 0 : _k.autoUpload) !== false) {
3241
+ this.processChunkedUpload();
3242
+ }
3243
+ } else {
3244
+ this.processFilesWithCustomUpload();
3245
+ }
3191
3246
  return true;
3192
3247
  }
3248
+ /**
3249
+ * 处理分片上传
3250
+ * 仅在配置了 chunkedUpload 时调用
3251
+ */
3252
+ async processChunkedUpload() {
3253
+ const pendingFiles = this.uploadFileList.filter(
3254
+ (f) => f.status === "pending"
3255
+ );
3256
+ for (const fileItem of pendingFiles) {
3257
+ await this.uploadSingleFile(fileItem);
3258
+ }
3259
+ }
3193
3260
  /**
3194
3261
  * 使用 customUpload 预处理文件
3195
3262
  * 仅在配置了 customUpload 时才调用
@@ -3268,12 +3335,6 @@ class ImportDialogUploader {
3268
3335
  (_c = (_b = this.callbacks).onMessage) == null ? void 0 : _c.call(_b, "文件正在上传中,无法删除", "warning");
3269
3336
  return false;
3270
3337
  }
3271
- const queueIndex = this.uploadQueue.findIndex(
3272
- (q) => q.id === fileItem.id
3273
- );
3274
- if (queueIndex !== -1) {
3275
- this.uploadQueue.splice(queueIndex, 1);
3276
- }
3277
3338
  this.uploadFileList.splice(index, 1);
3278
3339
  this.fileList.splice(index, 1);
3279
3340
  } else {
@@ -3286,7 +3347,6 @@ class ImportDialogUploader {
3286
3347
  return false;
3287
3348
  }
3288
3349
  }
3289
- this.uploadQueue = [];
3290
3350
  this.uploadFileList = [];
3291
3351
  this.fileList = [];
3292
3352
  }
@@ -3300,38 +3360,12 @@ class ImportDialogUploader {
3300
3360
  (_i = (_h = this.callbacks).onUpdate) == null ? void 0 : _i.call(_h);
3301
3361
  return true;
3302
3362
  }
3303
- /**
3304
- * 将文件加入上传队列并启动处理
3305
- */
3306
- enqueueUpload(fileItems) {
3307
- const newItems = fileItems.filter(
3308
- (item) => !this.uploadQueue.some((q) => q.id === item.id)
3309
- );
3310
- this.uploadQueue.push(...newItems);
3311
- this.processUploadQueue();
3312
- }
3313
- /**
3314
- * 处理上传队列(支持并发)
3315
- */
3316
- processUploadQueue() {
3317
- while (this.uploadQueue.length > 0 && this.activeUploads < this.concurrentLimit) {
3318
- const fileItem = this.uploadQueue.shift();
3319
- if (fileItem.status !== "pending") {
3320
- continue;
3321
- }
3322
- this.activeUploads++;
3323
- this.uploadSingleFile(fileItem).finally(() => {
3324
- this.activeUploads--;
3325
- this.processUploadQueue();
3326
- });
3327
- }
3328
- }
3329
3363
  /**
3330
3364
  * 单个文件分片上传
3331
3365
  * @param fileItem
3332
3366
  */
3333
3367
  async uploadSingleFile(fileItem) {
3334
- var _a, _b, _c, _d, _e, _f, _g, _h;
3368
+ var _a, _b, _c, _d, _e, _f;
3335
3369
  fileItem.status = "uploading";
3336
3370
  fileItem.progress = 0;
3337
3371
  this.isUploading = true;
@@ -3341,16 +3375,13 @@ class ImportDialogUploader {
3341
3375
  fileItem.status = "success";
3342
3376
  fileItem.progress = 100;
3343
3377
  (_d = (_c = this.callbacks).onUploadSuccess) == null ? void 0 : _d.call(_c, fileItem, fileItem.response);
3378
+ return fileItem.response;
3344
3379
  } catch (error) {
3345
3380
  fileItem.status = "error";
3346
3381
  fileItem.errorMessage = error instanceof Error ? error.message : "上传失败";
3347
3382
  (_f = (_e = this.callbacks).onUploadError) == null ? void 0 : _f.call(_e, fileItem, error);
3383
+ throw error;
3348
3384
  }
3349
- this.isUploading = this.uploadFileList.some(
3350
- (f) => f.status === "uploading"
3351
- );
3352
- (_h = (_g = this.callbacks).onUpdate) == null ? void 0 : _h.call(_g);
3353
- this.updateOverallProgress();
3354
3385
  }
3355
3386
  /**
3356
3387
  * 分片上传
@@ -3362,21 +3393,32 @@ class ImportDialogUploader {
3362
3393
  return await this.chunkedUploader.upload(fileItem);
3363
3394
  }
3364
3395
  /**
3365
- * 手动触发分片上传(仅用于分片上传场景)
3396
+ * 手动触发上传(用于延迟上传场景)
3397
+ * 分片上传:直接调用 uploadSingleFile 并等待完成
3398
+ * 普通上传:已在选择文件时通过 customUpload 处理完成
3366
3399
  */
3367
3400
  async startUpload() {
3368
- if (this.shouldUseChunkedUpload()) {
3369
- await this.startChunkedUploadFiles();
3401
+ if (!this.shouldUseChunkedUpload()) {
3402
+ return;
3370
3403
  }
3371
- }
3372
- /**
3373
- * 启动分片上传
3374
- */
3375
- async startChunkedUploadFiles() {
3376
3404
  const pendingFiles = this.uploadFileList.filter(
3377
3405
  (f) => f.status === "pending"
3378
3406
  );
3379
- this.enqueueUpload(pendingFiles);
3407
+ if (pendingFiles.length === 0) {
3408
+ return;
3409
+ }
3410
+ const results = [];
3411
+ for (const fileItem of pendingFiles) {
3412
+ try {
3413
+ const result = await this.uploadSingleFile(fileItem);
3414
+ if (result) {
3415
+ results.push(result);
3416
+ }
3417
+ } catch (error) {
3418
+ console.error(`文件 ${fileItem.file.name} 上传失败:`, error);
3419
+ }
3420
+ }
3421
+ return results;
3380
3422
  }
3381
3423
  /**
3382
3424
  * 暂停上传(仅分片上传支持)
@@ -3398,8 +3440,6 @@ class ImportDialogUploader {
3398
3440
  cancelUpload() {
3399
3441
  var _a, _b, _c;
3400
3442
  (_a = this.chunkedUploader) == null ? void 0 : _a.cancel();
3401
- this.uploadQueue = [];
3402
- this.activeUploads = 0;
3403
3443
  this.isUploading = false;
3404
3444
  this.uploadMessage = "上传已取消";
3405
3445
  this.uploadMessageType = "info";
@@ -3969,7 +4009,8 @@ const _ImportDialog = class _ImportDialog {
3969
4009
  this.updateModal();
3970
4010
  }
3971
4011
  try {
3972
- await this.uploader.startUpload();
4012
+ const chunkResult = await this.uploader.startUpload();
4013
+ console.log("[分片上传] 分片上传结果:", chunkResult);
3973
4014
  } catch (error) {
3974
4015
  console.error("[ImportDialog] 上传失败:", error);
3975
4016
  this.showMessage("上传失败,请重试", "error");