u
This commit is contained in:
1 parent
3620369d47
commit
217838c615
11 files changed
+1268
-1022
No files matched your search
@@ -0,0 +1,127 @@
|
||||
# 功能添加计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户要求添加两个功能:
|
||||
|
||||
### 功能一:双击事件扩展
|
||||
|
||||
- 添加 `onDblClick` 回调选项,供外部使用
|
||||
- 如果外部注册了 `onDblClick`,则优先执行外部回调
|
||||
- 如果外部未注册 `onDblClick`,则双击文件时跳转到文件预览页面(fullPreviewUrl)
|
||||
|
||||
### 功能二:onUploadBefore 回调
|
||||
|
||||
- 添加 `onUploadBefore` 回调选项,参考 `onBeforeDelete` 的实现方式
|
||||
- 支持返回值类型:
|
||||
- `false`: 阻止上传
|
||||
- Promise: 异步确认后再上传
|
||||
- Function: 回调确认后再上传
|
||||
- 其他/undefined: 继续执行上传
|
||||
- 同时将 `onBeforeDelete 名称修改为 onDeleteBefore`
|
||||
|
||||
## 修改文件
|
||||
|
||||
1. **index.js**:
|
||||
- 在 defaults 配置中添加 `onDblClick` 和 `onUploadBefore`
|
||||
- 在 bindEvents 中添加文件项双击事件处理
|
||||
- 在 handleUpload 方法中添加 onUploadBefore 逻辑
|
||||
|
||||
## 实现步骤
|
||||
|
||||
### 步骤一:添加配置项
|
||||
|
||||
在 `defaults` 对象中添加:
|
||||
|
||||
```javascript
|
||||
onDblClick: null,
|
||||
onUploadBefore: null,
|
||||
```
|
||||
|
||||
### 步骤二:添加双击事件处理
|
||||
|
||||
在文件列表事件委托中添加双击事件:
|
||||
|
||||
```javascript
|
||||
// 文件项双击
|
||||
.on("dblclick", ".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.getFileById(id);
|
||||
if (!file) return;
|
||||
if (!self.hasPermission(file, "view")) return;
|
||||
|
||||
// 如果外部注册了 onDblClick,优先执行外部回调
|
||||
if (typeof self.options.onDblClick === "function") {
|
||||
self.options.onDblClick(file);
|
||||
return;
|
||||
}
|
||||
|
||||
// 否则跳转到预览页面
|
||||
var isUploaded = file.status === "uploaded";
|
||||
var isPreviewable = self.isPreviewableFile(file.name);
|
||||
var fileUrl = file.url && file.url !== "" ? file.url : null;
|
||||
|
||||
if (isUploaded && fileUrl && isPreviewable) {
|
||||
var previewUrl = self.options.previewUrl || "";
|
||||
var fullPreviewUrl = previewUrl
|
||||
? previewUrl + G3FileUtils.base64Encode(fileUrl)
|
||||
: fileUrl;
|
||||
window.open(fullPreviewUrl, "_blank");
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 步骤三:添加 onUploadBefore 逻辑
|
||||
|
||||
在 `handleUpload` 方法开头添加:
|
||||
|
||||
```javascript
|
||||
// onUploadBefore 处理
|
||||
if (typeof self.options.onUploadBefore === "function") {
|
||||
var result = self.options.onUploadBefore(pendingFiles);
|
||||
if (result === false) return;
|
||||
if (typeof result.then === "function") {
|
||||
result.then(function (confirmed) {
|
||||
if (confirmed) self.internalHandleUpload(pendingFiles, taskId);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof result === "function") {
|
||||
result(function (confirmed) {
|
||||
if (confirmed) self.internalHandleUpload(pendingFiles, taskId);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
需要将原有的上传逻辑提取为 `internalHandleUpload` 方法。
|
||||
|
||||
## 风险处理
|
||||
|
||||
1. **兼容性风险**:确保修改不会影响现有功能
|
||||
2. **异步处理风险**:正确处理 Promise 和回调函数的情况
|
||||
3. **权限检查**:双击事件需要检查 view 权限
|
||||
|
||||
## 测试要点
|
||||
|
||||
1. 测试双击文件时:
|
||||
- 注册 onDblClick 时是否优先执行外部回调
|
||||
- 未注册 onDblClick 时是否正确跳转到预览页面
|
||||
- 未上传的文件双击时不跳转
|
||||
- 无权限文件双击时不响应
|
||||
2. 测试上传时:
|
||||
- onUploadBefore 返回 false 时是否阻止上传
|
||||
- onUploadBefore 返回 Promise 时是否等待异步结果
|
||||
- onUploadBefore 返回回调函数时是否正确处理
|
||||
|
||||
## 依赖分析
|
||||
|
||||
- 依赖 `isPreviewableFile` 方法判断文件是否可预览
|
||||
- 依赖 `G3FileUtils.base64Encode` 方法编码 URL
|
||||
- 依赖 `getFileById` 方法获取文件信息
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Task 关闭按钮修复计划
|
||||
|
||||
## 问题分析
|
||||
|
||||
根据代码审查,`g3-task-close` 点击无反应的核心问题在于:
|
||||
|
||||
1. **事件绑定方式错误**:使用直接绑定而非事件委托
|
||||
2. **taskId 未绑定到 DOM**:无法通过 DOM 获取当前任务 ID
|
||||
3. **closeTask 方法不完善**:只删除数据,未删除对应的 DOM 元素
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 修改 renderTaskCenter 方法
|
||||
|
||||
* 在 DOM 元素上添加 `data-task-id` 属性
|
||||
|
||||
* 移除直接的事件绑定
|
||||
|
||||
### 2. 修改 closeTask 方法
|
||||
|
||||
* 同时删除数据和对应的 DOM 元素
|
||||
|
||||
### 3. 添加事件委托(在初始化时绑定)
|
||||
|
||||
* 使用事件委托绑定 `.g3-task-close` 点击事件
|
||||
|
||||
### 4. 检查 pointer-events 样式
|
||||
|
||||
* 确保 `.g3-task-close` 按钮可点击
|
||||
|
||||
## 修改文件
|
||||
|
||||
* `d:\workspace\code\file-preview\g3-file\index.js`
|
||||
|
||||
## 修改步骤
|
||||
|
||||
1. 在 `renderTaskCenter` 的 HTML 模板中添加 `data-task-id`
|
||||
2. 移除 `renderTaskCenter` 中的直接事件绑定
|
||||
3. 修改 `closeTask` 方法,添加 DOM 删除逻辑
|
||||
4. 在初始化时添加事件委托绑定
|
||||
|
||||
## 风险评估
|
||||
|
||||
* 低风险:修改局部代码,不影响其他功能
|
||||
|
||||
* 需确保事件委托只绑定一次
|
||||
|
||||
## 验证方式
|
||||
|
||||
1. 点击关闭按钮,检查控制台是否输出正确的 taskId
|
||||
2. 确认任务数据和 UI 都被正确移除
|
||||
|
||||
@@ -0,0 +1,431 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>G3File Demo</title>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script type="text/javascript" src="./js/jquery-easyui-1.4/jquery.min.js"></script>
|
||||
|
||||
<!-- G3File 依赖 -->
|
||||
<script type="text/javascript" src="./g3-file/language.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/icon.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/common.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/index.js"></script>
|
||||
|
||||
<!-- 样式 -->
|
||||
<link rel="stylesheet" href="./g3-file/index.css" />
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #ffffff;
|
||||
padding: 20px 30px;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 24px;
|
||||
color: #1f2329;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header p {
|
||||
font-size: 14px;
|
||||
color: #646a73;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 30px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid #f0f1f5;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 16px;
|
||||
color: #1f2329;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #f5f7fa;
|
||||
border-color: #c0c4cc;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #5D87FF;
|
||||
border-color: #5D87FF;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #4a6fcf;
|
||||
border-color: #4a6fcf;
|
||||
}
|
||||
|
||||
.file-container {
|
||||
height: 400px;
|
||||
border: 1px dashed #dcdfe6;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.console {
|
||||
background: #1f2329;
|
||||
color: #e6e6e6;
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
font-size: 13px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.console .log {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.console .success {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.console .warning {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.console .error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #ecf5ff;
|
||||
border-left: 4px solid #5D87FF;
|
||||
padding: 16px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
margin: 0;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #f0f1f5;
|
||||
}
|
||||
|
||||
.tab {
|
||||
font-size: 14px;
|
||||
color: #646a73;
|
||||
cursor: pointer;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #5D87FF;
|
||||
border-bottom-color: #5D87FF;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
font-size: 13px;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>G3File 文件管理组件</h1>
|
||||
<p>演示文件上传、预览、下载、删除等功能</p>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- 基础功能演示 -->
|
||||
<div class="demo-section">
|
||||
<div class="section-header">
|
||||
<h2>基础功能演示</h2>
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="reloadFiles()">重新加载</button>
|
||||
<button class="btn" onclick="clearSelection()">清空选择</button>
|
||||
<button class="btn btn-primary" onclick="addFiles()">添加文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<div class="info-box">
|
||||
<p><strong>提示:</strong>双击文件可预览(如果配置了预览地址且文件已上传),或触发自定义双击事件。</p>
|
||||
</div>
|
||||
<div id="basicDemo" class="file-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 回调事件演示 -->
|
||||
<div class="demo-section">
|
||||
<div class="section-header">
|
||||
<h2>回调事件演示</h2>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<div class="info-box">
|
||||
<p><strong>提示:</strong>操作文件时,下方控制台会显示相应的回调信息。</p>
|
||||
</div>
|
||||
<div id="eventDemo" class="file-container"></div>
|
||||
<div style="margin-top: 20px;">
|
||||
<h3 style="font-size: 14px; margin-bottom: 10px; color: #606266;">事件日志:</h3>
|
||||
<div id="eventConsole" class="console"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API 操作演示 -->
|
||||
<div class="demo-section">
|
||||
<div class="section-header">
|
||||
<h2>API 操作演示</h2>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<div class="button-group">
|
||||
<button class="btn" onclick="getSelected()">获取选中文件</button>
|
||||
<button class="btn" onclick="getFileCount()">获取文件数量</button>
|
||||
<button class="btn" onclick="updateFileList()">更新文件列表</button>
|
||||
<button class="btn btn-primary" onclick="destroyComponent()">销毁组件</button>
|
||||
</div>
|
||||
<div id="apiDemo" class="file-container"></div>
|
||||
<div style="margin-top: 20px;">
|
||||
<h3 style="font-size: 14px; margin-bottom: 10px; color: #606266;">API 调用结果:</h3>
|
||||
<div id="apiResult" class="console"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 全局变量存储组件实例
|
||||
var basicFile = null;
|
||||
var eventFile = null;
|
||||
var apiFile = null;
|
||||
|
||||
// 模拟文件数据
|
||||
var mockFiles = [
|
||||
{
|
||||
name: '项目需求文档.pdf',
|
||||
size: 2048000,
|
||||
uploadDate: '2024-01-15T10:30:00',
|
||||
url: 'http://118.89.70.199:9000/test/DC2A4692147D10C9C7B48A7EA29BCBA8.jpg'
|
||||
},
|
||||
{
|
||||
name: '设计稿.png',
|
||||
size: 1536000,
|
||||
uploadDate: '2024-01-16T14:20:00',
|
||||
url: ''
|
||||
},
|
||||
{
|
||||
name: '数据报表.xlsx',
|
||||
size: 1024000,
|
||||
uploadDate: '2024-01-17T09:15:00',
|
||||
url: 'http://118.89.70.199:9000/test/data.xlsx'
|
||||
},
|
||||
{
|
||||
name: '会议记录.docx',
|
||||
size: 512000,
|
||||
uploadDate: '2024-01-18T16:45:00',
|
||||
url: ''
|
||||
}
|
||||
];
|
||||
|
||||
function logEvent(type, message) {
|
||||
var consoleEl = document.getElementById('eventConsole');
|
||||
var colorClass = 'log';
|
||||
if (type === 'success') colorClass = 'success';
|
||||
else if (type === 'warning') colorClass = 'warning';
|
||||
else if (type === 'error') colorClass = 'error';
|
||||
|
||||
var time = new Date().toLocaleTimeString();
|
||||
consoleEl.innerHTML += '<span class="' + colorClass + '">[' + time + '] ' + message + '</span>\n';
|
||||
consoleEl.scrollTop = consoleEl.scrollHeight;
|
||||
}
|
||||
|
||||
function logApiResult(message) {
|
||||
var resultEl = document.getElementById('apiResult');
|
||||
var time = new Date().toLocaleTimeString();
|
||||
resultEl.innerHTML += '[' + time + '] ' + message + '\n';
|
||||
resultEl.scrollTop = resultEl.scrollHeight;
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// 基础功能演示
|
||||
basicFile = $('#basicDemo').G3File({
|
||||
data: mockFiles,
|
||||
previewUrl: 'https://sxox.g3soft.cn:8012/onlinePreview?url=',
|
||||
customActionMenu: function (file) {
|
||||
return [
|
||||
{
|
||||
title: '审核',
|
||||
onClick: function (f) {
|
||||
alert('审核文件: ' + f.name);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '编辑',
|
||||
onClick: function (f) {
|
||||
alert('编辑文件: ' + f.name);
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
// 回调事件演示
|
||||
eventFile = $('#eventDemo').G3File({
|
||||
data: mockFiles.slice(0, 2),
|
||||
onSelect: function (files) {
|
||||
logEvent('success', 'onSelect: 选中了 ' + files.length + ' 个文件');
|
||||
},
|
||||
onUpload: function (pendingFiles) {
|
||||
logEvent('success', 'onUpload: 开始上传 ' + pendingFiles.length + ' 个文件');
|
||||
},
|
||||
onUploadBefore: function (pendingFiles) {
|
||||
logEvent('warning', 'onUploadBefore: 准备上传 ' + pendingFiles.length + ' 个文件');
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
logEvent('success', 'onUploadBefore: 确认上传');
|
||||
resolve(true);
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
onUploadSuccess: function (file) {
|
||||
logEvent('success', 'onUploadSuccess: 上传成功 - ' + file.name);
|
||||
},
|
||||
onUploadError: function (file, error) {
|
||||
logEvent('error', 'onUploadError: 上传失败 - ' + file.name + ', 错误: ' + error);
|
||||
},
|
||||
onUploadComplete: function (successCount, failCount) {
|
||||
logEvent('success', 'onUploadComplete: 上传完成 - ' + successCount + '成功, ' + failCount + '失败');
|
||||
},
|
||||
onDelete: function (files) {
|
||||
logEvent('success', 'onDelete: 删除了 ' + files.length + ' 个文件');
|
||||
}
|
||||
});
|
||||
|
||||
// API 操作演示
|
||||
apiFile = $('#apiDemo').G3File({
|
||||
data: mockFiles.slice(2),
|
||||
onSelect: function (files) {
|
||||
logApiResult('选中文件: ' + files.length + ' 个');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 基础演示操作
|
||||
function reloadFiles() {
|
||||
basicFile.setFiles(mockFiles);
|
||||
alert('文件已重新加载');
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
basicFile.updateState({ selectedFiles: [] });
|
||||
}
|
||||
|
||||
function addFiles() {
|
||||
basicFile.$btnSelect.click();
|
||||
}
|
||||
|
||||
// API 演示操作
|
||||
function getSelected() {
|
||||
var selected = apiFile.getSelectedFiles();
|
||||
logApiResult('选中的文件: ' + selected.map(f => f.name).join(', ') || '无');
|
||||
}
|
||||
|
||||
function getFileCount() {
|
||||
var count = apiFile.files.length;
|
||||
var uploadedCount = apiFile.getUploadedFiles().length;
|
||||
logApiResult('文件总数: ' + count + ', 已上传: ' + uploadedCount);
|
||||
}
|
||||
|
||||
function updateFileList() {
|
||||
var newFiles = [
|
||||
{
|
||||
name: '新文件_' + Date.now() + '.txt',
|
||||
size: 1024,
|
||||
uploadDate: new Date().toISOString(),
|
||||
url: ''
|
||||
}
|
||||
];
|
||||
apiFile.setFiles(newFiles);
|
||||
logApiResult('文件列表已更新');
|
||||
}
|
||||
|
||||
function destroyComponent() {
|
||||
if (confirm('确定要销毁组件吗?')) {
|
||||
apiFile.destroy();
|
||||
$('#apiDemo').html('<p style="text-align:center; padding:50px; color:#999;">组件已销毁</p>');
|
||||
logApiResult('组件已销毁');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,288 @@
|
||||
# G3File 文件管理组件
|
||||
|
||||
## 概述
|
||||
|
||||
G3File 是一个基于 jQuery 的文件管理组件,提供文件上传、预览、下载、删除等功能,支持阿里云 OSS 上传和自定义上传。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
g3-file/
|
||||
├── index.js # 主组件代码
|
||||
├── index.css # 样式文件
|
||||
├── common.js # 工具函数
|
||||
├── icon.js # 图标定义
|
||||
├── language.js # 语言配置
|
||||
└── libs/ # 第三方依赖
|
||||
├── FileSaver.min.js
|
||||
└── jszip.min.js
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 引入依赖
|
||||
|
||||
```html
|
||||
<!-- jQuery -->
|
||||
<script src="path/to/jquery.min.js"></script>
|
||||
|
||||
<!-- G3File 依赖 -->
|
||||
<script src="g3-file/language.js"></script>
|
||||
<script src="g3-file/icon.js"></script>
|
||||
<script src="g3-file/common.js"></script>
|
||||
<script src="g3-file/index.js"></script>
|
||||
<link rel="stylesheet" href="g3-file/index.css" />
|
||||
```
|
||||
|
||||
### 初始化组件
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
data: [
|
||||
{
|
||||
name: 'example.pdf',
|
||||
size: 1024000,
|
||||
uploadDate: '2024-01-15T10:30:00',
|
||||
url: 'http://example.com/example.pdf'
|
||||
}
|
||||
],
|
||||
previewUrl: 'https://preview.example.com?url=',
|
||||
onUploadSuccess: function(file) {
|
||||
console.log('上传成功:', file);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### 基础配置
|
||||
|
||||
| 配置项 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| `data` | Array | `[]` | 初始化时的文件数据 |
|
||||
| `mode` | String | `'aliyun'` | 上传模式 |
|
||||
| `language` | String | `'zh-CN'` | 语言(zh-CN/en/ru) |
|
||||
| `maxFileSize` | Number | `10485760` | 最大文件大小(字节) |
|
||||
| `previewUrl` | String | `''` | 文件预览服务地址 |
|
||||
|
||||
### 回调函数
|
||||
|
||||
| 配置项 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| `onDeleteBefore` | `files` | 删除前回调,返回 false/Promise/Function 可阻止删除 |
|
||||
| `onDelete` | `files` | 删除后回调 |
|
||||
| `onDownload` | `files` | 下载回调 |
|
||||
| `onSelect` | `files` | 文件选中回调 |
|
||||
| `onUpload` | `pendingFiles` | 上传开始回调 |
|
||||
| `onUploadBefore` | `pendingFiles` | 上传前回调,返回 false/Promise/Function 可阻止上传 |
|
||||
| `onUploadSuccess` | `file` | 单个文件上传成功回调 |
|
||||
| `onUploadError` | `file`, `error` | 单个文件上传失败回调 |
|
||||
| `onUploadComplete` | `successCount`, `failCount` | 全部上传完成回调 |
|
||||
| `onDblClick` | `file` | 文件双击回调,优先于默认预览行为 |
|
||||
| `customActionMenu` | `file` | 自定义操作菜单,返回菜单项数组 |
|
||||
|
||||
### 上传配置
|
||||
|
||||
```javascript
|
||||
uploadConfig: {
|
||||
aliyun: {
|
||||
getAliyunKey: function() {
|
||||
// 返回 Promise,包含阿里云 OSS 凭证
|
||||
return Promise.resolve({
|
||||
accessid: 'your-access-key',
|
||||
callback: '',
|
||||
dir: 'upload/',
|
||||
expire: 1704067200,
|
||||
host: 'https://your-bucket.oss-cn-hangzhou.aliyuncs.com',
|
||||
policy: 'your-policy',
|
||||
signature: 'your-signature'
|
||||
});
|
||||
}
|
||||
},
|
||||
customUpload: null // 自定义上传函数
|
||||
}
|
||||
```
|
||||
|
||||
### 权限配置
|
||||
|
||||
```javascript
|
||||
globalPermission: {
|
||||
upload: true, // 是否允许上传
|
||||
download: true, // 是否允许下载
|
||||
delete: true, // 是否允许删除
|
||||
view: true // 是否允许查看
|
||||
}
|
||||
```
|
||||
|
||||
## 文件数据结构
|
||||
|
||||
```javascript
|
||||
{
|
||||
_id: 'unique-id', // 文件唯一标识符(自动生成)
|
||||
name: 'example.pdf', // 文件名
|
||||
size: 1024000, // 文件大小(字节)
|
||||
uploadDate: '2024-01-15T10:30:00', // 上传日期(ISO格式)
|
||||
url: 'http://example.com/example.pdf', // 文件访问URL
|
||||
file: null, // 本地File对象(仅待上传文件有)
|
||||
status: 'uploaded' // 文件状态:pending/uploading/uploaded/failed
|
||||
}
|
||||
```
|
||||
|
||||
## API 方法
|
||||
|
||||
### setFiles(files)
|
||||
|
||||
设置文件列表,替换现有文件
|
||||
|
||||
```javascript
|
||||
file.setFiles([
|
||||
{ name: 'file1.pdf', size: 1024, uploadDate: '2024-01-01', url: '' },
|
||||
{ name: 'file2.jpg', size: 2048, uploadDate: '2024-01-02', url: 'http://example.com/file2.jpg' }
|
||||
]);
|
||||
```
|
||||
|
||||
### getFileById(fileId)
|
||||
|
||||
根据文件ID获取文件对象
|
||||
|
||||
```javascript
|
||||
var file = file.getFileById('file_123');
|
||||
```
|
||||
|
||||
### getSelectedFiles()
|
||||
|
||||
获取当前选中的文件列表
|
||||
|
||||
```javascript
|
||||
var selected = file.getSelectedFiles();
|
||||
```
|
||||
|
||||
### updateState(state)
|
||||
|
||||
更新组件状态
|
||||
|
||||
```javascript
|
||||
// 清空选择
|
||||
file.updateState({ selectedFiles: [] });
|
||||
```
|
||||
|
||||
### destroy()
|
||||
|
||||
销毁组件,清理资源
|
||||
|
||||
```javascript
|
||||
file.destroy();
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 示例1:基础用法
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
data: [],
|
||||
previewUrl: 'https://preview.example.com?url=',
|
||||
onUploadSuccess: function(file) {
|
||||
console.log('上传成功:', file.name);
|
||||
},
|
||||
onDelete: function(files) {
|
||||
console.log('删除文件:', files.length);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 示例2:双击事件
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
onDblClick: function(file) {
|
||||
// 自定义双击处理,优先于默认预览行为
|
||||
alert('双击了文件: ' + file.name);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 示例3:上传前确认
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
onUploadBefore: function(pendingFiles) {
|
||||
// 返回 Promise 进行异步确认
|
||||
return new Promise((resolve) => {
|
||||
if (confirm('确定上传 ' + pendingFiles.length + ' 个文件?')) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 示例4:自定义操作菜单
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
customActionMenu: function(file) {
|
||||
return [
|
||||
{
|
||||
title: '审核',
|
||||
onClick: function(file) {
|
||||
alert('审核文件: ' + file.name);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '编辑',
|
||||
onClick: function(file) {
|
||||
alert('编辑文件: ' + file.name);
|
||||
},
|
||||
disabled: false // 可选,是否禁用
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 示例5:删除前确认
|
||||
|
||||
```javascript
|
||||
var file = $('#fileContainer').G3File({
|
||||
onDeleteBefore: function(files) {
|
||||
// 返回 Promise 进行异步确认(与 onUploadBefore 用法一致)
|
||||
return new Promise((resolve) => {
|
||||
if (confirm('确定删除 ' + files.length + ' 个文件?')) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 事件处理
|
||||
|
||||
### 双击行为优先级
|
||||
|
||||
1. 如果配置了 `onDblClick` 回调,优先执行回调
|
||||
2. 如果未配置且文件已上传、可预览、有URL,则在新窗口打开预览
|
||||
|
||||
### 支持的预览文件类型
|
||||
|
||||
组件会排除以下不可预览的文件类型:
|
||||
- 压缩包:.rar, .zip, .7z, .tar, .gz, .bz2
|
||||
- 可执行文件:.exe, .dll, .bin, .msi, .cab, .rpm, .deb, .apk, .ipa
|
||||
- 数据库文件:.dat, .db, .sqlite
|
||||
- 临时文件:.bak, .tmp, .log, .cache
|
||||
- 光盘镜像:.iso
|
||||
|
||||
## 浏览器兼容性
|
||||
|
||||
支持 IE11+ 和现代浏览器(Chrome、Firefox、Safari、Edge)
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 使用阿里云 OSS 上传时,必须配置 `uploadConfig.aliyun.getAliyunKey` 函数
|
||||
2. 文件大小限制通过 `maxFileSize` 配置,默认 10MB
|
||||
3. 预览功能依赖 `previewUrl` 配置的外部预览服务
|
||||
4. 销毁组件时请调用 `destroy()` 方法,避免内存泄漏
|
||||
@@ -38,11 +38,7 @@ var G3FileIcons = {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from TDesign Icons by Tencent - https://github.com/Tencent/tdesign-icons/blob/main/LICENSE --><path fill="none" stroke="currentColor" stroke-linecap="square" stroke-width="2" d="M21 11V3H3v18h8m2-7l-4-4l-5.5 5.5m14.25-7.25a2 2 0 1 1-4 0a2 2 0 0 1 4 0Zm4.079 7.922L19 19m0 0l-2.828 2.829M19 19l-2.828-2.828M19 19l2.829 2.829"/></svg>
|
||||
`
|
||||
},
|
||||
modal: {
|
||||
minimize: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3M3 16h3a2 2 0 0 1 2 2v3m8 0v-3a2 2 0 0 1 2-2h3"/></svg>',
|
||||
maximize: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3M3 16v3a2 2 0 0 0 2 2h3m8 0h3a2 2 0 0 0 2-2v-3"/></svg>',
|
||||
close: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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="M18 6L6 18M6 6l12 12"/></svg>'
|
||||
},
|
||||
|
||||
toast: {
|
||||
success: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',
|
||||
error: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
border: 1px solid #eef0f2;
|
||||
border-radius: 8px;
|
||||
--g3-z-dropdown: 100;
|
||||
--g3-z-modal: 200;
|
||||
|
||||
--g3-z-toast: 300;
|
||||
--g3-z-task: 400;
|
||||
--g3-z-lock: 500;
|
||||
@@ -907,230 +907,4 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Modal 样式
|
||||
============================================================================ */
|
||||
|
||||
.g3-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: var(--g3-z-modal);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.g3-modal-overlay.is-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.g3-modal {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
opacity 0.3s ease;
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.g3-modal-overlay.is-visible .g3-modal {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.g3-modal.is-maximized {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.g3-modal-header {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
background: #fafbfc;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.g3-modal-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.g3-modal-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.g3-modal-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.g3-modal-btn:hover {
|
||||
background: #f0f2f5;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.g3-modal-btn-close:hover {
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.g3-modal-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.g3-modal-preview-toolbar {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.g3-modal-preview-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.g3-modal-preview-nav .g3-modal-preview-counter {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
min-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.g3-modal-preview-filename {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-left: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.g3-modal-preview-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.g3-modal-preview-btn:hover:not(:disabled) {
|
||||
border-color: #165dff;
|
||||
background: rgba(22, 93, 255, 0.05);
|
||||
color: #165dff;
|
||||
}
|
||||
|
||||
.g3-modal-preview-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.g3-modal-preview-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.g3-modal-preview-content .g3-modal-preview-placeholder {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.g3-modal-preview-content .g3-modal-preview-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.g3-modal-preview-content .g3-modal-preview-iframe.current {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.g3-modal-preview-content .g3-modal-preview-iframe.next {
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.g3-modal-footer {
|
||||
display: none;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0 16px;
|
||||
background: #fafbfc;
|
||||
border-top: 1px solid #eef0f2;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
padding: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.g3-modal-footer.has-content {
|
||||
display: flex;
|
||||
visibility: visible;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #eef0f2;
|
||||
}
|
||||
@@ -65,16 +65,17 @@
|
||||
*/
|
||||
data: [],
|
||||
mode: "aliyun",
|
||||
onBeforeDelete: null,
|
||||
onDeleteBefore: null,
|
||||
onDelete: null,
|
||||
onDownload: null,
|
||||
onSelect: null,
|
||||
onUpload: null,
|
||||
onUploadBefore: null,
|
||||
onDblClick: null,
|
||||
onUploadSuccess: null,
|
||||
onUploadError: null,
|
||||
onUploadComplete: null,
|
||||
onPreview: null,
|
||||
getActionMenu: null,
|
||||
customActionMenu: null,
|
||||
language: "zh-CN",
|
||||
maxFileSize: 10 * 1024 * 1024,
|
||||
// 上传配置
|
||||
@@ -313,23 +314,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-global-menu"></div>
|
||||
<div class="g3-modal-overlay">
|
||||
<div class="g3-modal">
|
||||
<div class="g3-modal-header">
|
||||
<span class="g3-modal-title"></span>
|
||||
<div class="g3-modal-actions">
|
||||
<button class="g3-modal-btn g3-modal-btn-toggle" title="${this.language.modal.maximize}">
|
||||
${G3FileIcons.modal.maximize}
|
||||
</button>
|
||||
<button class="g3-modal-btn g3-modal-btn-close" title="${this.language.modal.close}">
|
||||
${G3FileIcons.modal.close}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-modal-body"></div>
|
||||
<div class="g3-modal-footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -353,14 +337,6 @@
|
||||
this.$previewName = this.$container.find(".g3-preview-name");
|
||||
this.$previewCounter = this.$container.find(".g3-preview-counter");
|
||||
|
||||
this.$modalOverlay = this.$container.find(".g3-modal-overlay");
|
||||
this.$modal = this.$container.find(".g3-modal");
|
||||
this.$modalTitle = this.$container.find(".g3-modal-title");
|
||||
this.$modalBody = this.$container.find(".g3-modal-body");
|
||||
this.$modalBtnToggle = this.$container.find(".g3-modal-btn-toggle");
|
||||
this.$modalBtnClose = this.$container.find(".g3-modal-btn-close");
|
||||
this.$modalFooter = this.$container.find(".g3-modal-footer");
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -431,7 +407,10 @@
|
||||
|
||||
var rect = $anchor[0].getBoundingClientRect();
|
||||
var $mainContainer = this.$container.find(".main");
|
||||
var mainRect = $mainContainer.length > 0 ? $mainContainer[0].getBoundingClientRect() : null;
|
||||
var mainRect =
|
||||
$mainContainer.length > 0
|
||||
? $mainContainer[0].getBoundingClientRect()
|
||||
: null;
|
||||
|
||||
var menuWidth = 160;
|
||||
var itemHeight = 36;
|
||||
@@ -549,12 +528,18 @@
|
||||
|
||||
// <span>${G3FileUtils.formatDate(file.uploadDate)}</span>
|
||||
|
||||
var actionMenuItems = (this.options.getActionMenu && this.options.getActionMenu(file)) || [];
|
||||
var moreActionHtml = actionMenuItems && actionMenuItems.length > 0 ? `
|
||||
var actionMenuItems =
|
||||
(this.options.customActionMenu &&
|
||||
this.options.customActionMenu(file)) ||
|
||||
[];
|
||||
var moreActionHtml =
|
||||
actionMenuItems && actionMenuItems.length > 0
|
||||
? `
|
||||
<div class="g3-file-action g3-action-more" title="${this.language.more}">
|
||||
${G3FileIcons.action.more}
|
||||
</div>
|
||||
` : "";
|
||||
`
|
||||
: "";
|
||||
|
||||
return `
|
||||
<div class="g3-file-item" data-id="${file._id}">
|
||||
@@ -845,7 +830,10 @@
|
||||
var $currentIframe = $content.find(".g3-preview-iframe.current");
|
||||
var $nextIframe = $content.find(".g3-preview-iframe.next");
|
||||
|
||||
if ($nextIframe.length && this.previewCache.nextUrl === fullPreviewUrl) {
|
||||
if (
|
||||
$nextIframe.length &&
|
||||
this.previewCache.nextUrl === fullPreviewUrl
|
||||
) {
|
||||
$currentIframe.removeClass("current").addClass("next").hide();
|
||||
$nextIframe.removeClass("next").addClass("current").show();
|
||||
this.previewCache.currentUrl = fullPreviewUrl;
|
||||
@@ -880,12 +868,14 @@
|
||||
|
||||
newIframe.on("error", function () {
|
||||
newIframe.remove();
|
||||
self.showPlaceholder($content, `<p class="g3-url-error">${self.language.urlError}</p>`);
|
||||
self.showPlaceholder(
|
||||
$content,
|
||||
`<p class="g3-url-error">${self.language.urlError}</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
$content.append(newIframe);
|
||||
this.previewCache.nextUrl = fullPreviewUrl;
|
||||
|
||||
} else {
|
||||
this.previewCache = null;
|
||||
var tipsHtml = "";
|
||||
@@ -910,285 +900,6 @@
|
||||
`);
|
||||
},
|
||||
|
||||
showModalPlaceholder: function ($container, tipsHtml) {
|
||||
$container.find(".g3-modal-preview-iframe").remove();
|
||||
$container.html(`
|
||||
<div class="g3-modal-preview-placeholder">
|
||||
${tipsHtml}
|
||||
</div>
|
||||
`);
|
||||
},
|
||||
|
||||
openModal: function (options) {
|
||||
var defaults = {
|
||||
title: "",
|
||||
content: "",
|
||||
width: "80%",
|
||||
height: "80%",
|
||||
showToggle: true,
|
||||
showClose: true
|
||||
};
|
||||
|
||||
var opts = $.extend({}, defaults, options);
|
||||
|
||||
this.$modalTitle.text(opts.title || "");
|
||||
this.$modalBody.html(opts.content || "");
|
||||
|
||||
this.$modal.css({
|
||||
width: opts.width,
|
||||
height: opts.height
|
||||
});
|
||||
|
||||
this.$modalBtnToggle.toggle(opts.showToggle);
|
||||
this.$modalBtnClose.toggle(opts.showClose);
|
||||
|
||||
this.$modalOverlay.addClass("is-visible");
|
||||
this.$modal.removeClass("is-maximized");
|
||||
this.$modalBtnToggle.html(G3FileIcons.modal.maximize);
|
||||
this.$modalBtnToggle.attr("title", this.language.modal.maximize);
|
||||
},
|
||||
|
||||
openPreviewModal: function (fileId) {
|
||||
var file = this.getFileById(fileId);
|
||||
if (!file) return;
|
||||
|
||||
var isUploaded = file.status === "uploaded";
|
||||
var isPreviewable = this.isPreviewableFile(file.name);
|
||||
var fileUrl = file.url && file.url !== "" ? file.url : null;
|
||||
|
||||
var toolbarHtml = `
|
||||
<div class="g3-modal-preview-toolbar">
|
||||
<div class="g3-modal-preview-nav">
|
||||
<button class="g3-modal-preview-btn g3-modal-preview-prev" disabled>
|
||||
${G3FileIcons.preview.prev}
|
||||
</button>
|
||||
<span class="g3-modal-preview-counter">0/0</span>
|
||||
<button class="g3-modal-preview-btn g3-modal-preview-next" disabled>
|
||||
${G3FileIcons.preview.next}
|
||||
</button>
|
||||
</div>
|
||||
<div class="g3-modal-preview-filename">${file.name}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var contentHtml = "";
|
||||
if (isUploaded && fileUrl && isPreviewable) {
|
||||
var previewUrl = this.options.previewUrl || "";
|
||||
var fullPreviewUrl = previewUrl
|
||||
? previewUrl + G3FileUtils.base64Encode(fileUrl)
|
||||
: fileUrl;
|
||||
|
||||
contentHtml = `
|
||||
<div class="g3-modal-preview-content">
|
||||
<iframe
|
||||
src="${fullPreviewUrl}"
|
||||
class="g3-modal-preview-iframe current"
|
||||
frameborder="0"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
var tipsHtml = "";
|
||||
if (!isUploaded) {
|
||||
tipsHtml = `<p class="g3-upload-tip">${this.language.uploadToPreview}</p>`;
|
||||
} else if (!isPreviewable) {
|
||||
tipsHtml = `<p class="g3-cannot-preview">${this.language.downloadToPreview}</p>`;
|
||||
} else if (!fileUrl) {
|
||||
tipsHtml = `<p class="g3-url-error">${this.language.urlError}</p>`;
|
||||
}
|
||||
|
||||
contentHtml = `
|
||||
<div class="g3-modal-preview-content">
|
||||
<div class="g3-modal-preview-placeholder">
|
||||
${tipsHtml}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
var previewContent = toolbarHtml + contentHtml;
|
||||
|
||||
this.currentModalFileId = fileId;
|
||||
|
||||
this.openModal({
|
||||
title: this.language.filePreview,
|
||||
content: previewContent,
|
||||
width: "90%",
|
||||
height: "90%",
|
||||
});
|
||||
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
self.$modal.find(".g3-modal-preview-prev").off("click").on("click", function () {
|
||||
self.modalPrev();
|
||||
});
|
||||
self.$modal.find(".g3-modal-preview-next").off("click").on("click", function () {
|
||||
self.modalNext();
|
||||
});
|
||||
self.updateModalPreviewCounter(fileId);
|
||||
}, 0);
|
||||
},
|
||||
|
||||
updateModalPreviewCounter: function (fileId) {
|
||||
var allFiles = this.getUploadedFiles();
|
||||
var currentIndex = allFiles.findIndex(function (f) { return f._id === fileId; });
|
||||
var total = allFiles.length;
|
||||
|
||||
var $counter = this.$modal.find(".g3-modal-preview-counter");
|
||||
var $prevBtn = this.$modal.find(".g3-modal-preview-prev");
|
||||
var $nextBtn = this.$modal.find(".g3-modal-preview-next");
|
||||
|
||||
if ($counter.length) {
|
||||
$counter.text((currentIndex + 1) + "/" + total);
|
||||
}
|
||||
if ($prevBtn.length) {
|
||||
$prevBtn.prop("disabled", currentIndex === 0);
|
||||
}
|
||||
if ($nextBtn.length) {
|
||||
$nextBtn.prop("disabled", currentIndex === total - 1);
|
||||
}
|
||||
},
|
||||
|
||||
modalPrev: function () {
|
||||
var uploadedFiles = this.getUploadedFiles();
|
||||
if (uploadedFiles.length === 0) return;
|
||||
|
||||
var currentIndex = this.getPreviewFileIndex(this.currentModalFileId);
|
||||
var newIndex = currentIndex > 0 ? currentIndex - 1 : uploadedFiles.length - 1;
|
||||
this.currentModalFileId = uploadedFiles[newIndex]._id;
|
||||
this.updateModalPreviewWithFile(uploadedFiles[newIndex]);
|
||||
},
|
||||
|
||||
modalNext: function () {
|
||||
var uploadedFiles = this.getUploadedFiles();
|
||||
if (uploadedFiles.length === 0) return;
|
||||
|
||||
var currentIndex = this.getPreviewFileIndex(this.currentModalFileId);
|
||||
var newIndex = currentIndex < uploadedFiles.length - 1 ? currentIndex + 1 : 0;
|
||||
this.currentModalFileId = uploadedFiles[newIndex]._id;
|
||||
this.updateModalPreviewWithFile(uploadedFiles[newIndex]);
|
||||
},
|
||||
|
||||
updateModalPreviewWithFile: function (file) {
|
||||
var $content = this.$modal.find(".g3-modal-preview-content");
|
||||
var $title = this.$modal.find(".g3-modal-title");
|
||||
var $filename = this.$modal.find(".g3-modal-preview-filename");
|
||||
|
||||
if (!file || !$content.length) return;
|
||||
|
||||
$title.text(this.language.filePreview);
|
||||
if ($filename.length) {
|
||||
$filename.text(file.name);
|
||||
}
|
||||
|
||||
var isUploaded = file.status === "uploaded";
|
||||
var isPreviewable = this.isPreviewableFile(file.name);
|
||||
var fileUrl = file.url && file.url !== "" ? file.url : null;
|
||||
|
||||
if (isUploaded && fileUrl && isPreviewable) {
|
||||
var previewUrl = this.options.previewUrl || "";
|
||||
var fullPreviewUrl = previewUrl
|
||||
? previewUrl + G3FileUtils.base64Encode(fileUrl)
|
||||
: fileUrl;
|
||||
|
||||
var newIframe = $(`
|
||||
<iframe
|
||||
src="${fullPreviewUrl}"
|
||||
class="g3-modal-preview-iframe"
|
||||
frameborder="0"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
`);
|
||||
|
||||
$content.html(newIframe);
|
||||
} else {
|
||||
var tipsHtml = "";
|
||||
if (!isUploaded) {
|
||||
tipsHtml = `<p class="g3-upload-tip">${this.language.uploadToPreview}</p>`;
|
||||
} else if (!isPreviewable) {
|
||||
tipsHtml = `<p class="g3-cannot-preview">${this.language.downloadToPreview}</p>`;
|
||||
} else if (!fileUrl) {
|
||||
tipsHtml = `<p class="g3-url-error">${this.language.urlError}</p>`;
|
||||
}
|
||||
|
||||
$content.html(`
|
||||
<div class="g3-modal-preview-placeholder">
|
||||
${tipsHtml}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
this.updateModalPreviewCounter(file._id);
|
||||
},
|
||||
|
||||
closeModal: function () {
|
||||
this.$modalOverlay.removeClass("is-visible");
|
||||
this.$modalBody.html("");
|
||||
this.$modalTitle.text("");
|
||||
this.setModalFooter("");
|
||||
this.currentModalFileId = null;
|
||||
},
|
||||
|
||||
toggleModalSize: function () {
|
||||
var isMaximized = this.$modal.hasClass("is-maximized");
|
||||
|
||||
if (isMaximized) {
|
||||
this.$modal.removeClass("is-maximized");
|
||||
this.$modal.css({
|
||||
width: "80%",
|
||||
height: "80%",
|
||||
maxWidth: "none",
|
||||
borderRadius: "8px"
|
||||
});
|
||||
this.$modalBtnToggle.html(G3FileIcons.modal.maximize);
|
||||
this.$modalBtnToggle.attr("title", this.language.modal.maximize);
|
||||
} else {
|
||||
this.$modal.addClass("is-maximized");
|
||||
this.$modal.css({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
maxWidth: "none",
|
||||
borderRadius: "0"
|
||||
});
|
||||
this.$modalBtnToggle.html(G3FileIcons.modal.restore);
|
||||
this.$modalBtnToggle.attr("title", this.language.modal.restore);
|
||||
}
|
||||
},
|
||||
|
||||
setModalTitle: function (title) {
|
||||
if (this.$modalTitle) {
|
||||
this.$modalTitle.text(title || "");
|
||||
}
|
||||
},
|
||||
|
||||
setModalContent: function (content) {
|
||||
if (this.$modalBody) {
|
||||
this.$modalBody.html(content || "");
|
||||
}
|
||||
},
|
||||
|
||||
setModalSize: function (width, height) {
|
||||
if (!this.$modal) return;
|
||||
|
||||
this.$modal.css({
|
||||
width: width || "80%",
|
||||
height: height || "80%"
|
||||
});
|
||||
},
|
||||
|
||||
setModalFooter: function (content) {
|
||||
if (!this.$modalFooter) return;
|
||||
|
||||
if (content && content.trim()) {
|
||||
this.$modalFooter.html(content);
|
||||
this.$modalFooter.addClass("has-content");
|
||||
} else {
|
||||
this.$modalFooter.html("");
|
||||
this.$modalFooter.removeClass("has-content");
|
||||
}
|
||||
},
|
||||
|
||||
setPreviewFile: function (fileId) {
|
||||
var file = this.getFileById(fileId);
|
||||
if (file) {
|
||||
@@ -1352,9 +1063,6 @@
|
||||
if (!file) return;
|
||||
if (!self.hasPermission(file, "view")) return;
|
||||
self.setPreviewFile(id);
|
||||
if (typeof self.options.onPreview === "function") {
|
||||
self.options.onPreview([file]);
|
||||
}
|
||||
})
|
||||
// 下载按钮
|
||||
.on("click", ".g3-action-download", function (e) {
|
||||
@@ -1399,12 +1107,9 @@
|
||||
var file = self.getFileById(id);
|
||||
if (!file) return;
|
||||
if (!self.hasPermission(file, "view")) return;
|
||||
if (typeof self.options.onPreview === "function") {
|
||||
self.options.onPreview([file]);
|
||||
}
|
||||
self.setPreviewFile(id);
|
||||
})
|
||||
// 文件项双击打开 modal 预览
|
||||
// 文件项双击
|
||||
.on("dblclick", ".g3-file-item", function (e) {
|
||||
if (
|
||||
$(e.target).closest(
|
||||
@@ -1417,8 +1122,25 @@
|
||||
var file = self.getFileById(id);
|
||||
if (!file) return;
|
||||
if (!self.hasPermission(file, "view")) return;
|
||||
self.openPreviewModal(id);
|
||||
|
||||
if (typeof self.options.onDblClick === "function") {
|
||||
self.options.onDblClick(file);
|
||||
return;
|
||||
}
|
||||
|
||||
var isUploaded = file.status === "uploaded";
|
||||
var isPreviewable = self.isPreviewableFile(file.name);
|
||||
var fileUrl = file.url && file.url !== "" ? file.url : null;
|
||||
|
||||
if (isUploaded && fileUrl && isPreviewable) {
|
||||
var previewUrl = self.options.previewUrl || "";
|
||||
var fullPreviewUrl = previewUrl
|
||||
? previewUrl + G3FileUtils.base64Encode(fileUrl)
|
||||
: fileUrl;
|
||||
window.open(fullPreviewUrl, "_blank");
|
||||
}
|
||||
})
|
||||
|
||||
// 更多按钮
|
||||
.on("click", ".g3-action-more", function (e) {
|
||||
e.preventDefault();
|
||||
@@ -1437,23 +1159,6 @@
|
||||
self.openActionMenu($el, file);
|
||||
});
|
||||
|
||||
// Modal 事件绑定
|
||||
this.$modalBtnClose.off("click").on("click", function () {
|
||||
self.closeModal();
|
||||
});
|
||||
|
||||
this.$modalBtnToggle.off("click").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.toggleModalSize();
|
||||
});
|
||||
|
||||
this.$modalOverlay.off("click").on("click", function (e) {
|
||||
if (e.target === this) {
|
||||
self.closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 任务关闭按钮事件委托
|
||||
this.$container.on("click", ".g3-task-close", function (e) {
|
||||
e.preventDefault();
|
||||
@@ -1575,8 +1280,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.options.onBeforeDelete === "function") {
|
||||
var result = this.options.onBeforeDelete(files);
|
||||
if (typeof this.options.onDeleteBefore === "function") {
|
||||
var result = this.options.onDeleteBefore(files);
|
||||
if (result === false) return;
|
||||
if (typeof result.then === "function") {
|
||||
result.then(function (confirmed) {
|
||||
@@ -1881,6 +1586,39 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.options.onUploadBefore === "function") {
|
||||
var result = this.options.onUploadBefore(pendingFiles);
|
||||
if (result === false) return;
|
||||
if (typeof result.then === "function") {
|
||||
result.then(function (confirmed) {
|
||||
if (confirmed)
|
||||
self.internalHandleUpload(
|
||||
pendingFiles,
|
||||
customUpload,
|
||||
concurrency,
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof result === "function") {
|
||||
result(function (confirmed) {
|
||||
if (confirmed)
|
||||
self.internalHandleUpload(
|
||||
pendingFiles,
|
||||
customUpload,
|
||||
concurrency,
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.internalHandleUpload(pendingFiles, customUpload, concurrency);
|
||||
},
|
||||
|
||||
internalHandleUpload: function (pendingFiles, customUpload, concurrency) {
|
||||
var self = this;
|
||||
|
||||
var total = pendingFiles.length;
|
||||
var taskId = this.startTask({
|
||||
id: G3FileUtils.generateUniqueId(),
|
||||
@@ -2273,7 +2011,9 @@
|
||||
*/
|
||||
openActionMenu: function ($el, file) {
|
||||
var items =
|
||||
(this.options.getActionMenu && this.options.getActionMenu(file)) || [];
|
||||
(this.options.customActionMenu &&
|
||||
this.options.customActionMenu(file)) ||
|
||||
[];
|
||||
|
||||
this.actionMenuState = {
|
||||
open: true,
|
||||
@@ -2404,10 +2144,7 @@
|
||||
}
|
||||
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
partialState,
|
||||
"globalPermission",
|
||||
)
|
||||
Object.prototype.hasOwnProperty.call(partialState, "globalPermission")
|
||||
) {
|
||||
this.updatePermissions(partialState.globalPermission);
|
||||
}
|
||||
|
||||
@@ -57,12 +57,7 @@ var G3FileLanguages = {
|
||||
currentItem: "当前项",
|
||||
close: "关闭",
|
||||
},
|
||||
modal: {
|
||||
maximize: "全屏",
|
||||
restore: "恢复",
|
||||
close: "关闭",
|
||||
},
|
||||
},
|
||||
"en-US": {
|
||||
selectAll: "Select All",
|
||||
download: "Download",
|
||||
@@ -123,12 +118,7 @@ var G3FileLanguages = {
|
||||
currentItem: "Current",
|
||||
close: "Close",
|
||||
},
|
||||
modal: {
|
||||
maximize: "Maximize",
|
||||
restore: "Restore",
|
||||
close: "Close",
|
||||
},
|
||||
},
|
||||
"ru": {
|
||||
selectAll: "Выделить все",
|
||||
download: "Скачать",
|
||||
@@ -187,10 +177,5 @@ var G3FileLanguages = {
|
||||
currentItem: "Текущий",
|
||||
close: "Закрыть",
|
||||
},
|
||||
modal: {
|
||||
maximize: "На весь экран",
|
||||
restore: "Восстановить",
|
||||
close: "Закрыть",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>G3File iframe 演示</title>
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #1f2329;
|
||||
min-height: 100vh;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 28px;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header p {
|
||||
font-size: 14px;
|
||||
color: #8f959e;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.iframe-wrapper {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.iframe-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 20px;
|
||||
background: #f5f7fa;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dot.red {
|
||||
background: #ff5f56;
|
||||
}
|
||||
|
||||
.dot.yellow {
|
||||
background: #ffbd2e;
|
||||
}
|
||||
|
||||
.dot.green {
|
||||
background: #27ca40;
|
||||
}
|
||||
|
||||
.iframe-title {
|
||||
font-size: 13px;
|
||||
color: #646a73;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info-panel h3 {
|
||||
font-size: 14px;
|
||||
color: #ffffff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info-panel ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.info-panel li {
|
||||
font-size: 13px;
|
||||
color: #8f959e;
|
||||
padding: 5px 0;
|
||||
padding-left: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-panel li::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
color: #5D87FF;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>G3File 文件管理组件</h1>
|
||||
<p>通过 iframe 嵌入展示</p>
|
||||
</div>
|
||||
|
||||
<div class="iframe-wrapper">
|
||||
<div class="iframe-header">
|
||||
<div class="dot red"></div>
|
||||
<div class="dot yellow"></div>
|
||||
<div class="dot green"></div>
|
||||
<span class="iframe-title">index.html</span>
|
||||
</div>
|
||||
<iframe src="index.html" title="G3File Demo"></iframe>
|
||||
</div>
|
||||
|
||||
<div class="info-panel">
|
||||
<h3>功能特性</h3>
|
||||
<ul>
|
||||
<li>文件列表展示与管理</li>
|
||||
<li>文件上传(支持阿里云 OSS)</li>
|
||||
<li>文件预览与下载</li>
|
||||
<li>文件删除</li>
|
||||
<li>双击事件支持</li>
|
||||
<li>自定义操作菜单</li>
|
||||
<li>上传/删除前确认回调</li>
|
||||
<li>多选与批量操作</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+125
-202
@@ -1,241 +1,164 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<title>文件预览测试</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>G3File 基础示例</title>
|
||||
|
||||
<script type="text/javascript" src="./js/jquery-easyui-1.4/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./js/jquery-easyui-1.4/jquery.easyui.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="./g3-file/language.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/icon.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/common.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/index.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/libs/FileSaver.min.js"></script>
|
||||
<script type="text/javascript" src="./g3-file/libs/jszip.min.js"></script>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="./g3-file/index.css" />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #f5f7fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
padding: 10px 20px;
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f2;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.button-group button {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #5D87FF;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
|
||||
.header h1 {
|
||||
font-size: 20px;
|
||||
color: #1f2329;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header p {
|
||||
font-size: 14px;
|
||||
color: #646a73;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.button-group button:hover {
|
||||
background: #4a6fcf;
|
||||
}
|
||||
|
||||
#fileContainer {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.file-container {
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
height: 500px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="app">
|
||||
<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: 1200px;">
|
||||
<div id="fileContainer"></div>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>G3File 文件管理组件</h1>
|
||||
<p>基础示例 - 支持文件上传、预览、下载、删除等功能</p>
|
||||
</div>
|
||||
<div id="fileContainer" class="file-container"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
// 存储权限信息
|
||||
let userPermissions = {
|
||||
approve: true,
|
||||
edit: true,
|
||||
rename: true,
|
||||
copy: true,
|
||||
move: true,
|
||||
share: true,
|
||||
history: true
|
||||
};
|
||||
|
||||
// 模拟 API 请求获取权限
|
||||
function fetchPermissions() {
|
||||
return new Promise((resolve) => {
|
||||
// 模拟 API 请求延迟
|
||||
setTimeout(() => {
|
||||
// 模拟从 API 获取的权限数据
|
||||
const permissions = {
|
||||
approve: true,
|
||||
edit: true,
|
||||
rename: true,
|
||||
copy: true,
|
||||
move: true,
|
||||
share: true,
|
||||
history: true
|
||||
};
|
||||
userPermissions = permissions;
|
||||
resolve(permissions);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
// 先获取权限,然后初始化组件
|
||||
fetchPermissions().then(() => {
|
||||
const file = $('#fileContainer').G3File({
|
||||
language: 'zh-CN',
|
||||
previewUrl: 'https://sxox.g3soft.cn:8012/onlinePreview?url=',
|
||||
data: [
|
||||
{ name: 'DC2A4692147D10C9C7B48A7EA29BCBA8.jpg', size: 1024000, uploadDate: '2024-01-15T10:30:00', url: 'http://118.89.70.199:9000/test/DC2A4692147D10C9C7B48A7EA29BCBA8.jpg' },
|
||||
],
|
||||
uploadConfig: {
|
||||
aliyun: {
|
||||
// 模拟获取上传凭证的函数
|
||||
getUploadToken: function (file) {
|
||||
return new Promise((resolve) => {
|
||||
// 模拟 API 请求延迟
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
uploadUrl: `http://example.com/${file.name}`,
|
||||
// 其他阿里云上传所需的参数
|
||||
accessKeyId: 'test-access-key',
|
||||
accessKeySecret: 'test-secret-key',
|
||||
bucket: 'test-bucket',
|
||||
region: 'oss-cn-hangzhou'
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
$(function() {
|
||||
$('#fileContainer').G3File({
|
||||
language: 'zh-CN',
|
||||
previewUrl: 'https://sxox.g3soft.cn:8012/onlinePreview?url=',
|
||||
data: [
|
||||
{
|
||||
name: '项目需求文档.pdf',
|
||||
size: 2048000,
|
||||
uploadDate: '2024-01-15T10:30:00',
|
||||
url: 'http://118.89.70.199:9000/test/DC2A4692147D10C9C7B48A7EA29BCBA8.jpg'
|
||||
},
|
||||
{
|
||||
name: '设计稿.png',
|
||||
size: 1536000,
|
||||
uploadDate: '2024-01-16T14:20:00',
|
||||
url: ''
|
||||
},
|
||||
{
|
||||
name: '数据报表.xlsx',
|
||||
size: 1024000,
|
||||
uploadDate: '2024-01-17T09:15:00',
|
||||
url: ''
|
||||
},
|
||||
{
|
||||
name: '会议记录.docx',
|
||||
size: 512000,
|
||||
uploadDate: '2024-01-18T16:45:00',
|
||||
url: 'http://118.89.70.199:9000/test/report.docx'
|
||||
}
|
||||
],
|
||||
uploadConfig: {
|
||||
aliyun: {
|
||||
getAliyunKey: function() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
accessid: 'test-access-key',
|
||||
callback: '',
|
||||
dir: 'test/',
|
||||
expire: Math.floor(Date.now() / 1000) + 3600,
|
||||
host: 'http://example.com',
|
||||
policy: 'test-policy',
|
||||
signature: 'test-signature'
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
onUploadBefore: function(pendingFiles) {
|
||||
return new Promise((resolve) => {
|
||||
if (confirm('确定上传 ' + pendingFiles.length + ' 个文件吗?')) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
onDeleteBefore: function(files) {
|
||||
return new Promise((resolve) => {
|
||||
if (confirm('确定删除 ' + files.length + ' 个文件吗?')) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
customActionMenu: function(file) {
|
||||
return [
|
||||
{
|
||||
title: '审核',
|
||||
onClick: function(f) {
|
||||
alert('审核文件: ' + f.name);
|
||||
}
|
||||
},
|
||||
// 自定义上传方法(注释掉以使用阿里云上传)
|
||||
// customUpload: function(file) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// // 模拟上传延迟
|
||||
// setTimeout(() => {
|
||||
// // 模拟上传成功
|
||||
// resolve({
|
||||
// url: `http://custom-upload.com/${file.name}`,
|
||||
// uploadDate: new Date().toISOString()
|
||||
// });
|
||||
// // 模拟上传失败
|
||||
// // reject(new Error('上传失败'));
|
||||
// }, 1000);
|
||||
// });
|
||||
// }
|
||||
},
|
||||
onUploadSuccess: function (file) {
|
||||
console.log('上传成功:', file);
|
||||
alert('上传成功:' + file.name);
|
||||
},
|
||||
onUploadError: function (file, error) {
|
||||
console.error('上传失败:', file.name, error);
|
||||
alert('上传失败:' + file.name);
|
||||
},
|
||||
onUploadComplete: function (successCount, failCount) {
|
||||
console.log('上传完成:', successCount, '成功', failCount, '失败');
|
||||
alert('上传完成:' + successCount + '成功,' + failCount + '失败');
|
||||
},
|
||||
globalPermission: {
|
||||
select: true,
|
||||
upload: true,
|
||||
download: true,
|
||||
delete: true,
|
||||
view: true
|
||||
},
|
||||
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);
|
||||
{
|
||||
title: '编辑',
|
||||
onClick: function(f) {
|
||||
alert('编辑文件: ' + f.name);
|
||||
}
|
||||
}
|
||||
},
|
||||
onSelect: function (files) {
|
||||
console.log('选择文件:', files);
|
||||
},
|
||||
getActionMenu: function (file) {
|
||||
const menuItems = [];
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
});
|
||||
|
||||
$('#reloadBtn').click(function () {
|
||||
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.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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,227 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>G3 File UI Demo</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
background: #f5f6f7;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial;
|
||||
}
|
||||
|
||||
/* 列表 */
|
||||
.g3-file-list {
|
||||
width: 600px;
|
||||
margin: 40px auto;
|
||||
}
|
||||
|
||||
/* 文件项 */
|
||||
.g3-file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #eee;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.g3-file-item:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* 缩略图 */
|
||||
.g3-file-thumb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.g3-file-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* 信息 */
|
||||
.g3-file-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.g3-file-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.g3-file-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 进度条 */
|
||||
.g3-file-progress {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
background: #eee;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.g3-file-progress-bar {
|
||||
height: 100%;
|
||||
background: #52c41a;
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
/* 错误 */
|
||||
.g3-file-error {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
/* 操作 */
|
||||
.g3-file-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-left: 10px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.g3-file-item:hover .g3-file-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.g3-btn {
|
||||
border: none;
|
||||
background: #f0f0f0;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.g3-btn:hover {
|
||||
background: #e6e6e6;
|
||||
}
|
||||
|
||||
.g3-btn.danger {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
/* 状态控制 */
|
||||
.is-success .g3-file-progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.is-error .g3-file-progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.is-error .g3-file-error {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="g3-file-list" id="fileList">
|
||||
|
||||
<!-- 上传中 -->
|
||||
<div class="g3-file-item is-uploading">
|
||||
<div class="g3-file-thumb">
|
||||
<img src="https://via.placeholder.com/40" />
|
||||
</div>
|
||||
|
||||
<div class="g3-file-info">
|
||||
<div class="g3-file-name">uploading-file.zip</div>
|
||||
<div class="g3-file-meta">
|
||||
<span>3.2 MB</span>
|
||||
<div class="g3-file-progress">
|
||||
<div class="g3-file-progress-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="g3-file-actions">
|
||||
<button class="g3-btn">查看</button>
|
||||
<button class="g3-btn">下载</button>
|
||||
<button class="g3-btn danger">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 成功 -->
|
||||
<div class="g3-file-item is-success">
|
||||
<div class="g3-file-thumb">
|
||||
<img src="https://via.placeholder.com/40" />
|
||||
</div>
|
||||
|
||||
<div class="g3-file-info">
|
||||
<div class="g3-file-name">finished.pdf</div>
|
||||
<div class="g3-file-meta">
|
||||
<span>1.1 MB</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="g3-file-actions">
|
||||
<button class="g3-btn">查看</button>
|
||||
<button class="g3-btn">下载</button>
|
||||
<button class="g3-btn danger">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 失败 -->
|
||||
<div class="g3-file-item is-error">
|
||||
<div class="g3-file-thumb">
|
||||
<img src="https://via.placeholder.com/40" />
|
||||
</div>
|
||||
|
||||
<div class="g3-file-info">
|
||||
<div class="g3-file-name">error-image.png</div>
|
||||
<div class="g3-file-meta">
|
||||
<span>5.6 MB</span>
|
||||
<span class="g3-file-error">上传失败</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="g3-file-actions">
|
||||
<button class="g3-btn">重试</button>
|
||||
<button class="g3-btn danger">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 模拟上传进度
|
||||
const progressBar = document.querySelector('.is-uploading .g3-file-progress-bar');
|
||||
let percent = 0;
|
||||
|
||||
const timer = setInterval(() => {
|
||||
percent += 5;
|
||||
progressBar.style.width = percent + '%';
|
||||
|
||||
if (percent >= 100) {
|
||||
clearInterval(timer);
|
||||
const item = progressBar.closest('.g3-file-item');
|
||||
item.classList.remove('is-uploading');
|
||||
item.classList.add('is-success');
|
||||
}
|
||||
}, 300);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in new issue
Block a user