264 lines
11 KiB
HTML
264 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="stylesheet" href="/css/font.css">
|
|
<link rel="stylesheet" href="/css/xadmin.css">
|
|
<link rel="stylesheet" href="/css/win10ui.css">
|
|
<link rel="stylesheet" href="/lib/layui/css/layui.css">
|
|
<script type="text/javascript" src="/lib/layui/layui.js" charset="utf-8"></script>
|
|
<script type="text/javascript" src="/js/xadmin.js"></script>
|
|
<script src="/assets/js/socket/Socket.IO.js"></script>
|
|
<script>window.breadcrumbs = [{name: "首页", url: ""},{name: "Termination4", url: ""},{name: "大文件传输"}];</script>
|
|
<script src="/js/address.bar.js"></script>
|
|
<style>
|
|
.task-card {
|
|
width: 100px;
|
|
height: 100px;
|
|
margin: 10px;
|
|
display: inline-flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
border-radius: 4px;
|
|
background-color: #f2f2f2;
|
|
transition: all 0.3s;
|
|
cursor: pointer;
|
|
}
|
|
.task-card.success {
|
|
background-color: #d2e4c4;
|
|
border: 1px solid #5fb92f;
|
|
}
|
|
.task-card.error {
|
|
background-color: #f8d7da;
|
|
border: 1px solid #dc3545;
|
|
}
|
|
.task-card .card-index {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
}
|
|
.task-card .card-status {
|
|
font-size: 12px;
|
|
margin-top: 5px;
|
|
}
|
|
.task-container {
|
|
margin-top: 20px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.form-row {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
.form-row .layui-form-item {
|
|
margin-right: 15px;
|
|
margin-bottom: 0;
|
|
}
|
|
.stats-panel {
|
|
margin-top: 20px;
|
|
padding: 15px;
|
|
background-color: #f8f8f8;
|
|
border-radius: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="layui-fluid">
|
|
<div class="layui-card">
|
|
<div class="layui-card-header">大文件分段传输配置</div>
|
|
<div class="layui-card-body">
|
|
<form class="layui-form" id="DonwLoadForm">
|
|
<div class="form-row">
|
|
<div class="layui-form-item">
|
|
<label class="layui-form-label">工作线程数</label>
|
|
<div class="layui-input-inline">
|
|
<input type="number" name="thread_count" lay-verify="required" value="4" min="1" max="8" class="layui-input">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="layui-form-item">
|
|
<label class="layui-form-label">单线程工作量(KB)</label>
|
|
<div class="layui-input-inline">
|
|
<input type="number" name="chunk_size" lay-verify="required" value="1024" min="1" max="10240" class="layui-input">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="layui-form-item">
|
|
<label class="layui-form-label">超时时间(秒)</label>
|
|
<div class="layui-input-inline">
|
|
<input type="number" name="timeout" lay-verify="required" value="30" min="0.5" max="100" class="layui-input">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="layui-form-item">
|
|
<label class="layui-form-label">重试次数</label>
|
|
<div class="layui-input-inline">
|
|
<input type="number" name="retry_count" lay-verify="required" value="5" min="0" max="20" class="layui-input">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="layui-form-item">
|
|
<div class="layui-input-inline">
|
|
<button class="layui-btn" lay-submit lay-filter="formSubmit">开始传输</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="stats-panel" id="statsPanel" style="display: none;">
|
|
<div class="layui-row">
|
|
<div class="layui-col-md3">
|
|
<span>总任务数: </span><span id="totalTasks">0</span>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<span>已完成: </span><span id="completedTasks">0</span>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<span>失败数: </span><span id="failedTasks">0</span>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<span>进度: </span><span id="progress">0%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="task-container" id="taskContainer"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
socket = io("/Termination4SocketIOSpace");
|
|
var fileuuid = crypto.randomUUID().replace(/-/g, '');
|
|
layui.use(['form', 'layer'], function(){
|
|
var form = layui.form;
|
|
var layer = layui.layer;
|
|
|
|
form.on('submit(formSubmit)', function(data){
|
|
$("#DonwLoadForm").remove();
|
|
var threadCount = parseInt(data.field.thread_count);
|
|
var chunkSize = parseInt(data.field.chunk_size);
|
|
var timeout = parseInt(data.field.timeout);
|
|
var retryCount = parseInt(data.field.retry_count);
|
|
console.log(Path);
|
|
socket.emit('T4CMDCommand', {
|
|
PCMachineGUID: PCMachineGUID,
|
|
'work': 'updatefile',
|
|
'Command': {
|
|
"FileUUID": fileuuid,
|
|
"ThreadCount": threadCount,
|
|
"ChunkSize": chunkSize,
|
|
"Timeout": timeout,
|
|
"RetryCount": retryCount,
|
|
"Path": Path
|
|
}
|
|
});
|
|
// 这里应该是实际的文件大小获取逻辑
|
|
// 模拟一个1GB的文件
|
|
Toast.success("文件传输", "文件传输信息已发送,注意不要重复提交");
|
|
// 模拟任务更新
|
|
// simulateTaskUpdates(totalChunks);
|
|
return false;
|
|
});
|
|
|
|
function simulateTaskUpdates(totalChunks) {
|
|
var completed = 0;
|
|
var failed = 0;
|
|
var interval = setInterval(function() {
|
|
if(completed + failed >= totalChunks) {
|
|
clearInterval(interval);
|
|
layer.msg('所有任务已完成!', {icon: 1});
|
|
return;
|
|
}
|
|
var randomIndex = Math.floor(Math.random() * totalChunks);
|
|
var card = $(`.task-card[data-index="${randomIndex}"]`);
|
|
if(card.attr('data-status') !== 'pending') return;
|
|
var isSuccess = Math.random() > 0.1;
|
|
if(isSuccess) {
|
|
card.addClass('success');
|
|
card.attr('data-status', 'success');
|
|
card.find('.card-status').text('已完成');
|
|
completed++;
|
|
} else {
|
|
card.addClass('error');
|
|
card.attr('data-status', 'error');
|
|
card.find('.card-status').text('失败');
|
|
failed++;
|
|
}
|
|
|
|
// 更新统计信息
|
|
$('#completedTasks').text(completed);
|
|
$('#failedTasks').text(failed);
|
|
$('#progress').text(Math.round((completed + failed) / totalChunks * 100) + '%');
|
|
|
|
// 实际应用中应该是通过WebSocket接收更新
|
|
if(socket.taskUpdateCallback) {
|
|
socket.taskUpdateCallback({
|
|
index: randomIndex,
|
|
status: isSuccess ? 'success' : 'error',
|
|
message: isSuccess ? '下载完成' : '下载失败'
|
|
});
|
|
}
|
|
|
|
}, 500);
|
|
}
|
|
|
|
window.completed=0;
|
|
window.failed=0;
|
|
socket.on(PCMachineGUID+"CMDRUpdateFileReturnBack"+fileuuid, function(data) {
|
|
$('#statsPanel').show();
|
|
$('#totalTasks').text(data.ChunkCount);
|
|
$('#completedTasks').text(0);
|
|
$('#failedTasks').text(0);
|
|
$('#progress').text('0%');
|
|
var taskContainer = $('#taskContainer').empty();
|
|
for(var i = 0; i < data.ChunkCount; i++) {
|
|
taskContainer.append(`
|
|
<div class="task-card" data-index="${i}" data-status="pending">
|
|
<div class="card-index">${i+1}</div>
|
|
<div class="card-status">等待中</div>
|
|
</div>
|
|
`);
|
|
}
|
|
});
|
|
|
|
socket.on(PCMachineGUID+"CMDRUpdateFileTaskReturnBack"+fileuuid, function(data) {
|
|
console.log(data);
|
|
var card = $(`.task-card[data-index="${data.Partid}"]`);
|
|
$('#completedTasks').text(window.completed);
|
|
$('#failedTasks').text(window.failed);
|
|
$('#progress').text(Math.round((window.completed+1) / data.ChunkCount * 100) + '%');
|
|
if(card.length) {
|
|
if(data.status) {
|
|
card.addClass('success');
|
|
card.attr('data-status', 'success');
|
|
card.find('.card-status').text(data.status || '完成');
|
|
window.completed++
|
|
} else {
|
|
card.addClass('error');
|
|
card.attr('data-status', 'error');
|
|
card.find('.card-status').text(data.status || '失败');
|
|
window.failed++
|
|
}
|
|
}
|
|
if(data.Last){
|
|
layer.msg('所有任务已完成!', {icon: 1});
|
|
Toast.success("文件传输", "所有任务已完成");
|
|
}
|
|
});
|
|
function DownloadDirectly(url, fileName) {
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = fileName || url.split('/').pop();
|
|
link.click();
|
|
}
|
|
socket.on(PCMachineGUID+"CMDRDownloadFile"+fileuuid, (message) => {
|
|
console.log("CMDRDownloadFile", message);
|
|
DownloadDirectly(message.url, message.filename.substring(message.filename.lastIndexOf("/") + 1));
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |