u
This commit is contained in:
1 parent
ae6ccad238
commit
b2d113db38
17 files changed
+3087
-1630
No files matched your search
@@ -0,0 +1,141 @@
|
||||
# G3File 左右布局改造计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户需要将 g3-file-container 的布局从原来的垂直布局改为左右布局:
|
||||
|
||||
**原布局:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ header │
|
||||
├─────────────────────────────────────┤
|
||||
│ main │
|
||||
├─────────────────────────────────────┤
|
||||
│ footer │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**新布局:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 左边区域 │ 右边区域 │
|
||||
│ ┌─────────────────────────────┐ │ ┌─────────────────┐ │
|
||||
│ │ header │ │ │ toolbar │ │ (10%)
|
||||
│ ├─────────────────────────────┤ │ └─────────────────┘ │
|
||||
│ │ main │ │ ┌─────────────────┐ │
|
||||
│ ├─────────────────────────────┤ │ │ preview │ │ (90%)
|
||||
│ │ footer │ │ │ area │ │
|
||||
│ └─────────────────────────────┘ │ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Toolbar 功能需求:**
|
||||
|
||||
* 上一个/下一个按钮(用于切换预览)
|
||||
|
||||
- 当前预览的文件名
|
||||
|
||||
- 顺序显示(当前索引/总数)
|
||||
|
||||
**预览区域:**
|
||||
|
||||
* 预览功能暂不实现,显示测试内容即可
|
||||
|
||||
## 修改方案
|
||||
|
||||
### 1. 修改 index.js
|
||||
|
||||
**需要修改的内容:**
|
||||
|
||||
* 在 `render()` 方法中添加右侧预览区域的 HTML 结构
|
||||
|
||||
* 添加预览相关的状态管理(当前预览索引、已上传文件列表)
|
||||
|
||||
* 添加预览区域的 DOM 引用
|
||||
|
||||
* 添加上下按钮的事件处理
|
||||
|
||||
**新增状态:**
|
||||
|
||||
```javascript
|
||||
this.previewIndex = 0; // 当前预览索引
|
||||
```
|
||||
|
||||
**新增 DOM 引用:**
|
||||
|
||||
```javascript
|
||||
this.$previewPanel = this.$container.find('.g3-file-preview-panel');
|
||||
this.$previewToolbar = this.$container.find('.g3-preview-toolbar');
|
||||
this.$previewContent = this.$container.find('.g3-preview-content');
|
||||
this.$btnPrev = this.$container.find('.preview-prev');
|
||||
this.$btnNext = this.$container.find('.preview-next');
|
||||
this.$previewInfo = this.$container.find('.preview-info');
|
||||
```
|
||||
|
||||
### 2. 修改 index.css
|
||||
|
||||
**需要修改的内容:**
|
||||
|
||||
* 修改 `.g3-file-container` 为横向 flex 布局
|
||||
|
||||
* 添加左侧区域样式 `.g3-file-left-panel`
|
||||
|
||||
* 添加右侧预览区域样式 `.g3-file-preview-panel`
|
||||
|
||||
* 添加 toolbar 样式 `.g3-preview-toolbar`
|
||||
|
||||
* 添加预览内容区域样式 `.g3-preview-content`
|
||||
|
||||
* 添加导航按钮样式
|
||||
|
||||
## 文件修改清单
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
| ------------------- | ---------------------------------- |
|
||||
| `g3-file/index.js` | 修改 render 方法添加预览区域HTML,添加预览相关状态和事件 |
|
||||
| `g3-file/index.css` | 修改容器布局,添加左右区域样式、toolbar 样式、预览区域样式 |
|
||||
|
||||
## 实现步骤
|
||||
|
||||
1. **修改 CSS 布局**
|
||||
|
||||
* 修改 `.g3-file-container` 为 `flex-direction: row`
|
||||
|
||||
* 添加左侧面板样式(占50%宽度)
|
||||
|
||||
* 添加右侧预览面板样式(占50%宽度)
|
||||
|
||||
* 添加 toolbar 和预览内容区域样式
|
||||
|
||||
2. **修改 JS 渲染**
|
||||
|
||||
* 在 render 方法中添加右侧预览区域 HTML
|
||||
|
||||
* 添加预览相关状态
|
||||
|
||||
* 添加上下按钮事件绑定
|
||||
|
||||
3. **添加辅助方法**
|
||||
|
||||
* `getUploadedFiles()` - 获取已上传的文件列表
|
||||
|
||||
* `updatePreview()` - 更新预览区域显示
|
||||
|
||||
## 风险评估
|
||||
|
||||
* 现有功能(文件上传、下载、删除)不受影响
|
||||
|
||||
* 预览功能暂不实现,仅显示测试内容
|
||||
|
||||
* 布局变化可能影响现有样式,需要仔细测试
|
||||
|
||||
## 测试要点
|
||||
|
||||
1. 布局是否正确显示为左右结构
|
||||
2. 左侧原有功能是否正常工作
|
||||
3. Toolbar 是否正确显示文件信息
|
||||
4. 上下按钮是否可点击(即使预览功能未实现)
|
||||
5. 预览区域是否正常显示测试内容
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
# G3File 预览区域布局修改计划
|
||||
|
||||
## 一、需求分析
|
||||
|
||||
根据用户需求,需要对 g3-file-container 进行以下修改:
|
||||
|
||||
1. **布局调整**:改为左右两栏布局
|
||||
- **左侧区域**:保持现有完整结构(header + main + footer)
|
||||
- **右侧区域**:新增预览区域(toolbar 10% + 预览内容区 90%)
|
||||
|
||||
2. **预览区域 Toolbar**:
|
||||
- 文件总数(仅统计已上传文件)
|
||||
- 当前预览文件名
|
||||
- 顺序导航按钮(上一个/下一个)
|
||||
|
||||
3. **预览规则**:
|
||||
- 只有 `status === 'uploaded'` 的文件才可预览
|
||||
- 预览总数只计算已上传文件
|
||||
|
||||
4. **预览功能**:暂时不实现实际预览功能,只显示测试内容
|
||||
|
||||
## 二、布局结构
|
||||
|
||||
### 2.1 原布局
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Header │
|
||||
├─────────────────────────────────────┤
|
||||
│ Main │
|
||||
│ (文件列表) │
|
||||
├─────────────────────────────────────┤
|
||||
│ Footer │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 新布局
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 左侧区域 │ 右侧预览区域 │
|
||||
│ ┌─────────────────────────────────────┐ │ ┌───────────┐ │
|
||||
│ │ Header │ │ │ Toolbar │ │
|
||||
│ ├─────────────────────────────────────┤ │ │(10%高度) │ │
|
||||
│ │ Main │ ├───────────────┤ │
|
||||
│ │ (文件列表) │ │ │ │
|
||||
│ ├─────────────────────────────────────┤ │ 预览内容区 │ │
|
||||
│ │ Footer │ │ (90%高度) │ │
|
||||
│ └─────────────────────────────────────┘ │ │ │
|
||||
│ └─────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.3 Toolbar 内容
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ [上一个] 第 1/5 个文件 当前: filename.pdf [下一个] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 三、修改方案
|
||||
|
||||
### 3.1 修改文件
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|----------|
|
||||
| `g3-file/index.css` | 添加左右布局和预览区域样式 |
|
||||
| `g3-file/index.js` | 修改布局结构、添加预览区域逻辑 |
|
||||
|
||||
### 3.2 JS 修改要点
|
||||
|
||||
1. **渲染方法 (`render`)**:修改 HTML 结构为左右布局
|
||||
2. **状态管理**:
|
||||
- `currentPreviewIndex`: 当前预览文件索引
|
||||
3. **预览操作方法**:
|
||||
- `getPreviewableFiles()`: 获取已上传文件列表
|
||||
- `previewFile(file)`: 预览指定文件
|
||||
- `previewNext()`: 预览下一个文件
|
||||
- `previewPrev()`: 预览上一个文件
|
||||
- `updatePreviewArea()`: 更新预览区域 UI
|
||||
4. **事件绑定**:绑定预览区域按钮事件
|
||||
|
||||
### 3.3 CSS 修改要点
|
||||
|
||||
1. **整体容器**:改为横向 flex 布局
|
||||
2. **左侧区域**:保持原有结构,设置宽度比例(如 50%)
|
||||
3. **右侧区域**:
|
||||
- 设置宽度比例(如 50%)
|
||||
- 纵向 flex 布局
|
||||
- toolbar 占 10% 高度
|
||||
- 预览内容区占 90% 高度
|
||||
4. **Toolbar 样式**:按钮、进度显示等
|
||||
|
||||
## 四、实施步骤
|
||||
|
||||
### 步骤 1:修改 CSS 样式
|
||||
|
||||
```css
|
||||
/* 整体布局 - 横向排列 */
|
||||
.g3-file-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 左侧区域 */
|
||||
.g3-file-left-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid #eef0f2;
|
||||
}
|
||||
|
||||
/* 右侧预览区域 */
|
||||
.g3-file-right-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
/* 预览 Toolbar */
|
||||
.g3-preview-toolbar {
|
||||
height: 10%;
|
||||
min-height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
}
|
||||
|
||||
/* 预览内容区域 */
|
||||
.g3-preview-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* 预览空状态 */
|
||||
.g3-preview-empty {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 预览文件信息 */
|
||||
.g3-preview-file-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 预览按钮 */
|
||||
.g3-preview-btn {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.g3-preview-btn:hover:not(:disabled) {
|
||||
border-color: #165dff;
|
||||
color: #165dff;
|
||||
}
|
||||
|
||||
.g3-preview-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 预览状态文字 */
|
||||
.g3-preview-status {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 2:修改 JS 渲染方法
|
||||
|
||||
修改 `render()` 方法的 HTML 结构:
|
||||
|
||||
```javascript
|
||||
render: function () {
|
||||
const html = `
|
||||
<div class="g3-file-container">
|
||||
<!-- 左侧区域 -->
|
||||
<div class="g3-file-left-panel">
|
||||
<div class="header">...</div>
|
||||
<div class="main" style="display: none;">main</div>
|
||||
<div class="empty-tip">...</div>
|
||||
<div class="footer">...</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧预览区域 -->
|
||||
<div class="g3-file-right-panel">
|
||||
<div class="g3-preview-toolbar">
|
||||
<button class="g3-preview-btn preview-prev" disabled>上一个</button>
|
||||
<div class="g3-preview-status">
|
||||
<span class="preview-counter">第 0/0 个文件</span>
|
||||
<span class="preview-filename" style="margin-left: 12px;"></span>
|
||||
</div>
|
||||
<button class="g3-preview-btn preview-next" disabled>下一个</button>
|
||||
</div>
|
||||
<div class="g3-preview-content">
|
||||
<div class="g3-preview-empty">请选择一个已上传的文件进行预览</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="file" class="file-input" style="display: none;" multiple />
|
||||
<div class="g3-global-menu"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.$container.html(html);
|
||||
|
||||
// 缓存 DOM 元素
|
||||
this.$leftPanel = this.$container.find(".g3-file-left-panel");
|
||||
this.$rightPanel = this.$container.find(".g3-file-right-panel");
|
||||
this.$fileList = this.$leftPanel.find(".main");
|
||||
this.$emptyTip = this.$leftPanel.find(".empty-tip");
|
||||
this.$checkAll = this.$leftPanel.find(".check-all-checkbox");
|
||||
this.$btnDownload = this.$leftPanel.find(".download-all");
|
||||
this.$btnDelete = this.$leftPanel.find(".delete-all");
|
||||
this.$btnUpload = this.$leftPanel.find(".upload");
|
||||
this.$btnSelect = this.$leftPanel.find(".select");
|
||||
this.$fileInput = this.$container.find(".file-input");
|
||||
this.$pendingCount = this.$leftPanel.find(".pending-number");
|
||||
|
||||
// 预览区域元素
|
||||
this.$previewToolbar = this.$container.find(".g3-preview-toolbar");
|
||||
this.$previewContent = this.$container.find(".g3-preview-content");
|
||||
this.$btnPreviewPrev = this.$container.find(".preview-prev");
|
||||
this.$btnPreviewNext = this.$container.find(".preview-next");
|
||||
this.$previewCounter = this.$container.find(".preview-counter");
|
||||
this.$previewFilename = this.$container.find(".preview-filename");
|
||||
|
||||
return this;
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 3:添加预览相关状态和方法
|
||||
|
||||
```javascript
|
||||
// 构造函数中添加
|
||||
this.currentPreviewIndex = -1;
|
||||
|
||||
// 获取可预览文件(已上传文件)
|
||||
getPreviewableFiles: function () {
|
||||
return this.files.filter(file => file.status === 'uploaded');
|
||||
},
|
||||
|
||||
// 预览指定文件
|
||||
previewFile: function (file) {
|
||||
const previewableFiles = this.getPreviewableFiles();
|
||||
const index = previewableFiles.findIndex(f => f._id === file._id);
|
||||
|
||||
if (index !== -1) {
|
||||
this.currentPreviewIndex = index;
|
||||
this.updatePreviewArea();
|
||||
}
|
||||
},
|
||||
|
||||
// 预览下一个
|
||||
previewNext: function () {
|
||||
const previewableFiles = this.getPreviewableFiles();
|
||||
if (previewableFiles.length === 0) return;
|
||||
|
||||
if (this.currentPreviewIndex < previewableFiles.length - 1) {
|
||||
this.currentPreviewIndex++;
|
||||
this.updatePreviewArea();
|
||||
}
|
||||
},
|
||||
|
||||
// 预览上一个
|
||||
previewPrev: function () {
|
||||
if (this.currentPreviewIndex > 0) {
|
||||
this.currentPreviewIndex--;
|
||||
this.updatePreviewArea();
|
||||
}
|
||||
},
|
||||
|
||||
// 更新预览区域
|
||||
updatePreviewArea: function () {
|
||||
const previewableFiles = this.getPreviewableFiles();
|
||||
const total = previewableFiles.length;
|
||||
|
||||
// 更新计数器
|
||||
if (this.currentPreviewIndex >= 0 && this.currentPreviewIndex < total) {
|
||||
this.$previewCounter.text(`第 ${this.currentPreviewIndex + 1}/${total} 个文件`);
|
||||
this.$previewFilename.text(`当前: ${previewableFiles[this.currentPreviewIndex].name}`);
|
||||
} else {
|
||||
this.$previewCounter.text(`第 0/${total} 个文件`);
|
||||
this.$previewFilename.text('');
|
||||
}
|
||||
|
||||
// 更新按钮状态
|
||||
this.$btnPreviewPrev.prop('disabled', this.currentPreviewIndex <= 0);
|
||||
this.$btnPreviewNext.prop('disabled',
|
||||
this.currentPreviewIndex >= total - 1 || total === 0);
|
||||
|
||||
// 更新预览内容
|
||||
if (this.currentPreviewIndex >= 0 && this.currentPreviewIndex < total) {
|
||||
const file = previewableFiles[this.currentPreviewIndex];
|
||||
this.$previewContent.html(`
|
||||
<div class="g3-preview-file-info">
|
||||
<h3>${file.name}</h3>
|
||||
<p>大小: ${this.formatFileSize(file.size)}</p>
|
||||
<p>上传时间: ${this.formatDate(file.uploadDate)}</p>
|
||||
<p>状态: 已上传</p>
|
||||
<p>URL: ${file.url || '-'}</p>
|
||||
</div>
|
||||
`);
|
||||
} else {
|
||||
this.$previewContent.html('<div class="g3-preview-empty">请选择一个已上传的文件进行预览</div>');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 4:绑定预览事件
|
||||
|
||||
```javascript
|
||||
bindEvents: function () {
|
||||
var self = this;
|
||||
|
||||
// ... 原有事件绑定 ...
|
||||
|
||||
// 预览下一个按钮
|
||||
this.$btnPreviewNext.off("click").on("click", function () {
|
||||
self.previewNext();
|
||||
});
|
||||
|
||||
// 预览上一个按钮
|
||||
this.$btnPreviewPrev.off("click").on("click", function () {
|
||||
self.previewPrev();
|
||||
});
|
||||
|
||||
// 点击文件项预览(只对已上传文件生效)
|
||||
this.$fileList
|
||||
.off("click", ".g3-file-item")
|
||||
.on("click", ".g3-file-item", function (e) {
|
||||
if ($(e.target).closest(".g3-file-action, .g3-file-checkbox, .g3-file-delete-btn").length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var id = $(this).data("id");
|
||||
var file = self.files.find(f => f._id === id);
|
||||
|
||||
if (!file) return;
|
||||
|
||||
// 只有已上传文件才能预览
|
||||
if (file.status === 'uploaded') {
|
||||
self.previewFile(file);
|
||||
}
|
||||
|
||||
if (typeof self.options.onPreview === "function") {
|
||||
self.options.onPreview([file]);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 5:更新文件操作后的预览状态
|
||||
|
||||
在 `internalDelete()`、`updateFileStatus()` 等方法中调用 `updatePreviewArea()`
|
||||
|
||||
## 五、注意事项
|
||||
|
||||
1. **预览计数**:只统计 `status === 'uploaded'` 的文件
|
||||
2. **预览权限**:只有已上传文件才能预览
|
||||
3. **边界处理**:
|
||||
- 没有可预览文件时,工具栏按钮禁用
|
||||
- 处于第一个文件时,上一个按钮禁用
|
||||
- 处于最后一个文件时,下一个按钮禁用
|
||||
4. **预览内容**:暂时显示测试内容(文件名、大小、日期等信息)
|
||||
|
||||
## 六、测试验证
|
||||
|
||||
1. 上传文件后,预览区域显示可预览文件数量
|
||||
2. 点击已上传文件,预览区域显示文件信息
|
||||
3. 上下按钮正确切换预览文件
|
||||
4. 删除文件后,预览区域正确更新
|
||||
5. 未上传文件点击不触发预览
|
||||
@@ -0,0 +1,418 @@
|
||||
# G3File jQuery 到 Vue 3 迁移计划
|
||||
|
||||
## 1. 需求分析
|
||||
|
||||
用户需要将 `custom-file/index.js` 中的 jQuery 代码迁移到 `custom-file-vue/index.js`,使用 Vue 3 的 `vue.global.prod.js`。要求:
|
||||
|
||||
* 代码逻辑不变
|
||||
|
||||
* CSS 代码不变
|
||||
|
||||
## 2. 原 jQuery 代码结构分析
|
||||
|
||||
### 2.1 主要功能模块
|
||||
|
||||
| 模块 | 功能描述 |
|
||||
| ----- | --------------------- |
|
||||
| 配置与常量 | 默认配置、多语言、图标映射 |
|
||||
| 工具方法 | 文件图标、图片压缩、大小格式化、日期格式化 |
|
||||
| UI 渲染 | 主容器、文件列表、操作菜单、任务面板、通知 |
|
||||
| 事件绑定 | 文件选择、拖拽、粘贴、按钮点击 |
|
||||
| 文件处理 | 选择、下载、删除、上传 |
|
||||
| 任务管理 | 批量下载/上传进度跟踪 |
|
||||
| 通知系统 | 消息提示 |
|
||||
| 权限控制 | 全局权限和单文件权限 |
|
||||
|
||||
### 2.2 核心数据结构
|
||||
|
||||
```javascript
|
||||
// 文件对象
|
||||
{
|
||||
id: string,
|
||||
name: string,
|
||||
size: number,
|
||||
uploadDate: string,
|
||||
url: string,
|
||||
file: File,
|
||||
status: 'pending' | 'uploading' | 'uploaded' | 'failed'
|
||||
}
|
||||
|
||||
// 选中文件集合
|
||||
selectedFiles: Set<string>
|
||||
|
||||
// 任务状态
|
||||
taskStats: { total, success, fail }
|
||||
```
|
||||
|
||||
## 3. Vue 3 迁移方案
|
||||
|
||||
### 3.1 组件结构
|
||||
|
||||
```
|
||||
G3File.vue (主组件)
|
||||
├── 模板:HTML 结构
|
||||
├── 脚本:响应式数据和方法
|
||||
└── 样式:引用原 CSS
|
||||
```
|
||||
|
||||
### 3.2 迁移策略
|
||||
|
||||
| jQuery 特性 | Vue 3 等价实现 |
|
||||
| --------------- | ----------------------- |
|
||||
| `$(selector)` | `ref` + `template refs` |
|
||||
| `.html()` | `v-html` / 模板插值 |
|
||||
| `.on('event')` | `@event` 指令 |
|
||||
| `.off('event')` | Vue 自动管理 |
|
||||
| `$.extend()` | 展开运算符 |
|
||||
| `$.fn` 插件 | Vue 组件 |
|
||||
|
||||
### 3.3 关键迁移点
|
||||
|
||||
1. **DOM 操作 → 模板渲染**
|
||||
|
||||
* 主容器 HTML 使用 Vue 模板
|
||||
|
||||
* 文件列表使用 `v-for` 渲染
|
||||
|
||||
* 条件渲染使用 `v-if`/`v-show`
|
||||
|
||||
2. **事件处理**
|
||||
|
||||
* 选择文件:`@change`
|
||||
|
||||
* 拖拽:`@dragenter`, `@dragover`, `@dragleave`, `@drop`
|
||||
|
||||
* 粘贴:`@paste`
|
||||
|
||||
* 按钮点击:`@click`
|
||||
|
||||
3. **响应式数据**
|
||||
|
||||
* `files` → `ref([])`
|
||||
|
||||
* `selectedFiles` → `ref(new Set())`
|
||||
|
||||
* `actionMenuState` → `reactive({})`
|
||||
|
||||
* `tasks` → `ref([])`
|
||||
|
||||
4. **生命周期**
|
||||
|
||||
* `init()` → `onMounted()`
|
||||
|
||||
* `destroy()` → `onUnmounted()`
|
||||
|
||||
5. Setup写法
|
||||
|
||||
## 4. 迁移步骤
|
||||
|
||||
### 步骤 1:创建 Vue 组件结构
|
||||
|
||||
```javascript
|
||||
const { createApp, ref, reactive, onMounted, onUnmounted, computed } = Vue
|
||||
|
||||
const G3File = {
|
||||
template: `...`,
|
||||
props: {
|
||||
options: { type: Object, default: () => ({}) }
|
||||
},
|
||||
setup(props) {
|
||||
// 响应式数据
|
||||
const files = ref([])
|
||||
const selectedFiles = ref(new Set())
|
||||
const objectUrls = ref(new Map())
|
||||
const actionMenuState = reactive({ open: false, fileId: null, anchorEl: null, items: [] })
|
||||
const tasks = ref([])
|
||||
const taskStats = reactive({ total: 0, success: 0, fail: 0 })
|
||||
const notifications = ref([])
|
||||
|
||||
// 计算属性
|
||||
const pendingCount = computed(() => files.value.filter(f => f.status === 'pending').length)
|
||||
const allSelected = computed(() => files.value.length > 0 && selectedFiles.value.size === files.value.length)
|
||||
|
||||
// 方法
|
||||
const generateUniqueId = () => 'file_' + Math.random().toString(36).slice(2) + Date.now()
|
||||
const getFileIcon = (filename) => { /* ... */ }
|
||||
const compressImage = async (file, options) => { /* ... */ }
|
||||
const isImageFile = (filename) => { /* ... */ }
|
||||
const formatFileSize = (bytes) => { /* ... */ }
|
||||
const formatDate = (dateStr) => { /* ... */ }
|
||||
const getUniqueFileName = (fileName, existing) => { /* ... */ }
|
||||
const getFileBlob = async (url) => { /* ... */ }
|
||||
|
||||
// UI 更新方法
|
||||
const updateUI = () => { /* ... */ }
|
||||
const renderFileList = () => { /* ... */ }
|
||||
|
||||
// 文件操作方法
|
||||
const handleFileSelect = async (event) => { /* ... */ }
|
||||
const handleDownload = (fileList, options) => { /* ... */ }
|
||||
const handleDelete = (fileList) => { /* ... */ }
|
||||
const handleUpload = (fileList) => { /* ... */ }
|
||||
|
||||
// 任务管理
|
||||
const addTask = (task) => { /* ... */ }
|
||||
const updateTask = (taskId, updates) => { /* ... */ }
|
||||
const finishTask = (taskId, status) => { /* ... */ }
|
||||
const clearTasks = () => { /* ... */ }
|
||||
|
||||
// 通知系统
|
||||
const showNotification = (options) => { /* ... */ }
|
||||
const closeNotification = (notificationId) => { /* ... */ }
|
||||
|
||||
// 权限控制
|
||||
const hasPermission = (file, action) => { /* ... */ }
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
// 初始化脚本加载
|
||||
// 绑定全局事件(拖拽、粘贴)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理 ObjectURL
|
||||
// 解绑全局事件
|
||||
})
|
||||
|
||||
return {
|
||||
files,
|
||||
selectedFiles,
|
||||
actionMenuState,
|
||||
tasks,
|
||||
taskStats,
|
||||
notifications,
|
||||
pendingCount,
|
||||
allSelected,
|
||||
// ... methods
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 2:模板结构
|
||||
|
||||
```html
|
||||
<div class="g3-file-container" :class="{ 'drag-over': isDragOver }">
|
||||
<!-- 头部 -->
|
||||
<div class="header">
|
||||
<label class="check-all">
|
||||
<input type="checkbox" v-model="allSelected" />
|
||||
<span>{{ language.selectAll }}</span>
|
||||
</label>
|
||||
<button class="download-all" :disabled="!canBatchDownload" @click="handleBatchDownload">
|
||||
{{ staticIconMap.download }}
|
||||
{{ language.downloadBatch }}
|
||||
</button>
|
||||
<button class="delete-all" :disabled="!canBatchDelete" @click="handleBatchDelete">
|
||||
{{ staticIconMap.delete }}
|
||||
{{ language.delete }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 文件列表 -->
|
||||
<div class="main" v-show="files.length > 0">
|
||||
<div
|
||||
v-for="file in files"
|
||||
:key="file.id"
|
||||
class="g3-file-item"
|
||||
@click="handleFileClick(file)"
|
||||
>
|
||||
<input type="checkbox" v-model="selectedFiles.has(file.id)" />
|
||||
<label class="g3-checkbox-label"></label>
|
||||
<div class="g3-file-preview">
|
||||
<!-- 图片或图标 -->
|
||||
</div>
|
||||
<div v-if="file.status === 'pending'" class="g3-file-pending-badge">
|
||||
{{ language.pending }}
|
||||
</div>
|
||||
<div class="g3-file-delete-btn" @click.stop="handleDelete([file])">
|
||||
{{ staticIconMap.delete }}
|
||||
</div>
|
||||
<div class="g3-file-info">
|
||||
<span class="g3-file-name">{{ file.name }}</span>
|
||||
<span>{{ formatFileSize(file.size) }}</span>
|
||||
<span>{{ formatDate(file.uploadDate) }}</span>
|
||||
</div>
|
||||
<div class="g3-file-actions">
|
||||
<div class="g3-file-action preview" @click.stop="handlePreview(file)">
|
||||
{{ staticIconMap.preview }}
|
||||
</div>
|
||||
<div class="g3-file-action download" @click.stop="handleDownload([file], { batch: false })">
|
||||
{{ staticIconMap.download }}
|
||||
</div>
|
||||
<div class="g3-file-action more" @click.stop="openActionMenu($event, file)">
|
||||
{{ staticIconMap.more }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div class="empty-tip" v-show="files.length === 0">
|
||||
<span>{{ language.emptyTip1 }}</span>
|
||||
<span>{{ language.emptyTip2 }}</span>
|
||||
<span>{{ language.emptyTip3 }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 底部 -->
|
||||
<div class="footer">
|
||||
<div class="pending-count">
|
||||
<span>{{ language.pending }}</span>
|
||||
<span class="pending-number">{{ pendingCount }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="select" :disabled="!hasPermission(null, 'select')" @click="triggerFileInput">
|
||||
{{ staticIconMap.select }}
|
||||
{{ language.select }}
|
||||
</button>
|
||||
<button class="upload" :disabled="!hasPermission(null, 'upload') || pendingCount === 0" @click="handleUpload(files)">
|
||||
{{ staticIconMap.upload }}
|
||||
{{ language.upload }}
|
||||
</button>
|
||||
</div>
|
||||
<input type="file" class="file-input" style="display: none;" multiple @change="handleFileSelect" ref="fileInput" />
|
||||
</div>
|
||||
|
||||
<!-- 操作菜单 -->
|
||||
<div class="g3-global-menu" :class="{ 'is-open': actionMenuState.open }">
|
||||
<div
|
||||
v-for="(item, index) in actionMenuState.items"
|
||||
:key="index"
|
||||
class="g3-action-menu-item"
|
||||
:class="{ 'is-disabled': item.disabled }"
|
||||
@click="handleActionMenuItemClick(item)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务面板 -->
|
||||
<div class="task-dock" v-show="tasks.length > 0">
|
||||
<div class="dock-header">
|
||||
<span class="dock-title">Task Running</span>
|
||||
<div class="dock-actions">
|
||||
<button title="close" @click="clearTasks">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dock-body">
|
||||
<div class="progress-line">
|
||||
<span class="count">{{ taskStats.success + taskStats.fail }} / {{ taskStats.total }}</span>
|
||||
<span class="percent">{{ Math.round(totalProgress) }}%</span>
|
||||
</div>
|
||||
<div class="task-name">{{ currentTask?.name }}</div>
|
||||
<div class="bar">
|
||||
<div class="bar-inner" :style="{ width: currentTask?.progress + '%' }"></div>
|
||||
</div>
|
||||
<div class="task-result">
|
||||
{{ language.taskTotal }}: {{ taskStats.total }} |
|
||||
{{ language.taskSuccess }}: {{ taskStats.success }} |
|
||||
{{ language.taskFail }}: {{ taskStats.fail }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 通知容器 -->
|
||||
<div class="notification-container">
|
||||
<div
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
class="notification"
|
||||
:class="[`notification-${notification.type}`, { 'notification-fade-out': notification.closing }]"
|
||||
>
|
||||
<div class="notification-content">
|
||||
<div v-if="notification.title" class="notification-title">{{ notification.title }}</div>
|
||||
<div class="notification-message">{{ notification.message }}</div>
|
||||
</div>
|
||||
<button v-if="notification.showClose" class="notification-close" @click="closeNotification(notification.id)">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI Lock -->
|
||||
<div class="ui-lock" v-show="isUILocked"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 步骤 3:工具方法迁移
|
||||
|
||||
所有工具方法保持逻辑不变,只是移除 jQuery 依赖:
|
||||
|
||||
* `generateUniqueId` - 保持不变
|
||||
|
||||
* `getFileIcon` - 保持不变(纯字符串处理)
|
||||
|
||||
* `compressImage` - 保持不变(使用原生 API)
|
||||
|
||||
* `isImageFile` - 保持不变
|
||||
|
||||
* `formatFileSize` - 保持不变
|
||||
|
||||
* `formatDate` - 保持不变
|
||||
|
||||
* `getUniqueFileName` - 保持不变
|
||||
|
||||
* `getFileBlob` - 保持不变(使用 fetch API)
|
||||
|
||||
### 步骤 4:事件处理迁移
|
||||
|
||||
| jQuery 事件 | Vue 事件 |
|
||||
| ---------------------------------------------------- | ------------------------------------------------ |
|
||||
| `$(document).on('paste')` | 在 `onMounted` 中绑定原生事件 |
|
||||
| `$(document).on('click.g3file_actionmenu')` | Vue 模板事件 |
|
||||
| `$container.on('dragenter dragover dragleave drop')` | `@dragenter`, `@dragover`, `@dragleave`, `@drop` |
|
||||
| `$fileInput.on('change')` | `@change` |
|
||||
|
||||
### 步骤 5:权限控制迁移
|
||||
|
||||
保持原有的权限判断逻辑:
|
||||
|
||||
```javascript
|
||||
const hasPermission = (file, action) => {
|
||||
const globalPermission = props.options.globalPermission
|
||||
const filePermissionResolver = props.options.filePermissionResolver
|
||||
|
||||
if (typeof filePermissionResolver === 'function') {
|
||||
const result = filePermissionResolver({ file, action })
|
||||
if (result !== undefined) return !!result
|
||||
}
|
||||
|
||||
if (typeof globalPermission === 'function') {
|
||||
return !!globalPermission({ file, action })
|
||||
} else if (typeof globalPermission === 'object') {
|
||||
return !!globalPermission[action]
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 文件复制
|
||||
|
||||
由于 CSS 代码不需要改变,需要将 `custom-file/index.css` 复制到 `custom-file-vue/index.css`(如果不存在差异)。
|
||||
|
||||
## 6. 测试验证
|
||||
|
||||
迁移完成后需要验证:
|
||||
|
||||
1. 文件列表显示正常
|
||||
2. 文件选择功能正常(点击、拖拽、粘贴)
|
||||
3. 文件上传功能正常
|
||||
4. 文件下载功能正常(单个和批量)
|
||||
5. 文件删除功能正常
|
||||
6. 任务面板显示正常
|
||||
7. 通知系统正常
|
||||
8. 权限控制正常
|
||||
9. 多语言支持正常
|
||||
|
||||
## 7. 潜在风险
|
||||
|
||||
1. **jQuery 插件封装**:原代码使用 `$.fn.G3File` 封装,迁移后需要提供 Vue 组件注册方式
|
||||
2. **DOM 引用**:需要确保所有模板 ref 正确绑定
|
||||
3. **全局事件**:需要在 `onUnmounted` 中正确清理
|
||||
4. **异步操作**:确保所有异步操作(如文件上传、下载)正确处理
|
||||
|
||||
## 8. 输出文件
|
||||
|
||||
* `custom-file-vue/index.js` - Vue 3 组件实现
|
||||
|
||||
* `custom-file-vue/index.css` - 样式文件(保持不变)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# 批量操作进度通知重构计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户要求修改批量操作(下载、上传、删除等)的通知显示逻辑:
|
||||
|
||||
1. **单一通知**:批量操作只显示一个 notification
|
||||
2. **手动关闭**:通知不会自动关闭,需要用户手动关闭
|
||||
3. **实时更新**:显示当前正在处理的文件名和进度
|
||||
4. **结果统计**:操作完成后显示总数、成功数、失败数
|
||||
5. **多语言支持**:使用现有语言配置,不写死文字
|
||||
6. **通用设计**:支持批量下载、上传、删除等多种操作类型
|
||||
7. **UI锁定**:操作进行时自动锁定UI,操作结束后自动解锁(与通知关闭无关)
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. 新增任务组概念
|
||||
|
||||
在实例中添加 `currentTaskGroup` 来管理当前批量操作的通知状态:
|
||||
```javascript
|
||||
this.currentTaskGroup = null; // 当前任务组 { taskType, notificationId, total }
|
||||
```
|
||||
|
||||
### 2. 修改 addTask 方法
|
||||
|
||||
- 检查是否已有同类型的任务组
|
||||
- 如果没有,创建新的任务组和通知
|
||||
- 如果有,复用已有的通知
|
||||
|
||||
### 3. 修改 updateTask 方法
|
||||
|
||||
- 更新通知中的当前文件名和进度百分比
|
||||
- 显示格式:`正在下载:文件名 (进度%)`
|
||||
|
||||
### 4. 修改 finishTask 方法
|
||||
|
||||
- 所有任务完成后更新通知显示结果统计
|
||||
- 解锁 UI(与通知关闭无关)
|
||||
- 通知保持显示,等待用户手动关闭
|
||||
|
||||
### 5. 修改 clearTasks 方法
|
||||
|
||||
- 不自动关闭通知(用户手动关闭)
|
||||
- 只是重置任务状态
|
||||
|
||||
### 6. 修改 closeNotification 方法
|
||||
|
||||
- 关闭通知时清理对应的任务组
|
||||
|
||||
### 7. 更新多语言配置
|
||||
|
||||
确保以下语言键存在:
|
||||
- `batchDownload`: 批量下载
|
||||
- `batchUpload`: 批量上传
|
||||
- `batchDelete`: 批量删除
|
||||
- `downloading`: 正在下载
|
||||
- `uploading`: 正在上传
|
||||
- `deleting`: 正在删除
|
||||
- `downloadResult`: 结果统计格式
|
||||
|
||||
## 修改步骤
|
||||
|
||||
1. 在 `init` 或构造函数中添加 `currentTaskGroup` 状态
|
||||
2. 修改 `addTask` 方法支持任务组概念
|
||||
3. 修改 `updateTask` 方法更新进度显示
|
||||
4. 修改 `finishTask` 方法显示最终结果并解锁UI
|
||||
5. 修改 `clearTasks` 方法不自动关闭通知
|
||||
6. 修改 `closeNotification` 方法清理任务组
|
||||
7. 验证多语言支持
|
||||
|
||||
## 风险评估
|
||||
|
||||
| 风险项 | 风险等级 | 处理方式 |
|
||||
|--------|----------|----------|
|
||||
| 任务组状态管理 | 中 | 使用单一任务组管理同一类型的批量操作 |
|
||||
| 通知重复创建 | 低 | 添加检查逻辑,避免重复创建 |
|
||||
| UI锁定与通知生命周期不一致 | 中 | 分离 UI 锁定和通知关闭逻辑 |
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 原有 `showNotification` 调用方式保持兼容
|
||||
- 任务管理方法保持向后兼容
|
||||
@@ -0,0 +1,108 @@
|
||||
# Notification 重构计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户要求将现有的 `notification` 和 `dock` 两个组件合并,统一使用 `notification` 来显示所有通知和进度信息。
|
||||
|
||||
### 修改目标
|
||||
|
||||
1. **统一使用 notification**:删除 dock 组件,所有进度显示改用 notification
|
||||
2. **下载进度结构不变**:保持现有的任务进度数据结构
|
||||
3. **开放 notification 内容**:支持更灵活的内容传递
|
||||
4. **添加 lockUI 选项**:在 showNotification 中增加是否锁定 UI 的选项
|
||||
|
||||
***
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. 删除 DOM 结构中的 dock
|
||||
|
||||
**文件**: `custom-file/index.js`
|
||||
|
||||
删除 `render` 方法中的 task-dock HTML 结构:
|
||||
|
||||
```html
|
||||
<div class="task-dock">...</div>
|
||||
<div class="ui-lock"></div>
|
||||
```
|
||||
|
||||
### 2. 删除 dock 相关变量
|
||||
|
||||
删除 `render` 方法中的:
|
||||
|
||||
* `this.$taskDock = this.$container.find(".task-dock");`
|
||||
|
||||
* `this.$uiLock = this.$container.find(".ui-lock");`
|
||||
|
||||
### 3. 修改 showNotification 方法
|
||||
|
||||
增加以下 options:
|
||||
|
||||
* `lockUI`: 是否锁定 UI(默认 false)
|
||||
|
||||
* `progress`: 进度百分比(0-100),用于显示进度条
|
||||
|
||||
* `customContent`: 自定义内容(支持 HTML)
|
||||
|
||||
### 4. 修改任务管理方法
|
||||
|
||||
修改以下方法使用 notification 显示进度:
|
||||
|
||||
* `addTask`: 创建任务时显示通知
|
||||
|
||||
* `updateTask`: 更新任务进度时更新通知
|
||||
|
||||
* `finishTask`: 完成任务时更新通知状态
|
||||
|
||||
* `clearTasks`: 清空任务时关闭通知
|
||||
|
||||
### 5. 删除 dock 相关方法
|
||||
|
||||
删除以下方法:
|
||||
|
||||
* `showTaskDock`
|
||||
|
||||
* `hideTaskDock`
|
||||
|
||||
* `updateTaskDock`
|
||||
|
||||
* `bindTaskDockEvents`
|
||||
|
||||
* `lockUI`(改为在 showNotification 中处理)
|
||||
|
||||
* `unlockUI`(改为在通知关闭时处理)
|
||||
|
||||
* `isUILocked`
|
||||
|
||||
### 6. 修改批量下载逻辑
|
||||
|
||||
修改 `internalDownloadBatch` 方法,使用 notification 显示下载进度。
|
||||
|
||||
***
|
||||
|
||||
## 风险评估
|
||||
|
||||
| 风险项 | 风险等级 | 处理方式 |
|
||||
| --------- | ---- | ---------------------------- |
|
||||
| 任务进度状态丢失 | 低 | 保留 tasks 数组用于状态管理 |
|
||||
| UI 锁定逻辑变化 | 中 | 在 notification 中实现 lockUI 选项 |
|
||||
| 通知样式需要调整 | 低 | 保持原有样式,增加进度条样式 |
|
||||
|
||||
***
|
||||
|
||||
## 兼容性
|
||||
|
||||
* 原有 `showNotification` 调用方式保持兼容
|
||||
|
||||
* 新增参数为可选参数,不影响现有代码
|
||||
|
||||
***
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. 修改 `render` 方法,删除 dock 和 ui-lock 的 DOM 结构
|
||||
2. 修改 `showNotification` 方法,增加 lockUI、progress、customContent 选项
|
||||
3. 修改任务管理方法,使用 notification 显示进度
|
||||
4. 删除 dock 相关方法
|
||||
5. 修改 `internalDownloadBatch` 使用新的通知机制
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
# UI 提示系统重构计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户要求重新设计并实现一个轻量 UI 提示系统,包含:
|
||||
|
||||
1. **Toast(右上角)** - 瞬时提示,无状态设计
|
||||
2. **Task Center(右下角任务中心)** - 长任务状态系统,有状态
|
||||
|
||||
核心要求:
|
||||
- 两者完全独立,不共享逻辑
|
||||
- Task 必须通用化,不绑定具体业务类型
|
||||
- 实现 UI Lock 机制
|
||||
- 支持多语言国际化
|
||||
|
||||
---
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 1. 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ UI 提示系统 │
|
||||
├───────────────────────────┬─────────────────────────────────┤
|
||||
│ Toast 系统 │ Task Center 系统 │
|
||||
│ (右上角,无状态) │ (右下角,有状态) │
|
||||
├───────────────────────────┼─────────────────────────────────┤
|
||||
│ • 自动消失 │ • 手动关闭 │
|
||||
│ • 多条堆叠 │ • 单一实例 │
|
||||
│ • 类型:success/error/ │ • 生命周期独立 │
|
||||
│ info/warning │ • 进度追踪 │
|
||||
└───────────────────────────┴─────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. Toast API
|
||||
|
||||
```js
|
||||
showToast({
|
||||
title, // 标题
|
||||
message, // 消息内容
|
||||
type: "success | error | info | warning",
|
||||
duration // 显示时长(毫秒)
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Task API
|
||||
|
||||
```js
|
||||
// 创建任务
|
||||
startTask({
|
||||
id, // 任务ID
|
||||
title, // 任务标题(国际化key)
|
||||
total, // 总数量
|
||||
current, // 当前进度
|
||||
currentItem // 当前处理项
|
||||
});
|
||||
|
||||
// 更新任务
|
||||
updateTask({
|
||||
id, // 任务ID
|
||||
current, // 当前进度
|
||||
currentItem // 当前处理项
|
||||
});
|
||||
|
||||
// 完成任务
|
||||
finishTask({
|
||||
id, // 任务ID
|
||||
total, // 总数量
|
||||
success, // 成功数量
|
||||
failed // 失败数量
|
||||
});
|
||||
|
||||
// 手动关闭
|
||||
closeTask(id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. 修改 CSS 文件 (`custom-file/index.css`)
|
||||
|
||||
**新增样式:**
|
||||
- Toast 容器样式(右上角固定定位)
|
||||
- Toast 单条样式(支持不同类型)
|
||||
- Toast 动画(进入/退出)
|
||||
- Task Center 容器样式(右下角固定定位)
|
||||
- Task Center 进度条样式
|
||||
- Task Center 结果展示样式
|
||||
- UI Lock 样式
|
||||
|
||||
**删除旧样式:**
|
||||
- 删除 `.task-dock` 相关样式(如仍存在)
|
||||
|
||||
### 2. 修改 JS 文件 (`custom-file/index.js`)
|
||||
|
||||
**新增方法:**
|
||||
|
||||
| 方法名 | 功能 |
|
||||
|--------|------|
|
||||
| `showToast` | 显示 Toast 提示 |
|
||||
| `startTask` | 创建并启动任务 |
|
||||
| `updateTask` | 更新任务进度 |
|
||||
| `finishTask` | 完成任务 |
|
||||
| `closeTask` | 关闭任务 UI |
|
||||
| `lockUI` | 锁定 UI |
|
||||
| `unlockUI` | 解锁 UI |
|
||||
| `isUILocked` | 检查 UI 是否锁定 |
|
||||
|
||||
**修改方法:**
|
||||
- `render` - 添加 Toast 和 Task Center 的 DOM 结构
|
||||
- `internalDownloadBatch` - 使用新的 Task API
|
||||
|
||||
**删除方法:**
|
||||
- `addTask`(旧版本)
|
||||
- `updateTask`(旧版本)
|
||||
- `finishTask`(旧版本)
|
||||
- `clearTasks`(旧版本)
|
||||
- `updateTaskStats`(旧版本)
|
||||
|
||||
### 3. 新增多语言配置
|
||||
|
||||
```js
|
||||
languages: {
|
||||
"zh-CN": {
|
||||
// ... 现有配置
|
||||
toast: {
|
||||
success: "成功",
|
||||
error: "错误",
|
||||
info: "提示",
|
||||
warning: "警告"
|
||||
},
|
||||
task: {
|
||||
title: {
|
||||
processing: "处理中"
|
||||
},
|
||||
total: "总计",
|
||||
success: "成功",
|
||||
failed: "失败",
|
||||
currentItem: "当前项",
|
||||
close: "关闭"
|
||||
}
|
||||
},
|
||||
"en-US": {
|
||||
// ... 现有配置
|
||||
toast: {
|
||||
success: "Success",
|
||||
error: "Error",
|
||||
info: "Info",
|
||||
warning: "Warning"
|
||||
},
|
||||
task: {
|
||||
title: {
|
||||
processing: "Processing"
|
||||
},
|
||||
total: "Total",
|
||||
success: "Success",
|
||||
failed: "Failed",
|
||||
currentItem: "Current",
|
||||
close: "Close"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实施步骤
|
||||
|
||||
| 步骤 | 任务 | 文件 | 状态 |
|
||||
|------|------|------|------|
|
||||
| 1 | 添加 Toast 和 Task Center 的 CSS 样式 | `custom-file/index.css` | 待执行 |
|
||||
| 2 | 更新多语言配置 | `custom-file/index.js` | 待执行 |
|
||||
| 3 | 添加 Toast 相关方法 | `custom-file/index.js` | 待执行 |
|
||||
| 4 | 添加 Task Center 相关方法 | `custom-file/index.js` | 待执行 |
|
||||
| 5 | 添加 UI Lock 机制 | `custom-file/index.js` | 待执行 |
|
||||
| 6 | 修改 render 方法添加 DOM 结构 | `custom-file/index.js` | 待执行 |
|
||||
| 7 | 修改 internalDownloadBatch 使用新 API | `custom-file/index.js` | 待执行 |
|
||||
| 8 | 删除旧的任务管理方法 | `custom-file/index.js` | 待执行 |
|
||||
|
||||
---
|
||||
|
||||
## 风险评估
|
||||
|
||||
| 风险项 | 风险等级 | 处理方式 |
|
||||
|--------|----------|----------|
|
||||
| Task 状态与 UI 不同步 | 中 | 确保 task 对象独立于 UI 存在 |
|
||||
| Toast 堆叠过多 | 低 | 限制最大显示数量(如5条) |
|
||||
| UI Lock 状态异常 | 中 | 在任务完成时强制解锁 |
|
||||
| 多语言文案遗漏 | 低 | 统一使用 `this.language.xxx` 模式 |
|
||||
|
||||
---
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 原有 API 调用保持兼容
|
||||
- 新增 API 为可选参数
|
||||
- 不影响现有文件管理功能
|
||||
|
||||
---
|
||||
|
||||
## 最终目标
|
||||
|
||||
实现一个 **"通用任务系统 + Toast 提示系统 + UI Lock + i18n"** 的轻量 UI 架构,支持未来扩展:
|
||||
- 批量上传
|
||||
- 批量下载
|
||||
- 批量删除
|
||||
- 任意异步任务
|
||||
|
||||
无需修改核心结构,仅通过 task 数据驱动。
|
||||
Reference in new issue
Block a user