556 lines
19 KiB
JavaScript
556 lines
19 KiB
JavaScript
let form, layer, demo1, dataObj = {};
|
|
|
|
let fileArr = []; // 保存的文件路径
|
|
let delFileArr = []; // 删除的文件路径
|
|
let publishStatus = '0'; // 发布状态默认0-待发布
|
|
// 全局变量记录上传状态
|
|
let isUploading = false;
|
|
let allowWindowClose = false;
|
|
// 配置常量
|
|
const MAX_FILE_COUNT2 = 10;
|
|
let MAX_FILE_COUNT = 10;
|
|
const CHUNK_SIZE = 5 * 1024 * 1024; // 分片大小 5MB
|
|
let fileSingleSizeLimit = 5 * 1024 * 1024 * 1024;
|
|
let currentFileCount = 0;
|
|
let uploader = null;
|
|
let isAllUpload = true; // 文件是否已全部上传完成
|
|
function setParams(params) {
|
|
getFileParameter();
|
|
dataObj = JSON.parse(params);
|
|
layui.use(['form', 'layer', 'upload', 'element'], function () {
|
|
layer = layui.layer;
|
|
form = layui.form;
|
|
upload = layui.upload;
|
|
element = layui.element;
|
|
setStudyObject();
|
|
if (dataObj.id) {
|
|
form.val('formInfo', dataObj);
|
|
let studyObject = dataObj.studyObject.split(',');
|
|
demo1.setValue(studyObject)
|
|
getStudyTask(dataObj.id);
|
|
}
|
|
form.on('submit(formData)', function (data) {
|
|
submitApply(data);
|
|
});
|
|
form.render();
|
|
});
|
|
// 显示Toast提示
|
|
function showToast(message, type = 'error') {
|
|
const $toast = $('#toast');
|
|
$toast.text(message).css('background-color', `var(--${type}-color)`);
|
|
$toast.fadeIn(300);
|
|
setTimeout(() => {
|
|
$toast.fadeOut(300);
|
|
}, 3000);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成更可靠的文件UID
|
|
function generateFileUID(file) {
|
|
// 使用更稳定的属性组合生成UID
|
|
return [
|
|
file.name.replace(/[^a-zA-Z0-9]/g, '_'),
|
|
file.size,
|
|
file.lastModifiedDate ? file.lastModifiedDate.getTime() : Date.now(),
|
|
WebUploader.Base.guid()
|
|
].join('_').substring(0, 100); // 限制长度防止过长
|
|
}
|
|
|
|
// 初始化WebUploader
|
|
function initUploader() {
|
|
uploader = WebUploader.create({
|
|
headers: {
|
|
'Authorization': token,
|
|
'encryption': 'encryption',
|
|
},
|
|
auto: false,
|
|
swf: '../../js/public/webuploader/Uploader.swf',
|
|
server: dataUrl + 'proteam/pot/upload/uploadFile',
|
|
pick: '#picker',
|
|
chunked: true,
|
|
chunkSize: CHUNK_SIZE,
|
|
chunkTimeout: 120000, // 增加分片上传超时时间
|
|
threads: 3,
|
|
fileNumLimit: MAX_FILE_COUNT2,
|
|
fileSizeLimit: 5 * 1024 * 1024 * 1024,
|
|
fileSingleSizeLimit: fileSingleSizeLimit,
|
|
duplicate: true,
|
|
chunkRetry: 3, // 增加重试次数
|
|
disableGlobalDnd: true,
|
|
prepareNextFile: false,
|
|
finishTriggerFlag: 'successOnly',
|
|
accept: {
|
|
title: '所有文件',
|
|
extensions: 'mp4|ppt|pptx|pdf',
|
|
mimeTypes: 'video/mp4,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/pdf'
|
|
},
|
|
formData: {
|
|
uid: 'will-be-replaced'
|
|
},
|
|
chunkAccept: function (res) {
|
|
return res.status === 'chunk_uploaded' ||
|
|
res.status === 'complete' ||
|
|
res.status === 'chunk_existed' ||
|
|
res.status === 'merging_in_progress'; // 处理合并中的状态
|
|
}
|
|
});
|
|
|
|
// 文件添加成功
|
|
uploader.on('fileQueued', function (file) {
|
|
if (currentFileCount >= MAX_FILE_COUNT) {
|
|
uploader.removeFile(file, true);
|
|
showToast(`最多只能上传${MAX_FILE_COUNT}个文件`, 'warning');
|
|
return;
|
|
}
|
|
|
|
// 生成更可靠的UID
|
|
file.uid = generateFileUID(file);
|
|
currentFileCount++;
|
|
updateFileCounter();
|
|
$('#startUpload').prop('disabled', false);
|
|
$('#noFiles').hide();
|
|
|
|
// 添加文件到列表
|
|
const $fileList = $('#fileList');
|
|
const $tr = $(`
|
|
<tr id="file-${file.id}" data-uid="${file.uid}">
|
|
<td class="file-name">${file.name}</td>
|
|
<td class="file-size">${formatFileSize(file.size)}</td>
|
|
<td>
|
|
<div class="progress-container">
|
|
<div class="progress-bar">0%</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="file-status status-waiting">
|
|
<span class="status-icon"></span>
|
|
<span class="status-text">等待上传</span>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<a href="javascript:;" class="file-action" data-id="${file.id}">删除</a>
|
|
</td>
|
|
</tr>
|
|
`);
|
|
|
|
$fileList.append($tr);
|
|
|
|
// 绑定删除事件
|
|
$tr.find('.file-action').click(function () {
|
|
const fileId = $(this).data('id');
|
|
const file = uploader.getFile(fileId);
|
|
|
|
/* if (file && file.getStatus() === 'progress') {
|
|
if (!confirm('文件正在上传中,确定要取消上传吗?')) {
|
|
return;
|
|
}
|
|
} */
|
|
uploader.removeFile(fileId, true);
|
|
$(`#file-${fileId}`).remove();
|
|
currentFileCount--;
|
|
updateFileCounter();
|
|
|
|
if (currentFileCount === 0) {
|
|
$('#noFiles').show();
|
|
$('#startUpload').prop('disabled', true);
|
|
}
|
|
|
|
delFileData(fileId);
|
|
});
|
|
});
|
|
|
|
// 上传前设置UID
|
|
uploader.on('uploadBeforeSend', function (block, data) {
|
|
data.uid = block.file.uid;
|
|
});
|
|
|
|
// 文件上传进度
|
|
uploader.on('uploadProgress', function (file, percentage) {
|
|
const percent = Math.round(percentage * 100);
|
|
const $tr = $(`#file-${file.id}`);
|
|
|
|
$tr.find('.progress-bar')
|
|
.css('width', `${percent}%`)
|
|
.text(`${percent}%`);
|
|
|
|
$tr.find('.file-status')
|
|
.removeClass('status-waiting status-error status-success')
|
|
.addClass('status-uploading')
|
|
.find('.status-text').text('上传中');
|
|
});
|
|
|
|
// 分片上传成功
|
|
uploader.on('uploadAccept', function (file, response) {
|
|
// 处理分片已存在的情况
|
|
if (response.status === 'chunk_existed') {
|
|
console.log(`分片已存在: ${file.name} chunk ${response.chunk}`);
|
|
return false; // 告诉WebUploader这个分片已经处理过了
|
|
}
|
|
return true;
|
|
});
|
|
|
|
// 文件开始上传时隐藏删除按钮
|
|
uploader.on('uploadStart', function (file) {
|
|
$('#file-' + file.id + ' .file-action').hide();
|
|
$('#startUpload').prop('disabled', true);
|
|
isUploading = true;
|
|
allowWindowClose = false;
|
|
isAllUpload = false;
|
|
});
|
|
|
|
// 文件上传成功
|
|
uploader.on('uploadSuccess', function (file, response) {
|
|
const $tr = $(`#file-${file.id}`);
|
|
|
|
if (response.status === 'merging_in_progress') {
|
|
$tr.find('.file-status .status-text').text('合并中...');
|
|
return;
|
|
}
|
|
$('#file-' + file.id + ' .file-action').show();
|
|
if (response.status === 'success') {
|
|
$tr.find('.file-status')
|
|
.removeClass('status-waiting status-uploading status-error')
|
|
.addClass('status-success')
|
|
.find('.status-text').text('上传成功');
|
|
|
|
$tr.find('.file-action').show();
|
|
|
|
fileArr.push({
|
|
id: file.id,
|
|
fileUrl: response.path,
|
|
fileSize: response.size,
|
|
filePreviousName: file.name,
|
|
fileName: response.filename,
|
|
fileId: response.filename.split('.')[0]
|
|
});
|
|
}
|
|
});
|
|
|
|
// 文件上传失败
|
|
uploader.on('uploadError', function (file, reason) {
|
|
const $tr = $(`#file-${file.id}`);
|
|
let errorMessage = '上传失败';
|
|
|
|
// 解析错误原因
|
|
if (reason === '404') {
|
|
errorMessage = '上传接口不存在';
|
|
} else if (reason === '500') {
|
|
errorMessage = '服务器内部错误';
|
|
} else if (reason.message) {
|
|
errorMessage = reason.message;
|
|
} else if (reason.responseText) {
|
|
try {
|
|
const res = JSON.parse(reason.responseText);
|
|
errorMessage = res.message || '上传失败';
|
|
} catch (e) {
|
|
errorMessage = reason.responseText;
|
|
}
|
|
}
|
|
|
|
$tr.find('.file-status')
|
|
.removeClass('status-waiting status-uploading')
|
|
.addClass('status-error')
|
|
.find('.status-text').text('上传失败');
|
|
|
|
$tr.find('.progress-bar').css('background-color', 'var(--danger-color)');
|
|
$tr.find('.file-action').show();
|
|
|
|
// 对于特定错误自动重试
|
|
if (reason === '404' || reason === '500') {
|
|
setTimeout(() => {
|
|
uploader.retry(file);
|
|
}, 2000);
|
|
}
|
|
|
|
showToast(`文件 "${file.name}" 上传失败: ${errorMessage}`, 'error');
|
|
});
|
|
|
|
// 重试逻辑
|
|
uploader.on('error', function (type, file) {
|
|
if (type === 'serverError' || type === 'uploadError') {
|
|
// 服务器错误时延迟重试
|
|
setTimeout(() => {
|
|
uploader.retry(file);
|
|
}, 3000);
|
|
} else if (type === 'chunkError') {
|
|
// 分片错误时立即重试
|
|
uploader.retry(file);
|
|
}
|
|
});
|
|
|
|
// 上传完成
|
|
uploader.on('uploadComplete', function (file) {
|
|
// 可以在这里做一些清理工作
|
|
});
|
|
|
|
// 所有文件上传完成
|
|
uploader.on('uploadFinished', function () {
|
|
$('#startUpload').prop('disabled', true);
|
|
isUploading = false;
|
|
allowWindowClose = true;
|
|
showToast('所有文件上传完成', 'success');
|
|
isAllUpload = true;
|
|
// 检查是否有文件上传失败
|
|
const failedFiles = uploader.getFiles('error');
|
|
if (failedFiles.length > 0) {
|
|
showToast(`${failedFiles.length}个文件上传失败,请重试`, 'warning');
|
|
}
|
|
});
|
|
|
|
// 错误处理
|
|
uploader.on('error', function (type) {
|
|
let errorMsg = '';
|
|
switch (type) {
|
|
case 'F_EXCEED_SIZE':
|
|
errorMsg = '文件大小超过限制';
|
|
break;
|
|
case 'Q_EXCEED_NUM_LIMIT':
|
|
errorMsg = `最多只能上传${MAX_FILE_COUNT}个文件`;
|
|
break;
|
|
case 'Q_TYPE_DENIED':
|
|
errorMsg = '文件类型不允许';
|
|
break;
|
|
case 'F_DUPLICATE':
|
|
errorMsg = '文件已经存在队列中';
|
|
break;
|
|
case 'F_EMPTY':
|
|
errorMsg = '空文件不能上传';
|
|
break;
|
|
case 'serverError':
|
|
errorMsg = '服务器错误,请稍后重试';
|
|
break;
|
|
case 'uploadError':
|
|
errorMsg = '上传过程中发生错误';
|
|
break;
|
|
case 'chunkError':
|
|
errorMsg = '分片上传失败';
|
|
break;
|
|
default:
|
|
errorMsg = '上传出错: ' + type;
|
|
}
|
|
|
|
showToast(errorMsg, 'error');
|
|
});
|
|
}
|
|
|
|
// 初始化上传器
|
|
initUploader();
|
|
|
|
// 开始上传按钮
|
|
$('#startUpload').click(function () {
|
|
if (uploader.getFiles().length === 0) {
|
|
showToast('请先选择文件', 'warning');
|
|
return;
|
|
}
|
|
uploader.upload();
|
|
showToast('开始上传文件...', 'success');
|
|
});
|
|
|
|
// 删除保存的文件数据
|
|
function delFileData(idToDelete) {
|
|
if (fileArr.length === 0) return;
|
|
const index = fileArr.findIndex(item => item.id === idToDelete);
|
|
if (index !== -1) {
|
|
const obj = fileArr[index];
|
|
delFileArr.push({
|
|
fileUrl: obj.fileUrl
|
|
});
|
|
fileArr.splice(index, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 学习对象
|
|
function setStudyObject() {
|
|
demo1 = xmSelect.render({
|
|
el: '#demo1',
|
|
language: 'zn',
|
|
layVerify: 'required',
|
|
layVerType: 'msg',
|
|
data: [
|
|
{ name: '值班员', value: '2' },
|
|
{ name: '地市人员', value: '3' },
|
|
]
|
|
})
|
|
layui.form.render();
|
|
}
|
|
|
|
// 格式化文件大小
|
|
function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 B';
|
|
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${units[i]}`;
|
|
}
|
|
|
|
// 更新文件计数器
|
|
function updateFileCounter() {
|
|
const $counter = $('#fileCounter');
|
|
$counter.text(`已选择 ${currentFileCount}/${MAX_FILE_COUNT} 个文件`);
|
|
if (currentFileCount >= MAX_FILE_COUNT) {
|
|
$counter.addClass('warning');
|
|
} else {
|
|
$counter.removeClass('warning');
|
|
}
|
|
}
|
|
|
|
// 删除文件
|
|
function delFile(that, obj) {
|
|
$(that).parents('tr').remove();
|
|
delFileArr.push({
|
|
fileUrl:obj.fileUrl,
|
|
fileUrlNew:obj.fileUrlNew,
|
|
id:obj.id
|
|
})
|
|
MAX_FILE_COUNT = MAX_FILE_COUNT + 1;
|
|
updateFileCounter();
|
|
let length = $('#fileList2 tr').length;
|
|
if (length === 0) {
|
|
$('#fileList2').append('<tr><td colspan="3" class="no-files">暂无数据</td></tr>');
|
|
}
|
|
}
|
|
|
|
// 提交
|
|
function submitApply(data) {
|
|
if (fileArr.length === 0 && $('#fileList2 .files').length === 0) {
|
|
return layer.msg('未上传学习课件', { icon: 5 });
|
|
}
|
|
if(!isAllUpload){
|
|
return layer.msg('课件未全部上传完成,请稍后重试', { icon: 5 });
|
|
}
|
|
let url = dataUrl + "proteam/pot/studyTask/addOrUpdateStudyTask";
|
|
let params = Object.assign({}, data.field);
|
|
params.studyObject = demo1.getValue('valueStr');
|
|
params.delFiles = JSON.stringify(delFileArr);
|
|
params.files = JSON.stringify(fileArr);
|
|
params.publishStatus = publishStatus;
|
|
params.id = dataObj.id;
|
|
console.log(params);
|
|
let loadingMsg = layer.msg('正在提交保存,请稍等...', { icon: 16, shade: 0.01, time: '0' });
|
|
$('.save').addClass("layui-btn-disabled").attr("disabled", true);
|
|
$('.cancel').addClass("layui-btn-disabled").attr("disabled", true);
|
|
ajaxRequest2(url, "POST", params, true, function (result) {
|
|
layer.close(loadingMsg); // 关闭提示层
|
|
console.log(result);
|
|
if (result.code === 200) {
|
|
top.layer.msg(result.msg, { icon: 1 })
|
|
closePage(1);
|
|
} else {
|
|
$('.save').removeClass("layui-btn-disabled").attr("disabled", false);
|
|
$('.cancel').removeClass("layui-btn-disabled").attr("disabled", false);
|
|
layer.msg(result.msg, { icon: 2 })
|
|
}
|
|
}, function (xhr) {
|
|
layer.close(loadingMsg); // 关闭提示层
|
|
$('.save').removeClass("layui-btn-disabled").attr("disabled", false);
|
|
$('.cancel').removeClass("layui-btn-disabled").attr("disabled", false);
|
|
error(xhr)
|
|
}, null, token);
|
|
}
|
|
|
|
|
|
// 保存
|
|
function saveData2(type) {
|
|
publishStatus = type + '';
|
|
$('#formSubmit').trigger('click')
|
|
}
|
|
|
|
// 获取学习任务详情
|
|
function getStudyTask() {
|
|
let loadingMsg = layer.msg('数据加载中,请稍等...', { icon: 16, shade: 0.01, time: '0' });
|
|
let url = dataUrl + "proteam/pot/studyTask/getStudyTaskById";
|
|
let params = { id: dataObj.id };
|
|
ajaxRequest2(url, "POST", params, true, function (result) {
|
|
console.log(result);
|
|
layer.close(loadingMsg); // 关闭提示层
|
|
if (result.code === 200) {
|
|
initFileData(result.data.studyFileVoList);
|
|
} else {
|
|
layer.msg(result.msg, { icon: 2 })
|
|
}
|
|
}, function (xhr) {
|
|
layer.close(loadingMsg); // 关闭提示层
|
|
error(xhr)
|
|
}, null, token);
|
|
// 初始化已上传的文件
|
|
function initFileData(data) {
|
|
let html = '';
|
|
$.each(data, function (index, item) {
|
|
html += "<tr class='files'>" +
|
|
"<td>" + item.filePreviousName + "</td>" +
|
|
"<td>" + formatFileSize(item.fileSize || 0) + "</td>" +
|
|
"<td>" +
|
|
"<a href='javascript:;' style='margin: 0 5px;' onclick='viewFile(this," + JSON.stringify(item) + ")'>预览</a>" +
|
|
"<a href='javascript:;' style='margin: 0 5px;color:#e74c3c' onclick='delFile(this," + JSON.stringify(item) + ")'>删除</a>"
|
|
"</td>" +
|
|
"</tr>"
|
|
})
|
|
$('#fileList2').append(html);
|
|
MAX_FILE_COUNT = 10 - data.length;
|
|
$('#fileCounter').html(`已选择 0/${MAX_FILE_COUNT}个文件`);
|
|
}
|
|
}
|
|
|
|
// 获取学习任务相关配置参数
|
|
function getFileParameter() {
|
|
let url = dataUrl + "proteam/pot/studyTask/getFileParameter";
|
|
let params = {};
|
|
ajaxRequest2(url, "POST", params, false, function (result) {
|
|
console.log(result);
|
|
if (result.code === 200) {
|
|
if(result.data.fileSize){
|
|
fileSingleSizeLimit = parseInt(result.data.fileSize) * 1024 * 1024;
|
|
}
|
|
if(result.data.fileNum){
|
|
MAX_FILE_COUNT = parseInt(result.data.fileNum);
|
|
}
|
|
}
|
|
}, function (xhr) {
|
|
layer.close(loadingMsg); // 关闭提示层
|
|
error(xhr)
|
|
}, null, token);
|
|
}
|
|
|
|
// 文件预览函数
|
|
function viewFile(that,item) {
|
|
var fileExt = (item.fileUrlNew || item.fileUrl).split('.').pop().toLowerCase();
|
|
if (fileExt === 'pdf') { // pdf 预览
|
|
sessionStorage.setItem("fileUrlNew", item.fileUrlNew || item.fileUrl);
|
|
let href = '../../pdfjs/web/viewer2.html'
|
|
layui.layer.open({
|
|
title: 'PDF预览',
|
|
type: 2,
|
|
area: ['95%', '95%'], // 弹出框的宽高
|
|
fixed: false, // 是否固定
|
|
maxmin: true, // 是否允许最大化
|
|
shade: 0, // 隐藏弹框的遮罩层
|
|
content: href, // pdf的地址
|
|
move:false
|
|
})
|
|
}
|
|
else if (fileExt === 'mp4') {
|
|
let videoUrl = photoUrl + item.fileUrl + '?token=' + token;
|
|
layer.open({
|
|
type: 1,
|
|
title: '视频预览 - ' + item.filePreviousName,
|
|
content: '<video controls autoplay style="width: 98%;height: 96%;object-fit: contain;margin: 1% 1% 0 1%;"><source src="' + videoUrl + '" type="video/mp4"></video>',
|
|
area: ['95%', '95%'], // 弹出框的宽高
|
|
move:false
|
|
});
|
|
}
|
|
}
|
|
|
|
// 关闭页面
|
|
function closePage(type) {
|
|
if (isUploading && !allowWindowClose) {
|
|
return layer.msg('文件正在上传中,请勿关闭页面', { icon: 7 });
|
|
}
|
|
let index = parent.layer.getFrameIndex(window.name); //先得到当前 iframe层的索引
|
|
parent.layer.close(index); //再执行关闭
|
|
if (type === 1) {
|
|
parent.query(1);
|
|
}
|
|
} |