-
首页
+
分类区域(可扩展)
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
最近内容
-
任务:优化UI设计
-
消息:项目讨论
-
-
-
-
-
-
用户1:你好
-
用户2:项目OK
-
用户3:收到
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
选择空间
-
-
-
-
-
-
-
-
-
-
-
diff --git a/code/file-preview/.trae/documents/task_dock_refactor_plan.md b/code/file-preview/.trae/documents/task_dock_refactor_plan.md
new file mode 100644
index 00000000..74651d14
--- /dev/null
+++ b/code/file-preview/.trae/documents/task_dock_refactor_plan.md
@@ -0,0 +1,272 @@
+# Task Dock 重构计划
+
+## 1. 项目分析
+
+### 1.1 当前代码结构
+
+* **index.js**: 包含 G3File 构造函数和所有核心逻辑
+
+* **index.css**: 包含所有样式定义
+
+* **libs/**: 包含 FileSaver 和 JSZip 库
+
+### 1.2 当前下载进度条实现
+
+* 位于 `g3-file-container` 内部
+
+* 固定在顶部的 `download-progress-bar` 元素
+
+* 仅支持下载任务
+
+* 显示简单的进度信息
+
+## 2. 重构目标
+
+### 2.1 核心目标
+
+1. **移除 download-progress-bar**
+2. **新增全局 task dock**(右下角浮层)
+3. **支持所有异步任务类型**(不限定 download/upload)
+
+### 2.2 功能要求
+
+1. **全局任务中心**:fixed 右下角浮层
+2. **通用任务模型**:id, name, type, progress, status
+3. **批量任务支持**:多个任务同时运行,批量更新进度
+4. **结果汇总**:总任务数、成功数、失败数
+5. **UI Lock**:任务运行时禁止页面其他操作
+6. **交互要求**:close,实时进度更新
+
+## 3. 实现计划
+
+### 3.1 文件修改
+
+#### 3.1.1 index.js 修改
+
+1. **移除 download-progress-bar 相关代码**:
+
+ * 删除 `showDownloadProgress` 方法
+
+ * 删除 `updateDownloadProgress` 方法
+
+ * 删除 `completeDownloadProgress` 方法
+
+ * 删除 `$downloadProgressBar` 变量
+
+2. **新增 Task 管理功能**:
+
+ * 新增 `tasks` 数组存储任务列表
+
+ * 新增 `taskStats` 对象存储统计信息
+
+ * 新增 `addTask` 方法
+
+ * 新增 `updateTask` 方法
+
+ * 新增 `finishTask` 方法
+
+ * 新增 `updateTaskStats` 方法
+
+ * 新增 `clearTasks` 方法
+
+3. **新增 Task Dock 管理**:
+
+ * 新增 `renderTaskDock` 方法
+
+ * 新增 `updateTaskDock` 方法
+
+ * 新增 `showTaskDock` 方法
+
+ * 新增 `hideTaskDock` 方法
+
+ * 新增 `minimizeTaskDock` 方法
+
+4. **新增 UI Lock 功能**:
+
+ * 新增 `lockUI` 方法
+
+ * 新增 `unlockUI` 方法
+
+ * 新增 `isUILocked` 方法
+
+5. **修改现有方法**:
+
+ * 修改 `internalDownloadBatch` 方法使用新的任务管理
+
+ * 修改 `handleDownload` 方法支持任务管理
+
+#### 3.1.2 index.css 修改
+
+1. **移除 download-progress-bar 样式**
+2. **新增 task-dock 相关样式**:
+
+ * `.task-dock`:基础容器样式
+
+ * `.dock-header`:头部样式
+
+ * `.dock-body`:身体样式
+
+ * `.progress-line`:进度行样式
+
+ * `.task-name`:任务名称样式
+
+ * `.task-type`:任务类型样式
+
+ * `.bar`:进度条样式
+
+ * `.bar-inner`:进度条内部样式
+
+ * `.task-result`:结果汇总样式
+
+ * `.ui-lock`:UI 锁定遮罩样式
+
+### 3.2 实现步骤
+
+1. **步骤 1:修改 CSS 样式**
+
+ * 移除 `download-progress-bar` 相关样式
+
+ * 添加 `task-dock` 相关样式
+
+ * 添加 `ui-lock` 遮罩样式
+
+2. **步骤 2:修改 HTML 结构**
+
+ * 从 `render` 方法中移除 `download-progress-bar` 元素
+
+ * 添加 `task-dock` 元素到页面
+
+3. **步骤 3:实现 Task 管理功能**
+
+ * 添加任务管理相关变量
+
+ * 实现任务管理方法
+
+4. **步骤 4:实现 Task Dock UI 管理**
+
+ * 实现 dock 渲染和更新方法
+
+ * 实现 dock 显示/隐藏/最小化方法
+
+5. **步骤 5:实现 UI Lock 功能**
+
+ * 实现 UI 锁定和解锁方法
+
+6. **步骤 6:修改现有方法**
+
+ * 修改 `internalDownloadBatch` 方法使用新的任务管理
+
+ * 确保所有异步任务都通过任务中心管理
+
+7. **步骤 7:测试验证**
+
+ * 测试批量下载功能
+
+ * 测试任务状态更新
+
+ * 测试 UI Lock 功能
+
+ * 测试交互功能(close、minimize)
+
+## 4. 技术实现细节
+
+### 4.1 任务模型
+
+```javascript
+{
+ id: "task_123",
+ name: "report.pdf",
+ type: "download", // download / upload / custom
+ progress: 0, // 0-100
+ status: "running" // running / success / fail / paused
+}
+```
+
+### 4.2 统计模型
+
+```javascript
+{
+ total: 10,
+ success: 7,
+ fail: 3
+}
+```
+
+### 4.3 DOM 结构
+
+```html
+
+
+
+
+ 3 / 10
+ 30%
+
+
report.pdf
+
download / upload / custom
+
+
+ Total: xxx | Success: xxx | Fail: xxx
+
+
+
+```
+
+### 4.4 样式设计
+
+* **位置**:fixed 定位在右下角
+
+* **大小**:固定宽度,高度自适应
+
+* **颜色**:使用与现有设计一致的配色
+
+* **动画**:平滑的显示/隐藏动画
+
+* **响应式**:适配不同屏幕尺寸
+
+## 5. 风险评估
+
+### 5.1 潜在风险
+
+1. **兼容性问题**:确保新功能在所有浏览器中正常工作
+2. **性能问题**:确保任务管理不会影响页面性能
+3. **用户体验**:确保新的任务中心比原有的进度条更直观易用
+
+### 5.2 风险缓解措施
+
+1. **兼容性测试**:在主流浏览器中测试功能
+2. **性能优化**:使用防抖和节流技术减少 DOM 更新
+3. **用户测试**:确保新的任务中心操作流畅直观
+
+## 6. 预期效果
+
+1. **功能增强**:支持多种任务类型,提供更详细的任务信息
+2. **用户体验**:右下角浮层不干扰主界面操作
+3. **可扩展性**:易于添加新的任务类型和功能
+4. **代码质量**:UI 与逻辑分离,代码结构清晰
+
+## 7. 时间估计
+
+* **CSS 样式修改**:30 分钟
+
+* **HTML 结构修改**:15 分钟
+
+* **Task 管理功能实现**:60 分钟
+
+* **Task Dock UI 实现**:45 分钟
+
+* **UI Lock 功能实现**:30 分钟
+
+* **现有方法修改**:30 分钟
+
+* **测试验证**:45 分钟
+
+**总时间**:约 255 分钟(4.25 小时)
diff --git a/code/file-preview/custom-file/icons/Choose.svg b/code/file-preview/custom-file/icons/Choose.svg
deleted file mode 100644
index 07c54d2b..00000000
--- a/code/file-preview/custom-file/icons/Choose.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/code/file-preview/custom-file/icons/Delete.svg b/code/file-preview/custom-file/icons/Delete.svg
deleted file mode 100644
index b72f6eef..00000000
--- a/code/file-preview/custom-file/icons/Delete.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/code/file-preview/custom-file/icons/Download.svg b/code/file-preview/custom-file/icons/Download.svg
deleted file mode 100644
index 1090d9df..00000000
--- a/code/file-preview/custom-file/icons/Download.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/code/file-preview/custom-file/icons/Upload.svg b/code/file-preview/custom-file/icons/Upload.svg
deleted file mode 100644
index 4d792887..00000000
--- a/code/file-preview/custom-file/icons/Upload.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/code/file-preview/custom-file/index.css b/code/file-preview/custom-file/index.css
index 3c9d611f..bb0b6c7d 100644
--- a/code/file-preview/custom-file/index.css
+++ b/code/file-preview/custom-file/index.css
@@ -9,6 +9,7 @@
overflow: hidden;
}
+/* 头部样式 */
.g3-file-container .header {
display: flex;
align-items: center;
@@ -19,23 +20,30 @@
border-bottom: 1px solid #eef0f2;
}
+/* 主要内容区域 */
.g3-file-container .main {
flex: 1;
min-height: 0;
+ padding: 4px 0px;
overflow: auto;
display: flex;
flex-wrap: wrap;
- align-items: flex-start;
+ align-content: flex-start;
+
+ border-left: 1px solid #eef0f2;
+ border-right: 1px solid #eef0f2;
+
/* justify-content: center; */
}
.g3-file-container .main > * {
- margin: 7px;
+ margin: 10px;
}
+/* 空状态提示 */
.g3-file-container .empty-tip {
flex: 1;
min-height: 0;
@@ -47,6 +55,7 @@
color: #999;
}
+/* 底部样式 */
.g3-file-container .footer {
display: flex;
align-items: center;
@@ -55,7 +64,7 @@
padding: 10px 14px;
background: #fafbfc;
- border-top: 1px solid #eef0f2;
+ border-top: 1px solid #eee;
}
.g3-file-container .header,
@@ -93,6 +102,7 @@
.g3-file-container .check-all span {
margin-left: 4px;
+ color: #333;
}
/* 按钮 */
@@ -140,50 +150,81 @@
background: #ff4d4f;
}
-.g3-file-container .file-item {
- width: calc(50% - 20px);
+/* 文件项样式 */
+.g3-file-container .g3-file-item {
+ width: calc(50% - 26px);
position: relative;
- overflow: hidden;
cursor: pointer;
- transition: all 0.18s ease;
border: 1px solid #eef0f2;
- border-radius: 6px;
+ border-radius: 8px;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
-.g3-file-container .file-item:hover {
- border-color: #d6e4ff;
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
- transform: translateY(-2px);
+.g3-file-container .g3-file-item:hover {
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
}
-.file-item .file-preview {
- height: 120px;
+/* 文件预览 */
+.g3-file-item .g3-file-preview {
+ height: 100px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
+ background-color: #fafbfc;
+}
+
+.g3-file-item .g3-file-preview .g3-file-img {
+ width: 100%;
+ height: 100%;
+}
+
+.g3-file-item .g3-file-preview svg {
+ height: 86px;
+ width: 100%;
+}
+
+/* 图片容器样式 */
+.g3-file-item .g3-file-preview .g3-img-container {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
-.file-item .file-preview svg,
-.file-item .file-preview img {
+/* 图片错误状态 */
+.g3-file-item .g3-file-preview .g3-img-container.is-error .g3-img-error {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ background-color: #f0f2f5;
+}
+
+.g3-file-item .g3-file-preview .g3-img-container .g3-img-error {
+ display: none;
+ position: absolute;
+ top: 0;
+ left: 0;
width: 100%;
height: 100%;
}
-.file-item .file-checkbox {
- position: absolute;
- top: 10px;
- left: 10px;
- width: 16px;
- height: 16px;
+.g3-file-item .g3-file-preview .g3-img-container .g3-img-error svg {
+ width: 48px;
+ height: 48px;
+ color: #999;
}
-.file-item .file-info {
- padding: 10px 10px 12px;
+/* 文件信息 */
+.g3-file-item .g3-file-info {
+ padding: 8px;
font-size: 12px;
color: #999;
line-height: 1.4;
@@ -196,125 +237,129 @@
box-sizing: border-box;
}
-.file-item .file-info span {
+.g3-file-item .g3-file-info span {
display: block;
width: 100%;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+ font-size: 12px;
+ color: #888;
}
-.file-item .file-info .file-name {
+.g3-file-item .g3-file-info .g3-file-name {
font-size: 13px;
- color: #1f2937;
- font-weight: 600;
+ color: #000000;
}
-.file-item .file-actions {
+/* 文件操作按钮 */
+.g3-file-item .g3-file-actions {
display: flex;
align-items: center;
justify-content: flex-end;
- margin-bottom: 8px;
- margin-right: 8px;
+
+ overflow: hidden;
+ border-top: 1px solid #f0f2f5;
}
-.file-item .file-action {
- width: 24px;
- height: 24px;
-
+.g3-file-item .g3-file-action {
+ padding: 8px 2px;
+ flex: 1;
display: flex;
align-items: center;
justify-content: center;
-
- border-radius: 6px;
-
- /* 👇 稍微更明显 */
- background: rgba(0, 0, 0, 0.06);
-
- margin-left: 6px;
-
- color: rgba(0, 0, 0, 0.6);
+ gap: 4px;
cursor: pointer;
- transition: all 0.2s ease;
+ font-size: 12px;
+ border-right: 1px solid #f0f2f5;
}
-/* hover:明显增强 */
-.file-item .file-action:hover {
+.g3-file-item .g3-file-action:hover {
+ background-color: #f5f6f8;
+ color: #333;
+}
+
+.g3-file-item .g3-file-action:active {
background: rgba(22, 93, 255, 0.12);
- color: #165dff;
}
-/* active:点击反馈 */
-.file-item .file-action:active {
- background: rgba(22, 93, 255, 0.18);
- transform: scale(0.96);
-}
-
-.file-item .file-action.is-disabled {
+.g3-file-item .g3-file-action.is-disabled {
opacity: 0.4;
pointer-events: none;
cursor: not-allowed;
}
-.g3-download-modal {
+.g3-file-item .g3-file-action:last-child {
+ border-right: none;
+}
+
+.g3-file-item .g3-file-action svg {
+ width: 20px;
+ height: 20px;
+ color: #666;
+}
+
+/* 复选框样式 */
+.g3-file-item .g3-file-checkbox {
position: absolute;
- inset: 0;
- z-index: 9999;
+ top: 8px;
+ left: 8px;
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+ opacity: 0;
+ z-index: 10;
}
-.g3-download-mask {
+/* 自定义复选框样式 */
+.g3-file-item .g3-file-checkbox + .g3-checkbox-label {
position: absolute;
- inset: 0;
- background: rgba(0, 0, 0, 0.4);
+ top: 8px;
+ left: 8px;
+ width: 16px;
+ height: 16px;
+ border: 1px solid #d9d9d9;
+ border-radius: 2px;
+ background: white;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ z-index: 5;
}
-.g3-download-box {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #fff;
- padding: 20px;
- border-radius: 10px;
- width: 260px;
- text-align: center;
-}
-
-.g3-download-bar {
- height: 6px;
- background: #eee;
- border-radius: 4px;
- margin-top: 10px;
- overflow: hidden;
-}
-
-.g3-download-bar-inner {
- height: 100%;
- width: 0%;
- background: #4caf50;
- transition: width 0.2s;
-}
-
-/* 文件项选中样式 */
-.g3-file-container .file-item.file-item-selected {
+.g3-file-item .g3-file-checkbox:checked + .g3-checkbox-label {
+ background: #165dff;
border-color: #165dff;
- box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.2);
- background: rgba(22, 93, 255, 0.05);
}
-.g3-file-container .file-item.file-item-selected:hover {
+.g3-file-item .g3-file-checkbox:checked + .g3-checkbox-label::after {
+ content: "";
+ position: absolute;
+ top: 2px;
+ left: 5px;
+ width: 4px;
+ height: 8px;
+ border: solid white;
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+}
+
+.g3-file-item .g3-file-checkbox:hover + .g3-checkbox-label {
border-color: #165dff;
- box-shadow: 0 6px 18px rgba(22, 93, 255, 0.2);
- transform: translateY(-2px);
+ box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
+}
+
+.g3-file-item .g3-file-checkbox:disabled + .g3-checkbox-label {
+ opacity: 0.4;
+ cursor: not-allowed;
}
/* 未上传标记 */
-.file-item .file-pending-badge {
+.g3-file-item .g3-file-pending-badge {
position: absolute;
- top: 10px;
- right: 10px;
+ top: 6px;
+ right: 6px;
background: #ff9800;
color: white;
font-size: 10px;
@@ -322,3 +367,203 @@
border-radius: 10px;
z-index: 1;
}
+
+/* 浮动删除按钮 */
+.g3-file-container .g3-file-delete-btn {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: #ebebeb;
+ color: #666;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ z-index: 100;
+ font-size: 12px;
+ border: 1px solid #e8e8e8;
+
+ transition: all 0.2s ease;
+}
+
+.g3-file-container .g3-file-delete-btn:hover {
+ background: #ff4d4f;
+ color: white;
+}
+
+.g3-file-container .g3-file-item .g3-file-delete-btn.is-disabled {
+ opacity: 0.4;
+ pointer-events: none;
+ cursor: not-allowed;
+}
+
+/* 全局菜单 */
+.g3-global-menu {
+ position: absolute;
+ z-index: 9999;
+
+ width: 160px;
+ background: #fff;
+ border: 1px solid #eee;
+ border-radius: 8px;
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
+ position: fixed; /* ⭐必须,不然一定会错位 */
+
+ visibility: hidden;
+ pointer-events: none;
+}
+
+.g3-global-menu.is-open {
+ visibility: visible;
+ pointer-events: auto;
+}
+
+/* 更多菜单项样式 */
+.g3-global-menu .g3-action-menu-item {
+ padding: 8px 16px;
+ font-size: 14px;
+ color: #333;
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+}
+
+.g3-global-menu .g3-action-menu-item:hover {
+ background-color: #f5f5f5;
+}
+
+.g3-global-menu .g3-action-menu-item:active {
+ background-color: #e8e8e8;
+}
+
+/* Task Dock 样式 */
+.task-dock {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ width: 320px;
+ background: #ffffff;
+ border: 1px solid #eef0f2;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ z-index: 9999;
+ display: none;
+ animation: slideIn 0.3s ease-out;
+}
+
+@keyframes slideIn {
+ from {
+ transform: translateX(100%) translateY(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0) translateY(0);
+ opacity: 1;
+ }
+}
+
+.task-dock .dock-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+ background: #fafbfc;
+ border-bottom: 1px solid #eef0f2;
+ border-radius: 8px 8px 0 0;
+}
+
+.task-dock .dock-header .title {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+}
+
+.task-dock .dock-actions {
+ display: flex;
+ gap: 8px;
+}
+
+.task-dock .dock-actions button {
+ width: 24px;
+ height: 24px;
+ border: none;
+ background: transparent;
+ color: #666;
+ font-size: 16px;
+ cursor: pointer;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+}
+
+.task-dock .dock-actions button:hover {
+ background: #f0f2f5;
+ color: #333;
+}
+
+.task-dock .dock-body {
+ padding: 16px;
+}
+
+.task-dock .progress-line {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ font-size: 14px;
+ color: #666;
+}
+
+.task-dock .task-name {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 4px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.task-dock .task-type {
+ font-size: 12px;
+ color: #999;
+ margin-bottom: 12px;
+}
+
+.task-dock .bar {
+ width: 100%;
+ height: 6px;
+ background: #f0f2f5;
+ border-radius: 3px;
+ overflow: hidden;
+ margin-bottom: 12px;
+}
+
+.task-dock .bar .bar-inner {
+ height: 100%;
+ background: #165dff;
+ border-radius: 3px;
+ transition: width 0.3s ease;
+}
+
+.task-dock .task-result {
+ font-size: 12px;
+ color: #666;
+ text-align: right;
+}
+
+/* UI Lock 样式 */
+.ui-lock {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.05);
+ z-index: 9998;
+ display: none;
+}
diff --git a/code/file-preview/custom-file/index.js b/code/file-preview/custom-file/index.js
index c8dc4cb0..c92133aa 100644
--- a/code/file-preview/custom-file/index.js
+++ b/code/file-preview/custom-file/index.js
@@ -1,12 +1,151 @@
(function ($) {
'use strict';
- var G3File = {
- files: [],
- selectedFiles: new Set(),
+
+ // =====================
+ // G3File 构造函数
+ // =====================
+ function G3File(container, options) {
+ // 实例隔离
+ this.$container = $(container);
+ this.options = $.extend({}, this.defaults, options);
+ this.instanceId = this.generateUniqueId();
+ this.files = [];
+ this.selectedFiles = new Set();
+ this.objectUrls = new Map();
+ this.language = this.languages[this.options.language] || this.languages['zh-CN'];
+
+ this.actionMenuState = {
+ open: false,
+ fileId: null,
+ anchorEl: null,
+ items: []
+ };
+
+ // 任务管理
+ this.tasks = [];
+ this.taskStats = {
+ total: 0,
+ success: 0,
+ fail: 0
+ };
+
+ this.init();
+ }
+
+ // =====================
+ // 原型方法
+ // =====================
+ G3File.prototype = {
+ // =====================
+ // 默认配置
+ // =====================
+ defaults: {
+ data: [],
+ onDelete: null,
+ onDownload: null,
+ onSelect: null,
+ onUpload: null,
+ onPreview: null,
+ getActionMenu: null,
+ language: 'zh-CN',
+ maxFileSize: 10 * 1024 * 1024,
+ // 全局权限(支持对象或函数)
+ globalPermission: {
+ select: true,
+ upload: true,
+ download: true,
+ delete: true,
+ view: true
+ },
+ // 单文件权限解析函数(仅支持函数)
+ filePermissionResolver: null
+ },
+
+ // =====================
+ // 多语言
+ // =====================
+ languages: {
+ 'zh-CN': {
+ selectAll: '全选',
+ download: '下载',
+ downloadBatch: "批量下载",
+ delete: '删除',
+ upload: '上传',
+ select: '选择',
+ more: '更多',
+ confirmDelete: '确定要删除选中的 {count} 个文件吗?',
+ downloading: '准备下载 {count} 个文件',
+ deleting: '删除中...',
+ name: '名称',
+ size: '大小',
+ date: '日期',
+ pending: '未上传',
+ selectFiles: '选择文件',
+ emptyTip1: '拖拽文件到这里 …',
+ emptyTip2: '支持多文件同时上传/下载',
+ emptyTip3: '支持粘贴图片上传',
+ fileSizeError: '文件大小超过限制',
+ preview: '预览',
+ downloadingStatus: '下载中:',
+ downloadingFile: '正在下载:',
+ downloadComplete: '下载完成',
+ downloadResult: '共{total}文件,{success}成功,{failed}失败',
+ close: '关闭'
+ },
+ 'en-US': {
+ selectAll: 'Select All',
+ download: 'Download',
+ downloadBatch: 'Batch Download',
+ delete: 'Delete',
+ upload: 'Upload',
+ select: 'Select',
+ more: 'More',
+ confirmDelete: 'Are you sure you want to delete {count} selected file(s)?',
+ downloading: 'Preparing to download {count} file(s)',
+ deleting: 'Deleting...',
+ name: 'Name',
+ size: 'Size',
+ date: 'Date',
+ pending: 'Pending upload',
+ selectFiles: 'Select Files',
+ emptyTip1: 'Drag files here ...',
+ emptyTip2: 'Supports multiple file upload/download',
+ emptyTip3: 'Supports pasting images to upload',
+ fileSizeError: 'File size exceeds limit',
+ preview: 'Preview',
+ downloadingStatus: 'Downloading:',
+ downloadingFile: 'Downloading:',
+ downloadComplete: 'Download complete',
+ downloadResult: 'Total {total} files, {success} succeeded, {failed} failed',
+ close: 'Close'
+ }
+ },
+
+ // =====================
+ // 静态icon
+ // =====================
+ staticIconMap: {
+ download: `
+
+ `,
+ delete: `
+
+ `,
+ select: `
+
+ `,
+ upload: `
+
+ `,
+ preview: `
+
`,
+ more: `
+
+ `
+ },
loadScripts: function (items, callback) {
- var self = this;
var remaining = items.length;
function done() {
@@ -25,7 +164,7 @@
// 防重复加载
var key = item.key;
- if (window[key + '_loading']) {
+ if (window[key + "_loading"]) {
var timer = setInterval(function () {
if (item.check && item.check()) {
clearInterval(timer);
@@ -35,19 +174,19 @@
return;
}
- window[key + '_loading'] = true;
+ window[key + "_loading"] = true;
- var script = document.createElement('script');
+ var script = document.createElement("script");
script.src = item.src;
script.onload = function () {
- window[key + '_loading'] = false;
+ window[key + "_loading"] = false;
done();
};
script.onerror = function () {
- window[key + '_loading'] = false;
- console.error(key + ' load failed');
+ window[key + "_loading"] = false;
+ console.error(key + " load failed");
done();
};
@@ -55,137 +194,44 @@
});
},
+
// =====================
// 初始化
// =====================
- init: function (containerId, options) {
+ init: function () {
var self = this;
- this.$container = $('#' + containerId);
- this.options = $.extend({}, this.defaults, options);
+ this.loadScripts(
+ [
+ {
+ key: "fileSaver",
+ src: "/custom-file/libs/FileSaver.min.js",
+ check: function () {
+ return typeof window.saveAs === "function";
+ },
+ },
+ {
+ key: "jsZip",
+ src: "/custom-file/libs/jszip.min.js",
+ check: function () {
+ return typeof window.JSZip === "function";
+ },
+ },
+ ],
+ function () {
+ self.render();
+ self.bindEvents();
+ self.updateUI();
- this.language = this.languages[this.options.language] || this.languages['zh-CN'];
- this.files = this.options.data || [];
-
- this.loadScripts([
- {
- key: 'fileSaver',
- src: '/custom-file/libs/FileSaver.min.js',
- check: function () {
- return typeof window.saveAs === 'function';
+ if (self.options.data && self.options.data.length) {
+ self.setFiles(self.options.data);
}
},
- {
- key: 'jsZip',
- src: '/custom-file/libs/jszip.min.js',
- check: function () {
- return typeof window.JSZip === 'function';
- }
- }
- ], function () {
- self.render();
- self.bindEvents();
- self.updatePermissions(self.options.permissions);
-
- if (self.options.data?.length) {
- self.loadFiles(self.options.data);
- }
- });
+ );
return this;
},
- // =====================
- // 默认配置
- // =====================
- defaults: {
- data: [],
- onDelete: null,
- onDownload: null,
- onSelect: null,
- onUpload: null,
- language: 'zh-CN',
- maxFileSize: 10 * 1024 * 1024, // 默认最大10MB
- permissions: {
- select: true,
- upload: true,
- download: true,
- delete: true,
- view: true
- }
- },
-
- // =====================
- // 多语言
- // =====================
- languages: {
- 'zh-CN': {
- selectAll: '全选',
- download: '批量下载',
- delete: '删除',
- upload: '上传',
- select: '选择',
- confirmDelete: '确定要删除选中的 {count} 个文件吗?',
- downloading: '准备下载 {count} 个文件',
- deleting: '删除中...',
- name: '名称',
- size: '大小',
- date: '日期',
- pending: '未上传',
- selectFiles: '选择文件',
- emptyTip1: '拖拽文件到这里 …',
- emptyTip2: '支持多文件同时上传/下载',
- emptyTip3: '支持粘贴图片上传',
- fileSizeError: '文件大小超过限制'
- },
- 'en-US': {
- selectAll: 'Select All',
- download: 'Batch Download',
- delete: 'Delete',
- upload: 'Upload',
- select: 'Select',
- confirmDelete: 'Are you sure to delete {count} selected files?',
- downloading: 'Preparing to download {count} files',
- deleting: 'Deleting...',
- name: 'Name',
- size: 'Size',
- date: 'Date',
- pending: 'Pending',
- selectFiles: 'Select Files',
- fileSizeError: 'File size exceeds limit'
- }
- },
-
- // =====================
- // 静态icon合计
- // =====================
- staticIconMap: {
- download: `
-
- `,
- delete: `
-
- `,
- select: `
-
- `,
- upload: `
-
- `,
- more: `
-
- `,
- pdf: `
-
- `,
- video: `
-
- `,
- default_file: `
-
- `
- },
-
// =====================
// 生成唯一ID
// =====================
@@ -198,16 +244,19 @@
// =====================
getFileIcon: function (filename) {
var ext = filename.split('.').pop().toLowerCase();
- return this.staticIconMap[ext] || this.staticIconMap['default_file'];
- },
+ var iconMap = {
+ pdf: '
',
+ png: '
',
+ jpg: '
',
+ default: '
'
+ };
- // =====================
- // 更新语言
- // =====================
- updateLanguage: function (language) {
- this.language = this.languages[language] || this.languages['zh-CN'];
- this.render();
- return this;
+ // 不做处理
+ if (this.isImageFile(filename)) {
+ return ''
+ }
+
+ return iconMap[ext] || iconMap.default;
},
// =====================
@@ -223,7 +272,7 @@