完善页面内容,支持路径匹配计数
This commit is contained in:
parent
be8303cd63
commit
3323eef81e
9 changed files with 326 additions and 130 deletions
11
README.md
11
README.md
|
@ -1 +1,12 @@
|
||||||
### 文件代理下载工具
|
### 文件代理下载工具
|
||||||
|
|
||||||
|
#### 功能列表
|
||||||
|
- [x] 代理下载文件
|
||||||
|
- [x] 浏览器下载文件
|
||||||
|
- [x] 文件名黑名单
|
||||||
|
- [x] 目标Host黑名单
|
||||||
|
- [x] 文件大小限制
|
||||||
|
- [x] 基于IP查询提交的任务状态
|
||||||
|
- [x] 基于IP和路由的请求次数限制
|
||||||
|
- [ ] 已经存在对应文件时候直接跳过代理下载 直接下载已经缓存的内容
|
||||||
|
- [ ] 捐赠
|
|
@ -55,6 +55,7 @@ namespace iFileProxy.Config
|
||||||
public List<string> BlockedHost { get; set; } = [];
|
public List<string> BlockedHost { get; set; } = [];
|
||||||
public List<string> BlockedFileName { get; set; } = [];
|
public List<string> BlockedFileName { get; set; } = [];
|
||||||
public List<string> BlockedClientIP { get; set; } = [];
|
public List<string> BlockedClientIP { get; set; } = [];
|
||||||
|
public List<string> RoutesToTrack { get; set; } = [];
|
||||||
public int DailyRequestLimitPerIP { get; set; } = -1;
|
public int DailyRequestLimitPerIP { get; set; } = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ namespace iFileProxy.Helpers
|
||||||
|
|
||||||
public bool UpdateTaskStatus(TaskInfo taskInfo)
|
public bool UpdateTaskStatus(TaskInfo taskInfo)
|
||||||
{
|
{
|
||||||
string sql = @"UPDATE t_tasks_info set `status` = @status WHERE `tid` = @tid";
|
string sql = @"UPDATE t_tasks_info set `status` = @status , update_time = Now() WHERE `tid` = @tid";
|
||||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
namespace iFileProxy.Middleware
|
namespace iFileProxy.Middleware
|
||||||
{
|
{
|
||||||
|
using iFileProxy.Config;
|
||||||
using iFileProxy.Helpers;
|
using iFileProxy.Helpers;
|
||||||
using iFileProxy.Models;
|
using iFileProxy.Models;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly Dictionary<string, Dictionary<string, uint>> _IPAccessCountDict;
|
private readonly Dictionary<string, Dictionary<string, uint>> _IPAccessCountDict;
|
||||||
private readonly int _dailyRequestLimitPerIP;
|
private readonly int _dailyRequestLimitPerIP;
|
||||||
|
private readonly AppConfig _appConfig = AppConfig.GetCurrConfig();
|
||||||
|
|
||||||
public IPAccessLimitMiddleware(RequestDelegate next, Dictionary<string, Dictionary<string, uint>> IPAccessCountDict, int dailyRequestLimitPerIP)
|
public IPAccessLimitMiddleware(RequestDelegate next, Dictionary<string, Dictionary<string, uint>> IPAccessCountDict, int dailyRequestLimitPerIP)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,26 @@
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
|
// 获取需要跟踪的路由列表
|
||||||
|
var routesToTrack = _appConfig.SecurityOptions.RoutesToTrack;
|
||||||
|
|
||||||
|
// 检查当前请求的路径是否在需要跟踪的路由列表中
|
||||||
|
foreach (var p in routesToTrack)
|
||||||
|
{
|
||||||
|
if (context.Request.Path.ToString().StartsWith(p, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// 如果匹配到需要跟踪的路由,继续处理请求
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有匹配到需要跟踪的路由,直接调用下一个中间件
|
||||||
|
if (!routesToTrack.Any(p => context.Request.Path.ToString().StartsWith(p, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
await _next(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string dateStr = DateTime.Now.ToString("yyyy-MM-dd");
|
string dateStr = DateTime.Now.ToString("yyyy-MM-dd");
|
||||||
string ipStr = MasterHelper.GetClientIPAddr(context);
|
string ipStr = MasterHelper.GetClientIPAddr(context);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
<_TargetId>Folder</_TargetId>
|
<_TargetId>Folder</_TargetId>
|
||||||
<SiteUrlToLaunchAfterPublish />
|
<SiteUrlToLaunchAfterPublish />
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<ProjectGuid>e343bd8a-27ed-47e2-b50d-e3000730e65e</ProjectGuid>
|
<ProjectGuid>e343bd8a-27ed-47e2-b50d-e3000730e65e</ProjectGuid>
|
||||||
<SelfContained>false</SelfContained>
|
<SelfContained>false</SelfContained>
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace iFileProxy.Services
|
||||||
public TaskAddState AddTask(HttpContext c)
|
public TaskAddState AddTask(HttpContext c)
|
||||||
{
|
{
|
||||||
string? clientIp = MasterHelper.GetClientIPAddr(c);
|
string? clientIp = MasterHelper.GetClientIPAddr(c);
|
||||||
string? t_url = c.Request.Query["url"].FirstOrDefault();
|
string? t_url = c.Request.Query["url"].FirstOrDefault() ?? c.Request.Form["url"].FirstOrDefault();
|
||||||
|
|
||||||
if (_appConfig.DownloadOptions.MaxParallelTasks != 0 && runningTasks.Count >= _appConfig.DownloadOptions.MaxParallelTasks)
|
if (_appConfig.DownloadOptions.MaxParallelTasks != 0 && runningTasks.Count >= _appConfig.DownloadOptions.MaxParallelTasks)
|
||||||
return TaskAddState.ErrMaxParallelTasksLimit;
|
return TaskAddState.ErrMaxParallelTasksLimit;
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
"BlockedClientIP": [ // 禁止使用服务的客户端IP
|
"BlockedClientIP": [ // 禁止使用服务的客户端IP
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
||||||
],
|
],
|
||||||
"DailyRequestLimitPerIP": 200 // 单个IP每日最大请求次数限制
|
"DailyRequestLimitPerIP": 200, // 单个IP每日最大请求次数限制
|
||||||
|
"RoutesToTrack": [ // 参加IP请求数统计的路径名单
|
||||||
|
"/Download",
|
||||||
|
"/AddOfflineTask"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,70 +1,19 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="cn">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>离线下载任务管理</title>
|
<title>Github文件下载加速</title>
|
||||||
|
<!-- 引入 Bootstrap 5 CSS -->
|
||||||
<link href="static/css/bootstarp/5/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
<link href="static/css/bootstarp/5/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
.more-content {
|
||||||
padding: 20px;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #343a40;
|
|
||||||
}
|
|
||||||
.table-responsive {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
background-color: transparent;
|
|
||||||
border-collapse: collapse;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.table th, .table td {
|
|
||||||
padding: 15px;
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
text-align: center;
|
|
||||||
max-width: 90px; /* 设置最大宽度 */
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.table thead th {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.table tbody tr:nth-child(even) {
|
|
||||||
background-color: #f1f3f5;
|
|
||||||
}
|
|
||||||
.table tbody tr:hover {
|
|
||||||
background-color: #e2e6ea;
|
|
||||||
}
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.table-responsive {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
.table th, .table td {
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.hidden-on-small {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
@ -72,24 +21,36 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title text-center">Github文件下载加速</h5>
|
||||||
|
|
||||||
<div class="container">
|
<!-- URL 输入框 -->
|
||||||
<h1 class="text-center">离线下载任务管理</h1>
|
<div class="mb-3">
|
||||||
<div class="table-responsive">
|
<label for="url_ipt" class="form-label">目标文件URL</label>
|
||||||
<table class="table table-striped table-bordered">
|
<input type="text" required="required" class="form-control" id="url_ipt"
|
||||||
<thead>
|
placeholder="请输入要下载的文件链接">
|
||||||
<tr>
|
</div>
|
||||||
<th>文件名</th>
|
|
||||||
<th class="hidden-on-small">大小</th>
|
<!-- 验证码 输入框 -->
|
||||||
<th>提交时间</th>
|
<!-- <div class="mb-3 input-group">
|
||||||
<th>状态</th>
|
<input type="text" class="form-control" id="vcode" placeholder="交易验证码">
|
||||||
<th class="hidden-on-small">哈希</th>
|
<button type="button" id="send_vcode_btn" class="btn btn-primary">发送验证码</button>
|
||||||
</tr>
|
</div> -->
|
||||||
</thead>
|
|
||||||
<tbody id="taskTableBody">
|
<!-- 提交按钮 -->
|
||||||
<!-- 数据将在这里动态填充 -->
|
<div class="d-grid gap-2">
|
||||||
</tbody>
|
<button type="button" id="sub_btn" class="btn btn-primary">提交</button>
|
||||||
</table>
|
</div>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<p class="more-content"><a href="/query_download_task.html">查询文件下载任务状态</a> | 捐赠</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -97,57 +58,25 @@
|
||||||
<script src="static/js/bootstarp/5/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
<script src="static/js/bootstarp/5/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
<script src="static/js/jquery/2.1.4/jquery.min.js"></script>
|
<script src="static/js/jquery/2.1.4/jquery.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
let statusStrDict = new Map([
|
$(document).ready(function () {
|
||||||
[0,"排队中"],
|
console.log("document ready")
|
||||||
[1,"进行中"],
|
sub_btn.addEventListener('click', function (param) {
|
||||||
[2,"错误"],
|
|
||||||
[3,"已完成"]
|
|
||||||
])
|
|
||||||
data = [];
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "GET",
|
type: "POST",
|
||||||
url: "/GetMyTasks",
|
url: "/AddOfflineTask",
|
||||||
|
data: {
|
||||||
|
url: url_ipt.value
|
||||||
|
},
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.retcode == 0) {
|
if (response.retcode == 0)
|
||||||
data = response.data;
|
alert("任务提交成功! 请稍后点击页面下方的 \"查询文件下载任务状态\" 超链接查询任务状态!");
|
||||||
populateTable(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
else
|
||||||
alert(response.message);
|
alert(response.message);
|
||||||
},
|
|
||||||
error(xhr, status, error) {
|
|
||||||
alert(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
function formatBytes(bytes, decimals = 2) {
|
|
||||||
if (bytes === 0) return '0 Bytes';
|
|
||||||
const k = 1024;
|
|
||||||
const dm = decimals || 2;
|
|
||||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateTable(data) {
|
|
||||||
const tableBody = document.getElementById('taskTableBody');
|
|
||||||
tableBody.innerHTML = ''; // 清空现有内容
|
|
||||||
|
|
||||||
data.forEach(item => {
|
|
||||||
const row = document.createElement('tr');
|
|
||||||
row.innerHTML = `
|
|
||||||
<td><a href="/Download/${item.tid}"> ${item.file_name}</td>
|
|
||||||
<td class="hidden-on-small">${formatBytes(item.size)}</td>
|
|
||||||
<td>${item.add_time}</td>
|
|
||||||
<td>${statusStrDict.get(item.status)}</td>
|
|
||||||
<td class="hidden-on-small">${item.hash || 'N/A'}</td>
|
|
||||||
`;
|
|
||||||
tableBody.appendChild(row);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
229
src/wwwroot/query_download_task.html
Normal file
229
src/wwwroot/query_download_task.html
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>离线下载任务管理</title>
|
||||||
|
<link href="static/css/bootstarp/5/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
color: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
background-color: transparent;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th,
|
||||||
|
.table td {
|
||||||
|
padding: 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 256px;
|
||||||
|
/* 设置最大宽度 */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table thead th {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table tbody tr:nth-child(even) {
|
||||||
|
background-color: #f1f3f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table tbody tr:hover {
|
||||||
|
background-color: #e2e6ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th,
|
||||||
|
.table td {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-on-small {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-content {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#loading-mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
border: 16px solid #f3f3f3;
|
||||||
|
/* Light grey */
|
||||||
|
border-top: 16px solid #3498db;
|
||||||
|
/* Blue */
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="text-center">离线下载任务管理</h1>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<div id="loading-mask" style="display: none;">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
</div>
|
||||||
|
<table id="data-table" class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>文件名</th>
|
||||||
|
<th class="hidden-on-small">大小</th>
|
||||||
|
<th>提交时间</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th class="hidden-on-small">哈希</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="taskTableBody">
|
||||||
|
<!-- 数据将在这里动态填充 -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="more-content"><a href="/index.html">返回主页</a> | 捐赠</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 优先加载jq一类的三方库 -->
|
||||||
|
<script src="static/js/bootstarp/5/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="static/js/jquery/2.1.4/jquery.min.js"></script>
|
||||||
|
<script>
|
||||||
|
const $loadingMask = $('#loading-mask');
|
||||||
|
const $dataTable = $('#data-table');
|
||||||
|
|
||||||
|
// 显示遮罩层
|
||||||
|
function showLoadingMask() {
|
||||||
|
$loadingMask.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏遮罩层
|
||||||
|
function hideLoadingMask() {
|
||||||
|
$loadingMask.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoadingMask();
|
||||||
|
let statusStrDict = new Map([
|
||||||
|
[0, "排队中"],
|
||||||
|
[1, "进行中"],
|
||||||
|
[2, "错误"],
|
||||||
|
[3, "已完成"]
|
||||||
|
])
|
||||||
|
data = [];
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: "/GetMyTasks",
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
hideLoadingMask();
|
||||||
|
if (response.retcode == 0) {
|
||||||
|
data = response.data;
|
||||||
|
populateTable(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
alert(response.message);
|
||||||
|
},
|
||||||
|
error(xhr, status, error) {
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
function formatBytes(bytes, decimals = 2) {
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
const k = 1024;
|
||||||
|
const dm = decimals || 2;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateTable(data) {
|
||||||
|
const tableBody = document.getElementById('taskTableBody');
|
||||||
|
tableBody.innerHTML = ''; // 清空现有内容
|
||||||
|
|
||||||
|
data.forEach(item => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
row.innerHTML = `
|
||||||
|
<td>${item.status == 3 ? `<a href="/Download/${item.tid}">${item.file_name}</a>` : item.file_name}</td>
|
||||||
|
<td class="hidden-on-small">${formatBytes(item.size)}</td>
|
||||||
|
<td>${item.add_time}</td>
|
||||||
|
<td>${statusStrDict.get(item.status)}</td>
|
||||||
|
<td class="hidden-on-small">${item.hash || 'N/A'}</td>
|
||||||
|
`;
|
||||||
|
tableBody.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in a new issue