This commit is contained in:
oneao committed 2026-04-27 17:26:15 +08:00
1 parent 04491e14a3
commit 12fdf320c2
12 files changed
+2493 -824

No files matched your search

@@ -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
<div class="task-dock">
<div class="dock-header">
<span class="title">Task Running</span>
<div class="dock-actions">
<button title="minimize">−</button>
<button title="close">×</button>
</div>
</div>
<div class="dock-body">
<div class="progress-line">
<span class="count">3 / 10</span>
<span class="percent">30%</span>
</div>
<div class="task-name">report.pdf</div>
<div class="task-type">download / upload / custom</div>
<div class="bar">
<div class="bar-inner"></div>
</div>
<div class="task-result">
Total: xxx | Success: xxx | Fail: xxx
</div>
</div>
</div>
```
### 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 小时)
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12.586 12.586L19 19M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z"/></svg>

Before

Width:  |  Height:  |  Size: 466 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11v6m4-6v6m5-11v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>

Before

Width:  |  Height:  |  Size: 405 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 15V3m9 12v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10l5 5l5-5"/></g></svg>

Before

Width:  |  Height:  |  Size: 386 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v12m5-7l-5-5l-5 5m14 7v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg>

Before

Width:  |  Height:  |  Size: 368 B

+343 -98
View File
@@ -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;
}
File diff suppressed because it is too large. Load diff
+138 -12
View File
@@ -23,16 +23,41 @@
align-items: center;
justify-content: center;
}
.button-group {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
.button-group button {
padding: 8px 16px;
border: none;
border-radius: 4px;
background: #5D87FF;
color: white;
cursor: pointer;
font-size: 14px;
}
.button-group button:hover {
background: #4a6fcf;
}
</style>
</head>
<body>
<div id="app">
<button id="reloadBtn">重新加载文件</button>
<button id="reloadBtn2">重新加载文件2</button>
<div class="button-group">
<button id="reloadBtn">加载文件组1</button>
<button id="reloadBtn2">加载文件组2</button>
<button id="addFileBtn">添加文件</button>
<button id="clearBtn">清空选择</button>
<button id="destroyBtn">销毁组件</button>
</div>
<div style="height: 600px;width: 400px;">
<div style="height: 600px;width: 500px;">
<div id="fileContainer"></div>
</div>
</div>
@@ -44,32 +69,133 @@
data: [
{ name: 'test.jar', size: 1024000, uploadDate: '2024-01-15T10:30:00', url: 'http://118.89.70.199:9000/test/XI26033384.rar' },
],
permissions: {
globalPermission: {
select: true,
upload: true,
download: true,
delete: true,
view: true
},
onUpload: function () {
console.log('Upload clicked');
alert('上传功能');
onUpload: function (pendingFiles) {
console.log('上传文件:', pendingFiles);
alert('上传功能,共 ' + pendingFiles.length + ' 个文件待上传');
},
onDelete: function (files, callback) {
console.log('删除文件:', files);
if (confirm('确定要删除 ' + files.length + ' 个文件吗?')) {
callback(true);
} else {
callback(false);
}
},
onPreview: function (files) {
console.log('预览文件:', files);
alert('预览文件: ' + files[0].name);
},
onSelect: function (files) {
console.log('选择文件:', files);
},
getActionMenu: function (file) {
const menuItems = [];
menuItems.push({
title: '审批',
onClick: function (f) {
console.log('审批文件:', f.name);
alert('审批功能:' + f.name);
}
});
menuItems.push({
title: '修改',
onClick: function (f) {
console.log('修改文件:', f.name);
alert('修改功能:' + f.name);
}
});
menuItems.push({
title: '重命名',
onClick: function (f) {
console.log('重命名文件:', f.name);
const newName = prompt('请输入新文件名:', f.name);
if (newName && newName !== f.name) {
console.log('文件已重命名为:', newName);
}
}
});
menuItems.push({
title: '复制',
disabled: false,
onClick: function (f) {
console.log('复制文件:', f.name);
alert('复制功能:' + f.name);
}
});
menuItems.push({
title: '移动到文件夹',
disabled: false,
onClick: function (f) {
console.log('移动文件:', f.name);
alert('移动功能:' + f.name);
}
});
menuItems.push({
title: '分享',
disabled: false,
onClick: function (f) {
console.log('分享文件:', f.name);
alert('分享功能:' + f.name);
}
});
menuItems.push({
title: '历史版本',
disabled: false,
onClick: function (f) {
console.log('查看历史版本:', f.name);
alert('历史版本功能:' + f.name);
}
});
return menuItems;
}
});
$('#reloadBtn').click(function () {
file.loadFiles([
{ name: '测试文档1.pdf', uploadDate: '2024-01-15T10:30:00', url: '' },
{ name: 'test.png', size: 1024000, uploadDate: '2024-01-15T10:30:00', url: 'http://118.89.70.199:9000/test/DC2A4692147D10C9C7B48A7EA29BCBA8.jpg' },
file.setFiles([
{ name: '测试文档1.pdf', size: 2048000, uploadDate: '2024-01-15T10:30:00', url: '' },
{ name: 'test.png', size: 1024000, uploadDate: '2024-01-15T10:30:00', url: 'http://118.89.70.:9000/test/DC2A4692147D10C9C7B48A7EA29BCBA8.jpg' },
{ name: '项目报告.docx', size: 524288, uploadDate: '2024-02-20T14:45:00', url: 'http://118.89.70.199:9000/test/report.docx' },
]);
});
$('#reloadBtn2').click(function () {
file.loadFiles([
{ name: '测试文档2.pdf', size: 1024000, uploadDate: '2024-01-15T10:30:00', url: '' },
file.setFiles([
{ name: '测试文档2.pdf', size: 4096000, uploadDate: '2024-01-15T10:30:00', url: '' },
{ name: '项目报告2.docx', size: 524288, uploadDate: '2024-02-20T14:45:00', url: '' },
{ name: '数据表.xlsx', size: 1572864, uploadDate: '2024-03-01T09:00:00', url: 'http://118.89.70.199:9000/test/data.xlsx' },
{ name: '演示文稿.pptx', size: 3145728, uploadDate: '2024-03-05T16:30:00', url: '' },
]);
});
$('#addFileBtn').click(function () {
file.$btnSelect.click();
});
$('#clearBtn').click(function () {
file.updateState({ selectedFiles: [] });
});
$('#destroyBtn').click(function () {
if (confirm('确定要销毁组件吗?')) {
file.destroy();
$('#fileContainer').html('<p style="text-align:center;padding:50px;color:#999;">组件已销毁</p>');
}
});
});
</script>
-3
View File
@@ -1,3 +0,0 @@
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
//# sourceMappingURL=FileSaver.min.js.map
+205
View File
@@ -0,0 +1,205 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Download Progress UI Comparison</title>
<style>
/* =========================
Base Layout
========================= */
body {
margin: 0;
font-family: Arial;
background: #f5f5f5;
}
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.header,
.footer {
padding: 12px;
background: #fff;
border-bottom: 1px solid #eee;
}
.footer {
border-top: 1px solid #eee;
margin-top: auto;
}
.content {
flex: 1;
padding: 16px;
}
/* =========================
🔴 方案 A:嵌入式进度条
========================= */
.embedded-bar {
background: #fff7e6;
border: 1px solid #ffe58f;
padding: 10px;
border-radius: 6px;
margin-bottom: 12px;
}
.embedded-bar .row {
display: flex;
gap: 10px;
align-items: center;
font-size: 13px;
}
.embedded-bar .actions {
margin-top: 8px;
display: flex;
gap: 8px;
}
.embedded-bar button {
border: 1px solid #ddd;
background: #fff;
padding: 4px 8px;
cursor: pointer;
}
/* =========================
🟢 方案 B:浮层 Dock(推荐)
========================= */
.download-dock {
position: fixed;
right: 20px;
bottom: 20px;
width: 320px;
background: #fff;
border-radius: 10px;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
overflow: hidden;
z-index: 9999;
}
.dock-header {
display: flex;
justify-content: space-between;
padding: 10px 12px;
background: #f6f6f6;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.dock-actions button {
border: none;
background: transparent;
cursor: pointer;
font-size: 16px;
}
.dock-body {
padding: 12px;
}
.progress-line {
display: flex;
justify-content: space-between;
font-size: 13px;
margin-bottom: 8px;
}
.current-file {
font-size: 12px;
color: #666;
margin-bottom: 10px;
}
.bar {
height: 6px;
background: #eee;
border-radius: 3px;
overflow: hidden;
}
.bar-inner {
width: 45%;
height: 100%;
background: #faad14;
}
</style>
</head>
<body>
<div class="page">
<div class="header">File Manager Header</div>
<div class="content">
<!-- =========================
🔴 方案 A:嵌入式
========================== -->
<div class="embedded-bar">
<div class="row">
<span>Downloading</span>
<span>3 / 10</span>
<span>report.pdf</span>
</div>
<div class="actions">
<button>Hide</button>
<button>Cancel</button>
</div>
</div>
<div>
<p>File list area...</p>
<p>Scroll content...</p>
<p>Scroll content...</p>
<p>Scroll content...</p>
</div>
</div>
<div class="footer">Footer</div>
</div>
<!-- =========================
🟢 方案 B:浮层 Dock
========================= -->
<div class="download-dock">
<div class="dock-header">
<span>Downloading</span>
<div class="dock-actions">
<button title="minimize">−</button>
<button title="close">×</button>
</div>
</div>
<div class="dock-body">
<div class="progress-line">
<span>3 / 10</span>
<span>30%</span>
</div>
<div class="current-file">
report.pdf
</div>
<div class="bar">
<div class="bar-inner"></div>
</div>
</div>
</div>
</body>
</html>