# 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 = `
`;
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(`
${file.name}
大小: ${this.formatFileSize(file.size)}
上传时间: ${this.formatDate(file.uploadDate)}
状态: 已上传
URL: ${file.url || '-'}
`);
} else {
this.$previewContent.html('请选择一个已上传的文件进行预览
');
}
}
```
### 步骤 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. 未上传文件点击不触发预览