需求不同,思路相同,可借鉴,无法直接使用
实现思路
- 调用接口,回显,状态为正在上传的改为上传中断 第132行
- 上传文件,调用接口判断文件是否存在 ,当前上传到第几片。 第207行
- 如果上传过,并且中断,从指定切片开始上传 第212行
- 上传面板列表添加文件进度 第334行
- 上传完第一片后,前端存储后台上传接口返回的唯一id,下片传入,后台更新库更方便 第343行
- 上传文件成功/失败后,修改按钮、进度条等文字样式 第349行
上传面板样式
文件分为上传完成、上传中断、正在上传、任务暂停、上传失败等几个状态
上传面板template模板
因为jsp中语法<%%>占用,需要将template.js中<% %>改为 {{ }}
<script type="text/html" id="upload-tel">
{{for(var i=0;i<data.length;i++){ }}
{{var item = data[i]}}
{{if(item.isShow){ }}
<li class="clear" dbid="{{=item.dbId}}" md5="{{=item.md5Value}}">
{{ } }}
{{if(!item.isShow){ }}
<li class="clear" style="display:none" dbid="{{=item.dbId}}" md5="{{=item.md5Value}}">
{{ } }}
<div class="list-left">
<p class="clear">
<span class="file-name" title="{{=item.name}}">{{=item.name}}</span>
<span class="upload-status" status="{{=item.status}}">{{=item.statusText}}</span>
</p>
<div class="progress {{=item.barClass}}">
<div class="bar" style="width: {{=item.progress}}"></div>
</div>
</div>
<div class="list-right">
<span class="progressText">{{=item.progress}}</span>
<span class="size" title="{{=item.overSize}}/{{=item.fakeSize}}{{=item.company}}">
<span>{{=item.overSize}}</span>
/
<span>{{=item.fakeSize}}</span>
<span>{{=item.company}}</span>
</span>
{{if (item.status == "1") { }}
<input type="button" class="btn btn-link pause" value="暂停">
{{ }else if (item.status == "-1") { }}
<input type="button" class="btn btn-link start" value="开始">
{{ }else if (item.status == "0" || item.status == "3") { }}
<input type="button" class="btn btn-link reup" value="重传">
{{ } }}
<input type="button" class="btn btn-link delete" value="删除">
</div>
</li>
{{ } }}
</script>
全代码展示
//定义layer
var layer
layui.use('layer',function(){
layer = layui.layer
})
//打开上传面板
function showUploadBox(){
layer.open({
type: 1,
area: ['600px', '450px'],
title: "上传文件列表",
fixed: false, //不固定
maxmin: true,
shade:0,
content: $('#upload-box'),
success:function(layero){
layero.find('.layui-layer-max').hide(); //去掉最大化按钮
},
min:function(layero){
layero.find('.layui-layer-max').css('display','inline-block'); //去掉最大化按钮
},
restore:function(layero){
layero.find('.layui-layer-max').hide(); //去掉最大化按钮
}
});
}
//重传按钮绑定点击事件
function reuploadClick($li){
$li.on("click",'.reup',function(){
layer.msg('选择文件名为 <span style="color:red">'+$li.find('.file-name').text()+'</span>的文件,即可续传。',function(){
$("#upload-btn input").click()
})
})
}
//删除按钮绑定点击事件
function deleteClick($li, file, uploader){
$li.find('.delete').click(function(){
clearUploader(file, uploader)
})
}
//开始、暂停绑定点击事件
function playClick($li, uploader, file){
$li.on('click', '.pause',function(){
uploader.stop(file)
$li.find('.pause').addClass('start').removeClass('pause').val('开始')
.end().find('.upload-status').text('任务暂停').attr('status', "0")
.end().find('.progress').attr('class','').addClass('progress')
})
$li.on('click', '.start',function(){
uploader.upload(file)
$li.find('.start').addClass('pause').removeClass('start').val('暂停')
.end().find('.upload-status').text('正在上传').attr('status', "1")
.end().find('.progress').attr('class','').addClass('progress uploading')
})
}
//渲染下载列表
function drawList(data, fake){
var tpl = $('#upload-tel').html();
if (data && data.length > 0){
data.forEach(function(e,i){
e.isShow = e.isShow == 0? false : true;
// 转换状态
switch(e.status){
case "0":
e.statusText = "等待上传";break;
case "1":
e.statusText = "正在上传";
e.barClass = "uploading";break;
case "-1":
e.statusText = "上传失败";
e.barClass = "upload-fail";break;
case "2":
e.statusText = "上传完成";
e.barClass = "uploader";break;
case "3":
e.statusText = "上传中断";
e.barClass = "upload-fail";break;
}
// 是否需要转换文件大小单位
if (fake){
var sizeCompany = computeSize(e.size)
e.company = sizeCompany.company
e.fakeSize = sizeCompany.fakeSize
}
// 上传完成赋值百分百,否则通过切片和切片大小计算百分比
if (e.status == "2"){
e.progress = "100%";
e.overSize = e.fakeSize;
} else {
e.progress = ((e.chunk+1)/e.chunks * 100).toFixed(1) + '%'
if(e.company == "GB"){
e.overSize = (50 * 1024 * 1024 *(e.chunk+1)/1024/1024/1024).toFixed(1)
}else if(e.company == "MB"){
e.overSize = (50 * 1024 * 1024 *(e.chunk+1)/1024/1024).toFixed(1)
}else {
e.overSize = (50 * 1024 * 1024 *(e.chunk+1)/1024).toFixed(1)
}
}
})
// 渲染页面
$("#upload-box ul").prepend(template(tpl, {data:data}))
}
}
//计算文件适应单位和大小
function computeSize(size) {
if(size > 1024 * 1024 * 1024){
fakeSize = (size/1024/1024/1024).toFixed(1)
company = "GB"
}else if(size > 1024*1024){
fakeSize = (size/1024/1024).toFixed(1)
company = "MB"
}else {
fakeSize = (size/1024).toFixed(1)
company = "KB"
}
return {fakeSize, company}
}
//检查文件
function checkFile(dbId="", name="", size="", md5Value="", successFnc){
$.ajax({
url: ctx+'/fileinfo/fileInfo/check',
type:"POST",
data: {
'size': size,
'md5Value': md5Value,
'dbId': dbId
},
success:successFnc
})
}
//获取上传列表,回显
function getUploadList(uploader){
$.ajax({
url: ctx+'/fileinfo/fileInfo/fileList',
success:function(res){
if(res && res.length > 0){
res.forEach(function(e,i){
if(e.status == "1"){
e.status = "3"
}
})
drawList(res, true)
res.forEach(function(e,i){
var $li = $('li[md5='+e.md5Value+']')
deleteClick($li, {md5Value: e.md5Value, name: e.name,size: e.size}, uploader)
reuploadClick($li)
})
}
}
})
}
//删除任务
function clearUploader(data, uploader){
// 如果数据包含MD5属性,删除单个文件,否则清除全部完成文件
if (data.md5Value || data.wholeMd5){
var $li = $('li[md5='+(data.md5Value?data.md5Value:data.wholeMd5)+']')
var dbid = $li.attr('dbid')
var loading = layer.load(1, {shade: 0.5})
$.ajax({
url: ctx+'/fileinfo/fileInfo/clear',
type: "POST",
data:{
md5: data.md5Value?data.md5Value:data.wholeMd5,
size: data.size,
dbId: dbid?dbid:""
},
success:function(res){
// 如果此文件正在上传,移出上传列表
if(data.id)uploader.removeFile(data)
$li.hide();
layer.close(loading)
layer.msg("删除 "+data.name+" 成功")
},
error:function(){
layer.close(loading)
layer.msg('删除失败',{icon: 2})
}
})
}else{
$.ajax({
url: ctx+'/fileinfo/fileInfo/clear',
success:function(res){
$("#upload-box .uploader").parents('li').hide();
layer.msg("清除已完成任务成功")
}
})
}
}
$(function () {
// 刷新提示
window.addEventListener('beforeunload', function (event) {
// 谷歌浏览器不支持设置文字内容,ie下会提示此段文字
event.returnValue = '刷新或关闭页面会导致上传中断,之后继续上传需要重新选择文件。'
})
// 清除全部完成任务按钮事件
$('#upload-box>input').click(clearUploader)
// HOOK 这个必须要再uploader实例化前面
WebUploader.Uploader.register({
'before-send-file': 'beforeSendFile',//整个文件上传前
'before-send': 'beforeSend' //每个分片上传前
}, {
beforeSendFile: function (file) {
var deferred = WebUploader.Deferred();
var $li = $('li[md5='+file.wholeMd5+']')
// 检查接口,判断文件是否存在,上传到哪片
checkFile($li.attr('dbid'), file.name, file.size, file.wholeMd5, function(res){
if (res.data && res.data.status == 2) {
layer.msg('文件已存在',{icon: 2})
deferred.reject();
} else {
file.startChunk = res.data.chunk
deferred.resolve();
}
})
return deferred.promise();
},
beforeSend: function (block) {
var doneChunkPartIndex = block.file.startChunk;//获取已经上传过的下标
var deferred = WebUploader.Deferred();
if(doneChunkPartIndex>0){
if(block.chunk>doneChunkPartIndex){
//分块不存在,重新发送该分块内容
deferred.resolve();
}else{
//分块存在,跳过
deferred.reject();
}
}else{
//分块不存在,重新发送该分块内容
deferred.resolve();
}
return deferred.promise();
}
});
var uploader = WebUploader.create({
//设置选完文件后是否自动上传
auto: false,
// 文件接收服务端。
swf: ctxStatic+'webuploader/dist/Uploader.swf', // flash上传
server: ctx+'/fileinfo/fileInfo/upload',
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#upload-btn',
chunked: true, //开启分块上传
chunkSize: 50*1024*1024, // 50MB 每片大小 单位B 如果文件小于每片大小限制,不会分片
chunkRetry: 3,//网络问题上传失败后重试次数
threads: 1, //上传并发数
//fileNumLimit :1,
fileSizeLimit: 10 * 1024 * 1024 * 1024 * 1024,// 10T 文件总大小限制 单位B
fileSingleSizeLimit: 1024 * 1024 * 1024 * 1024,// 1T 单个文件大小限制 单位B
resize: false//不压缩
//选择文件类型
//accept: {
// title: 'Video',
// extensions: 'mp4,avi',
// mimeTypes: 'video/*'
//}
});
// window.onbeforeunload = function(){
// layer.confirm("",function(){
// uploader.getFiles('progressNum')
// })
// return false
// }
getUploadList(uploader);
// 当有文件被添加进队列的时候
uploader.on('fileQueued', function (file) {
//md5计算
var loading = layer.load(1,{shade: 0.5})
uploader.md5File(file).then(function (fileMd5) { // 完成
layer.close(loading)
var end = +new Date();
var sizeCompany = computeSize(file.size)
// file添加属性
file.company = sizeCompany.company
file.fakeSize = sizeCompany.fakeSize
file.wholeMd5 = fileMd5;//获取到了md5
uploader.options.formData.md5Value = file.wholeMd5;//每个文件都附带一个md5,便于实现秒传
var $li = $('li[md5='+file.wholeMd5+']')
// 如果当前文件已存在,修改状态,按钮文字,进度条颜色
if ($li.length > 0){
file.dbId = $li.attr('dbid')
var status = $li.find('.upload-status').attr('status')
file.status = status=="3"?"1":status;
$li.find('.reup').addClass('pause').removeClass('reup').val('暂停')
$li.find('.upload-status').text('正在上传').attr('status', "1")
.end().find('.progress').attr('class','').addClass('progress uploading')
playClick($li, uploader, file);
}
uploader.upload();
});
});
//发送前填充数据
uploader.on( 'uploadBeforeSend', function( block, data ) {
// file为分块对应的file对象。
var file = block.file;
var fileMd5 = file.wholeMd5;
// 修改data可以控制发送哪些携带数据。
// 将存在file对象中的md5数据携带发送过去。
data.md5Value = fileMd5;//md5
data.dbId = file.dbId?file.dbId:""
// 删除其他数据
if(block.chunks>1){ //文件大于chunksize 分片上传 1:分片;0:不分片
data.isChunked = 1;
}else{
data.isChunked = 0;
}
});
// 文件上传过程中创建进度条实时显示。
uploader.on('uploadProgress', function (file, percentage) {
var $li = $('li[md5='+file.wholeMd5+']')
// 列表存在文件,只更新进度
if ($li && $li.length>0){
$li.find('.bar').css('width',(percentage*100).toFixed(1)+'%')
.end().find('.progressText').text((percentage*100).toFixed(1)+'%')
.end().find('.size>span').eq(0).text((file.fakeSize*percentage).toFixed(1))
} else {
// 新增列表,默认参数
var data = [{
isShow:true,
id:file.id,
md5Value:file.wholeMd5,
name:file.name,
status:"1",
overSize:0,
company:file.company,
fakeSize:file.fakeSize,
chunk:-1,
chunks:1,
dbId: ""
}]
drawList(data);
var $li = $('li[md5='+file.wholeMd5+']')
playClick($li, uploader, file);
deleteClick($li, file, uploader)
reuploadClick($li)
//showUploadBox();
}
});
// 分片上传成功
uploader.on('uploadAccept', function (object, ret) {
var $li = $('li[md5='+object.file.wholeMd5+']')
$li.attr("dbid", ret.dbId)
object.file.dbId = ret.dbId
});
// 上传成功
uploader.on('uploadSuccess', function (file) {
$('#upload-btn input').val('')
var $li = $('li[md5='+file.wholeMd5+']')
$li.find('.upload-status').text('上传完成')
.end().find('.progressText').text('√').css('color','green')
.end().find('.progress').attr('class','').addClass('progress uploader')
.end().find('.size').next().remove()
var fileList = [];
$(document).find("iframe")[0].contentWindow.$("td[data-field='dbId']").each(function(index,data){
fileList.push($(data).text());
})
fileList.push($li.attr("dbId"));
var fileJson = JSON.stringify(fileList);
var url = ctx+ "/fileinfo/fileInfo/fileSecList";
$(document).find("iframe")[0].contentWindow.fileTable.reload({url, where: {"fileJson": fileJson}})
});
// 上传出错
uploader.on('uploadError', function (file) {
$('#upload-btn input').val('')
var $li = $('li[md5='+file.wholeMd5+']')
$li.find('.upload-status').text('上传失败')
.end().find('.progressText').text('×').css('color','red')
.end().find('.progress').attr('class','').addClass('progress upload-fail')
.end().find('.size').next().removeClass('pause').removeClass('start').addClass('reup').val('重传')
});
});