mirror of
https://github.com/ngfchl/ptools
synced 2023-07-10 13:41:22 +08:00
1181 lines
53 KiB
HTML
1181 lines
53 KiB
HTML
{% load static %}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>任务管理</title>
|
|
{# <link rel="stylesheet" href="https://unpkg.com/umy-ui/lib/theme-chalk/index.css">#}
|
|
<!-- 引入样式 -->
|
|
{% include 'admin/includes/css-part.html' %}
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vxe-table@legacy/lib/style.css">
|
|
<style>
|
|
/* 用来设置当前页面element全局table 选中某行时的背景色*/
|
|
.vxe-table--body tr.row--current > td {
|
|
background-color: #e76b11 !important;
|
|
color: #fff;
|
|
}
|
|
|
|
.vxe-table--body tr.row--checked > td {
|
|
background-color: rgb(86, 105, 219) !important;
|
|
color: #fff;
|
|
}
|
|
|
|
.col--current {
|
|
background-color: #e76b11 !important;
|
|
color: #fff;
|
|
}
|
|
|
|
.vxe-table--body tr > td {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.vxe-table--body .vxe-footer--column .col-blue {
|
|
background-color: #2db7f5;
|
|
color: #fff;
|
|
}
|
|
|
|
.vxe-table--body .vxe-footer--column .col-blue {
|
|
background-color: red;
|
|
color: #fff;
|
|
}
|
|
|
|
/* 用来设置当前页面element全局table 鼠标滑过某行时的背景色*/
|
|
.vxe-table--body .vxe-body--row.row--hover td {
|
|
background-color: #df9942 !important;
|
|
}
|
|
|
|
|
|
.table-footer .col-blue {
|
|
background-color: rgba(32, 63, 218, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-red {
|
|
background-color: rgba(255, 22, 1, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-orange {
|
|
background-color: rgba(241, 114, 46, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-green {
|
|
background-color: rgba(29, 119, 8, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-yellow {
|
|
background-color: rgba(231, 211, 108, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-blueviolet {
|
|
background-color: rgba(155, 62, 229, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.table-footer .col-greenyellow {
|
|
background-color: rgba(12, 238, 62, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.my-menus {
|
|
background-color: #F8F8F9;
|
|
}
|
|
|
|
.my-menus .vxe-ctxmenu--link {
|
|
width: 200px;
|
|
}
|
|
|
|
.my-copy-item {
|
|
font-weight: 700;
|
|
font-style: inherit;
|
|
}
|
|
|
|
.color-red {
|
|
color: red;
|
|
}
|
|
|
|
.color-blue {
|
|
color: blue;
|
|
}
|
|
|
|
.color-orange {
|
|
color: orange;
|
|
}
|
|
|
|
.footer-info {
|
|
background-color: rgba(218 165 32 /50%);
|
|
width: 100%;
|
|
height: 28px;
|
|
margin: auto;
|
|
padding: 5px;
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
position: fixed;
|
|
bottom: 0;
|
|
z-index: 999999;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.footer-item {
|
|
display: inline-block;
|
|
}
|
|
|
|
.el-tabs__item.is-active {
|
|
background-color: #da8342;
|
|
color: #fff;
|
|
}
|
|
|
|
.keyword-lighten {
|
|
color: #000;
|
|
background-color: #FFFF00;
|
|
}
|
|
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="app" style="height: 100%;">
|
|
<div style="text-align: center">
|
|
{# <el-button-group style="margin: auto;">#}
|
|
{# <el-button size="small"#}
|
|
{# type="warning" plain#}
|
|
{# v-for="downloader in downloaders"#}
|
|
{# icon="el-icon-s-promotion"#}
|
|
{# @click="handleButtonClick(downloader.id)">#}
|
|
{# <span v-text="downloader.name"></span>#}
|
|
{# </el-button>#}
|
|
{##}
|
|
{# </el-button-group>#}
|
|
<el-tabs ref="downloaders" type="card" editable @tab-click="handleButtonClick"
|
|
v-model="downloader_id"
|
|
@edit="handleTabsEdit">
|
|
<el-tab-pane v-for="downloader in downloaders"
|
|
:label="downloader.name"
|
|
icon="el-icon-s-promotion"
|
|
:name="downloader.id">
|
|
{# <span v-text="downloader.name"></span>#}
|
|
</el-tab-pane>
|
|
|
|
</el-tabs>
|
|
</div>
|
|
<div>
|
|
<el-dialog title="删除任务" :visible.sync="deleteForm" min-width="180" width="30%" center>
|
|
<div style="text-align: center">
|
|
<el-switch v-model="delete_files" active-text="删除文件" active-color="#ff4949"
|
|
inactive-text="保留文件">
|
|
</el-switch>
|
|
</div>
|
|
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="deleteForm = false">取 消</el-button>
|
|
<el-button type="danger" @click="handleDelete">确 定</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
<el-dialog title="修改分类" :visible.sync="categoryForm" min-width="180" center>
|
|
<div style="text-align: center">
|
|
<el-radio-group v-model="category" @change="setCategory" size="mini">
|
|
<el-radio-button v-for="item in categories"
|
|
:content="item.title"
|
|
border type="warning"
|
|
:label="item.value">
|
|
<span v-text="item.title"></span>
|
|
</el-radio-button>
|
|
</el-radio-group>
|
|
<el-button type="danger" size="mini" @click="setCategory">
|
|
<span>重置分类</span>
|
|
</el-button>
|
|
</div>
|
|
{# <span slot="footer" class="dialog-footer">#}
|
|
{# <el-button @click="categoryForm = false">取 消</el-button>#}
|
|
{# <el-button type="danger" @click="setCategory">确 定</el-button>#}
|
|
{# </span>#}
|
|
</el-dialog>
|
|
</div>
|
|
|
|
<vxe-toolbar ref="xToolbar" size="mini" custom style="margin-top: -15px;">
|
|
<template #buttons>
|
|
<vxe-input size="mini" v-model="searchModal" type="search" placeholder="试试全表搜索"
|
|
style="margin-right: 10px;width: 140px;"
|
|
@keyup="searchEvent"></vxe-input>
|
|
{# <el-button circle size="mini" type="primary" icon="el-icon-link" @click="handleSelected(resume)"></el-button>#}
|
|
{# <el-button circle size="mini" type="primary" icon="el-icon-plus" @click="handleSelected(resume)"></el-button>#}
|
|
<el-button circle size="mini" type="danger" icon="el-icon-delete" @click="handleDeleteForm"></el-button>
|
|
<el-button circle size="mini" type="success" icon="el-icon-video-play"
|
|
@click="handleSelected('resume')"></el-button>
|
|
<el-button circle size="mini" type="warning" icon="el-icon-video-pause"
|
|
@click="handleSelected('pause')"></el-button>
|
|
|
|
{# <el-dropdown split-button type="primary" size="mini" @command="handleSelected">#}
|
|
{# 操作#}
|
|
{# <el-dropdown-menu slot="dropdown">#}
|
|
{# <el-dropdown-item command="resume">继续</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="set_force_start">强制继续</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="pause">暂停</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="set_auto_management">自动管理</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="set_super_seeding">超级做种</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="recheck">重新校验</el-dropdown-item>#}
|
|
{# <el-dropdown-item command="reannounce">重新汇报</el-dropdown-item>#}
|
|
{# </el-dropdown-menu>#}
|
|
{# </el-dropdown>#}
|
|
{# <el-dropdown split-button type="success" size="mini">#}
|
|
{# 操作#}
|
|
{# <el-dropdown-menu slot="dropdown">#}
|
|
{# <el-dropdown-item>#}
|
|
{# <el-button size="mini" type="danger" @click="deleteForm = true">删除任务</el-button>#}
|
|
{# </el-dropdown-item>#}
|
|
{# <el-dropdown-item @click="setCategory">#}
|
|
{# <el-button size="mini" type="primary" @click="categoryForm = true">修改分类</el-button>#}
|
|
{# </el-dropdown-item>#}
|
|
{# <el-dropdown-item @click="limitSpeed">限速</el-dropdown-item>#}
|
|
{# <el-dropdown-item @click="setLocation">更改路径</el-dropdown-item>#}
|
|
{# </el-dropdown-menu>#}
|
|
{# </el-dropdown>#}
|
|
</template>
|
|
<template #tools>
|
|
<el-button size="mini" type="success" v-if="refresh" icon="el-icon-refresh" @click="startRefresh">刷新
|
|
</el-button>
|
|
<el-button size="mini" type="danger" v-else="refresh" icon="el-icon-pause" @click="stopRefresh">停止
|
|
</el-button>
|
|
|
|
{# <el-button size="mini" type="warning" icon="vxe-icon-funnel-clear" @click="clearFilters">清除筛选#}
|
|
{# </el-button>#}
|
|
{# <el-button size="mini" type="warning" icon="vxe-icon-square-checked-fill" @click="clearSelection">清除选中#}
|
|
{# </el-button>#}
|
|
</template>
|
|
</vxe-toolbar>
|
|
<div style="height: 90vh;bottom:0;border: coral solid 1px;display: flex;flex-flow: column;flex-direction: row;flex-wrap: wrap;">
|
|
<vxe-table ref="dataTable" id="table"
|
|
class="table-footer"
|
|
showBodyOverflow="title" showHeaderOverflow="title"
|
|
:menu-config="tableMenu"
|
|
@menu-click="contextMenuClickEvent"
|
|
show-footer
|
|
:footer-method="footerMethod"
|
|
:footer-cell-class-name="footerCellClassName"
|
|
:footer-span-method="footerColspanMethod"
|
|
@cell-dblclick="showDetails"
|
|
:data="torrents"
|
|
:loading="loading"
|
|
{# height="750" #}
|
|
height="100%"
|
|
size="mini"
|
|
auto-resize
|
|
round border stripe
|
|
:tooltip-config="{showAll: true}"
|
|
:keyboard-config="{isArrow: true, isTab: true, enterToTab: true}"
|
|
:column-config="{isCurrent: true, isHover: true, resizable: true}"
|
|
:mouse-config="{selected: true}"
|
|
:row-config="{isCurrent: true, isHover: true, keyField: 'hash', height: 25}"
|
|
:checkbox-config="{trigger: 'row', highlight: true, range: true, reserve: true}"
|
|
:sort-config="{trigger: 'cell', orders: ['desc', 'asc', null]}"
|
|
highlight-current-row
|
|
style="width: 100%;">
|
|
<vxe-table-column fixed="left" type="checkbox" width="45">
|
|
</vxe-table-column>
|
|
<vxe-table-column type="seq" fixed="left" width="60"></vxe-table-column>
|
|
<vxe-table-column field="name" fixed="left" sortable show-header-overflow show-overflow="tooltip"
|
|
show-footer-overflow title="种子名称" type="html" max-width="280" min-width="150">
|
|
</vxe-table-column>
|
|
<vxe-table-column field="size" sortable width="85" show-header-overflow show-overflow="tooltip"
|
|
show-footer-overflow :formatter="handleSize" title="大小">
|
|
</vxe-table-column>
|
|
<vxe-table-column field="category" sortable width="85"
|
|
type="html"
|
|
:filters="[]"
|
|
:filter-method="filterCategoryMethod"
|
|
:filter-multiple="false"
|
|
title="分类"></vxe-table-column>
|
|
<vxe-table-column field="tracker" sortable
|
|
:filters="[]"
|
|
type="html"
|
|
:formatter="handleTracker"
|
|
:filter-method="filterTrackerMethod"
|
|
:filter-multiple="false"
|
|
:filter-change="handlerTrackerFilter"
|
|
min-width="110"
|
|
title="Tracker"></vxe-table-column>
|
|
<vxe-table-column field="state" sortable width="85" :formatter="handleState" column-key="state"
|
|
:filter-method="filterStateMethod" type="html"
|
|
:filters="stateFilters" :filter-multiple="false" title="状态"></vxe-table-column>
|
|
<vxe-table-column field="last_activity" sortable width="105" type="html"
|
|
show-header-overflow show-overflow="tooltip"
|
|
show-footer-overflow title="最后活动"></vxe-table-column>
|
|
<vxe-table-column field="downloaded" :formatter="handleSize" min-width="90" sortable
|
|
type="html" title="已下载"></vxe-table-column>
|
|
<vxe-table-column field="uploaded" :formatter="handleSize" sortable width="85"
|
|
type="html" title="上传"></vxe-table-column>
|
|
<vxe-table-column field="dlspeed" sortable width="95" :formatter="handleSpeed"
|
|
type="html" title="下载速度"></vxe-table-column>
|
|
<vxe-table-column field="upspeed" sortable width="95" :formatter="handleSpeed"
|
|
type="html" title="上传速度"></vxe-table-column>
|
|
<vxe-table-column field="progress" sortable min-width="110" title="进度" type="html">
|
|
<template slot-scope="scope">
|
|
<el-progress
|
|
v-if="scope.row.progress==1"
|
|
:text-inside="true"
|
|
status="success"
|
|
stroke-linecap="butt"
|
|
:stroke-width="18"
|
|
:percentage="scope.row.progress * 100">
|
|
</el-progress>
|
|
<el-progress
|
|
v-else="scope.row.progress==1"
|
|
:text-inside="true"
|
|
:color="customColors"
|
|
:stroke-width="18"
|
|
:percentage="scope.row.progress * 100">
|
|
</el-progress>
|
|
</template>
|
|
</vxe-table-column>
|
|
|
|
<vxe-table-column field="ratio" sortable width="85" {# :formatter="handlePercent" #}
|
|
type="html" title="分享率"></vxe-table-column>
|
|
<vxe-table-column field="seeding_time" width="100"
|
|
show-header-overflow show-overflow="tooltip"
|
|
show-footer-overflow type="html"
|
|
title="做种时间"></vxe-table-column>
|
|
|
|
<vxe-table-column field="added_on" width="100"
|
|
show-header-overflow show-overflow="tooltip"
|
|
show-footer-overflow type="html"
|
|
title="添加时间"></vxe-table-column>
|
|
<template #empty>
|
|
<span style="color: red;">
|
|
<img src="https://pic2.zhimg.com/50/v2-f7031359103859e1ed38559715ef5f3f_hd.gif">
|
|
<p>搜索不到数据,可能输入的关键字姿势不对!</p>
|
|
</span>
|
|
</template>
|
|
</vxe-table>
|
|
|
|
</div>
|
|
{# <div class="footer-info">#}
|
|
{# <el-tag size="medium" effect="plain" type="success" class="footer-item">#}
|
|
{# <i class="vxe-icon-cloud-download"></i>#}
|
|
{# <span v-text="renderSize(server_state.up_info_speed) + '/S (' + renderSize(server_state.up_info_data) + '/' + renderSize(server_state.alltime_ul) + ')'"></span>#}
|
|
{# </el-tag>#}
|
|
{# <el-tag size="medium" effect="plain" type="warning" class="footer-item">#}
|
|
{# <i class="vxe-icon-cloud-upload"></i>#}
|
|
{# <span v-text="renderSize(server_state.dl_info_speed) + '/S (' + renderSize(server_state.dl_info_data)+ '/' + renderSize(server_state.alltime_dl) + ')'"></span>#}
|
|
{# </el-tag>#}
|
|
{##}
|
|
{# <el-tag size="medium" type="primary" class="footer-item">#}
|
|
{# <i class="fas fa-hdd"></i>#}
|
|
{# <span v-text="renderSize(server_state.free_space_on_disk)"></span>#}
|
|
{# </el-tag>#}
|
|
{# <el-tag size="medium" type="danger" class="footer-item">#}
|
|
{# <i class="fas fa-share-alt"></i>#}
|
|
{# <span v-text="server_state.global_ratio"></span>#}
|
|
{# </el-tag>#}
|
|
{# </div>#}
|
|
<div>
|
|
<el-drawer
|
|
style="margin-bottom: 35px !important;position: fixed;z-index:99999;"
|
|
:title="torrent.name"
|
|
:visible.sync="details"
|
|
direction="btt"
|
|
:modal="false"
|
|
:wrapperClosable="false"
|
|
:destroy-on-close="true"
|
|
:close-on-press-escape="true"
|
|
:close="closeDrawer"
|
|
:with-header="false"
|
|
show-header-overflow show-overflow="tooltip"
|
|
size="40%">
|
|
<el-descriptions :title="torrent.name" border size="mini" colon :column="1">
|
|
<el-descriptions-item v-for="(value,key,index) in torrent"
|
|
:label="key">
|
|
<span v-text="value"></span>
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-drawer>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{#<script src="https://unpkg.com/umy-ui@1.1.6/lib/index.js"></script>#}
|
|
<!-- 引入脚本 -->
|
|
{% include 'admin/includes/js-part.html' %}
|
|
<script src="https://cdn.jsdelivr.net/npm/xe-utils"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/vxe-table@legacy"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/xe-clipboard"></script>
|
|
|
|
<script src="{% static 'admin/simpleui-x/js/axios.min.js' %}"></script>
|
|
<script>
|
|
const download_state = {
|
|
'uploading': '正在上传',
|
|
'downloading': '正在下载',
|
|
'pausedUP': '完成上传',
|
|
'pausedDL': '暂停下载',
|
|
'checkingUP': '正在校验',
|
|
'forcedDL': '强制下载',
|
|
'stalledUP': '正在做种',
|
|
'stalledDL': '等待下载',
|
|
'missingFiles': '文件丢失',
|
|
'forcedUP': '强制做种',
|
|
'moving': '正在移动',
|
|
'queuedDL': '下载队列中',
|
|
'queuedUP': '上传队列中',
|
|
'error': '错误',
|
|
'unknown': '未知',
|
|
'allocating': '分配',
|
|
'metaDL': '下载元数据',
|
|
'checkingDL': '下载校验中',
|
|
'checkingResumeData': '校验恢复数据',
|
|
'forcedMetaDL': '强制下载元数据',
|
|
}
|
|
const vm = new Vue({
|
|
// 配置选项(option)
|
|
// element: 指定用vue来管理页面中的哪个标签区域
|
|
el: '#app',
|
|
data: {
|
|
downloaders: [],
|
|
loading: false,
|
|
mainData: {},
|
|
tracker_list: [],
|
|
dialogFormVisible: false,
|
|
timer: {},
|
|
deleteForm: false,
|
|
categoryForm: false,
|
|
refresh: false,
|
|
downloader_id: 0,
|
|
details: false,
|
|
table: {},
|
|
torrent: {},
|
|
torrents: [],
|
|
searchModal: '',
|
|
customColors: [
|
|
{color: '#f56c6c', percentage: 20},
|
|
{color: '#e6a23c', percentage: 40},
|
|
{color: '#5cb87a', percentage: 60},
|
|
{color: '#1989fa', percentage: 80},
|
|
{color: '#6f7ad3', percentage: 100}
|
|
],
|
|
selected_rows: [],
|
|
categoryFilters: [
|
|
{
|
|
label: '未分类',
|
|
value: ''
|
|
}
|
|
],
|
|
categories: [],
|
|
menuCategories: [],
|
|
category: '',
|
|
server_state: {},
|
|
delete_files: false,
|
|
tableMenu: {
|
|
className: 'my-menus',
|
|
header: {
|
|
options: [
|
|
[]
|
|
]
|
|
},
|
|
body: {
|
|
options: [
|
|
[
|
|
{
|
|
code: 'resume',
|
|
name: '继续',
|
|
prefixIcon: 'vxe-icon-square-caret-right'
|
|
},
|
|
{
|
|
code: 'set_force_start',
|
|
name: '强制继续',
|
|
prefixIcon: 'vxe-icon-square-caret-right-fill'
|
|
},
|
|
{
|
|
code: 'pause',
|
|
name: '暂停',
|
|
prefixIcon: 'vxe-icon-square-minus'
|
|
}
|
|
],
|
|
[
|
|
{
|
|
{#code: 'delete',#}
|
|
code: 'deleteForm',
|
|
name: '删除',
|
|
prefixIcon: 'vxe-icon-delete color-red'
|
|
},
|
|
],
|
|
[
|
|
{
|
|
name: '分类',
|
|
code: 'categoryForm',
|
|
prefixIcon: 'vxe-icon-square-square',
|
|
children: [
|
|
{#{code: 'create_category', name: '添加', prefixIcon: 'vxe-icon-square-plus'},#}
|
|
{#{code: 'set_category', name: '重置', prefixIcon: 'vxe-icon-square-close'},#}
|
|
{#{code: 'categoryForm', name: '修改分类', prefixIcon: 'vxe-icon-edit'},#}
|
|
]
|
|
},
|
|
{#{#}
|
|
{# name: '标签',#}
|
|
{# children: [#}
|
|
{# {code: 'create_tags', name: '添加'},#}
|
|
{# {code: 'remove_tags', name: '删除全部'}#}
|
|
{# ]#}
|
|
//},
|
|
{
|
|
code: 'set_auto_management',
|
|
name: '自动管理',
|
|
prefixIcon: 'vxe-icon-platform'
|
|
},
|
|
],
|
|
[
|
|
{
|
|
code: 'set_super_seeding',
|
|
name: '超级做种',
|
|
prefixIcon: 'vxe-icon-cloud-download'
|
|
}
|
|
],
|
|
|
|
[
|
|
{code: 'recheck', name: '重新校验', prefixIcon: 'vxe-icon-folder'},
|
|
{code: 'reannounce', name: '重新汇报', prefixIcon: 'vxe-icon-comment'},
|
|
{
|
|
code: 'copy',
|
|
name: '复制当前',
|
|
prefixIcon: 'vxe-icon-copy',
|
|
children: [
|
|
{code: 'name', name: '名称', prefixIcon: 'vxe-icon-table'},
|
|
{code: 'hash', name: 'HASH', prefixIcon: 'vxe-icon-sort-alpha-asc'},
|
|
{code: 'magnet_uri', name: '链接', prefixIcon: 'vxe-icon-sort-alpha-desc'}
|
|
]
|
|
}
|
|
],
|
|
[
|
|
{
|
|
code: 'sort',
|
|
name: '排序',
|
|
prefixIcon: 'vxe-icon-sort',
|
|
children: [
|
|
{code: 'clearSort', name: '清除排序', prefixIcon: 'vxe-icon-undo'},
|
|
{#{code: 'sortAsc', name: '升序', prefixIcon: 'vxe-icon-sort-alpha-asc'},#}
|
|
{#{code: 'sortDesc', name: '倒序', prefixIcon: 'vxe-icon-sort-alpha-desc'}#}
|
|
]
|
|
},
|
|
{
|
|
name: '筛选',
|
|
prefixIcon: 'vxe-icon-funnel',
|
|
children: [
|
|
{code: 'clearFilter', name: '清除筛选', prefixIcon: 'vxe-icon-funnel-clear'},
|
|
{
|
|
code: 'filterSelect',
|
|
name: '按所选单元格的值筛选',
|
|
prefixIcon: 'vxe-icon-square-checked'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
code: 'clearCheckboxRow',
|
|
name: '清除选中',
|
|
prefixIcon: 'vxe-icon-funnel',
|
|
{#children: [#}
|
|
{# {code: 'clearCheckboxRow', name: '清除选中', prefixIcon: 'vxe-icon-funnel-clear'},#}
|
|
{#{#}
|
|
{# code: 'setAllCheckboxRow',#}
|
|
{# name: '全选',#}
|
|
{# prefixIcon: 'vxe-icon-square-checked'#}
|
|
//}
|
|
{#]#}
|
|
}
|
|
],
|
|
]
|
|
},
|
|
footer: {
|
|
options: [
|
|
[],
|
|
[],
|
|
[]
|
|
]
|
|
},
|
|
visibleMethod: this.menuVisibleMethod
|
|
}
|
|
},
|
|
beforeMount() {
|
|
window.vm = this
|
|
// 任务状态过滤器数据
|
|
let data = []
|
|
for (let x in download_state) {
|
|
data.push({
|
|
'label': download_state[x],
|
|
'value': x
|
|
})
|
|
}
|
|
this.stateFilters = data
|
|
},
|
|
mounted() {
|
|
this.loading = true
|
|
this.$message({
|
|
type: 'warning', message: '下载器将在十分钟后停止刷新!'
|
|
});
|
|
{#console.log("获取下载器数量:", this.downloaders.length)#}
|
|
{#this.get_downloading(this.downloaders[0].id)#}
|
|
},
|
|
updated() {
|
|
// 十分钟后停止刷新
|
|
setTimeout(() => {
|
|
clearInterval(this.timer)
|
|
this.timer = null
|
|
this.refresh = true
|
|
}, 1000 * 60 * 10)
|
|
},
|
|
beforeUpdated() {
|
|
|
|
},
|
|
// 清除定时器,不然页面会卡死
|
|
beforeDestroy() {
|
|
this.$once('hook:beforeDestroy',
|
|
() => {
|
|
clearInterval(this.timer)
|
|
this.timer = null
|
|
}
|
|
)
|
|
},
|
|
created() {
|
|
this.$nextTick(() => {
|
|
// 将表格和工具栏进行关联
|
|
this.table = this.$refs.dataTable
|
|
{#console.log(this.$refs)#}
|
|
this.table.connect(this.$refs.xToolbar)
|
|
{#let ddd = this.$refs.downloaders#}
|
|
{#console.log(ddd.$data.panes)#}
|
|
})
|
|
|
|
this.get_downloaders()
|
|
},
|
|
watch: {},
|
|
methods: {
|
|
handleTabsEdit(targetName, action) {
|
|
if (action === 'add') {
|
|
let newTabName = ++this.tabIndex + '';
|
|
this.editableTabs.push({
|
|
title: 'New Tab',
|
|
name: newTabName,
|
|
content: 'New Tab content'
|
|
});
|
|
this.downloader_id = newTabName;
|
|
}
|
|
if (action === 'remove') {
|
|
let tabs = this.editableTabs;
|
|
let activeName = this.downloader_id;
|
|
if (activeName === targetName) {
|
|
tabs.forEach((tab, index) => {
|
|
if (tab.name === targetName) {
|
|
let nextTab = tabs[index + 1] || tabs[index - 1];
|
|
if (nextTab) {
|
|
activeName = nextTab.name;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
this.downloader_id = activeName;
|
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName);
|
|
}
|
|
},
|
|
footerMethod({columns, data}) {
|
|
return [
|
|
/**
|
|
columns.map((column, columnIndex) => {
|
|
if (columnIndex === 1) {
|
|
return '总计'
|
|
}
|
|
return data.length
|
|
|
|
if (['size'].includes(column.property)) {
|
|
return this.renderSize(this.meanNum(data, column.property))
|
|
}
|
|
return null
|
|
|
|
}),
|
|
**/
|
|
columns.map((column, columnIndex) => {
|
|
if (columnIndex === 0) {
|
|
return '总计'
|
|
}
|
|
if (columnIndex === 1) {
|
|
return data.length
|
|
}
|
|
|
|
if (columnIndex === 2) {
|
|
return '做种大小:' + this.renderSize(this.sumNum(data, 'size'))
|
|
}
|
|
|
|
if (columnIndex === 3) {
|
|
return '剩余空间:'
|
|
}
|
|
|
|
if (columnIndex === 4) {
|
|
return this.renderSize(this.server_state.free_space_on_disk)
|
|
}
|
|
if (columnIndex === 5) {
|
|
return '分享率:' + this.server_state.global_ratio
|
|
}
|
|
|
|
if (columnIndex === 6) {
|
|
return '上传'
|
|
}
|
|
if (columnIndex === 7) {
|
|
return this.renderSize(this.server_state.up_info_speed) + ' / S(' +
|
|
this.renderSize(this.server_state.up_info_data) + ' / ' +
|
|
this.renderSize(this.server_state.alltime_ul) + ')'
|
|
|
|
}
|
|
if (columnIndex === 8) {
|
|
return '下载'
|
|
}
|
|
if (columnIndex === 9) {
|
|
return this.renderSize(this.server_state.dl_info_speed) + '/S (' +
|
|
this.renderSize(this.server_state.dl_info_data) + '/' +
|
|
this.renderSize(this.server_state.alltime_dl) + ')'
|
|
}
|
|
|
|
return null
|
|
})
|
|
]
|
|
},
|
|
/**
|
|
* 合并列
|
|
*/
|
|
footerColspanMethod({$rowIndex, _columnIndex}) {
|
|
if ($rowIndex === 0) {
|
|
if (_columnIndex === 7) {
|
|
return {
|
|
rowspan: 1,
|
|
colspan: 3
|
|
}
|
|
}
|
|
if (_columnIndex === 9) {
|
|
return {
|
|
rowspan: 1,
|
|
colspan: 3
|
|
}
|
|
}
|
|
if (_columnIndex === 10) {
|
|
return {
|
|
rowspan: 1,
|
|
colspan: 3
|
|
}
|
|
}
|
|
}
|
|
},
|
|
meanNum(list, field) {
|
|
let count = 0
|
|
list.forEach(item => {
|
|
count += Number(item[field])
|
|
})
|
|
return count / list.length
|
|
},
|
|
sumNum(list, field) {
|
|
let count = 0
|
|
list.forEach(item => {
|
|
count += Number(item[field])
|
|
})
|
|
return count
|
|
},
|
|
footerCellClassName({$rowIndex, columnIndex}) {
|
|
if (columnIndex === 0 || columnIndex === 1) {
|
|
return 'col-blue'
|
|
}
|
|
if (columnIndex === 2) {
|
|
return 'col-orange'
|
|
}
|
|
if (columnIndex === 3 || columnIndex === 4) {
|
|
return 'col-yellow'
|
|
}
|
|
if (columnIndex === 5) {
|
|
return 'col-red'
|
|
}
|
|
if (columnIndex === 6 || columnIndex === 7) {
|
|
return 'col-green'
|
|
}
|
|
if (columnIndex === 8 || columnIndex === 9) {
|
|
return 'col-blueviolet'
|
|
}
|
|
if (columnIndex === 10) {
|
|
return 'col-greenyellow'
|
|
}
|
|
},
|
|
searchEvent() {
|
|
const filterName = XEUtils.toValueString(this.searchModal).trim().toLowerCase()
|
|
if (filterName) {
|
|
const filterRE = new RegExp(filterName, 'gi')
|
|
const searchProps = ['name', 'category', 'tracker', 'state']
|
|
const rest = this.mainData.torrents.filter(item => searchProps.some(key => XEUtils.toValueString(item[key]).toLowerCase().indexOf(filterName) > -1))
|
|
this.torrents = rest.map(row => {
|
|
const item = Object.assign({}, row)
|
|
searchProps.forEach(key => {
|
|
item[key] = XEUtils.toValueString(item[key]).replace(filterRE, match => `<span class="keyword-lighten">${match}</span>`)
|
|
})
|
|
return item
|
|
})
|
|
} else {
|
|
this.torrents = this.mainData.torrents
|
|
}
|
|
},
|
|
showDetails({row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event}) {
|
|
console.log(row)
|
|
this.torrent = row
|
|
this.details = true
|
|
},
|
|
closeDrawer() {
|
|
this.details = false
|
|
this.torrent = {}
|
|
},
|
|
clearFilters() {
|
|
//清除筛选
|
|
this.table.clearFilter()
|
|
},
|
|
clearSelection() {
|
|
//清除选中
|
|
this.table.clearCheckboxRow()
|
|
},
|
|
stopRefresh() {
|
|
this.refresh = true
|
|
clearInterval(this.timer)
|
|
this.timer = null
|
|
},
|
|
startRefresh() {
|
|
this.refresh = false
|
|
this.timer = setInterval(() => {
|
|
this.get_downloading(this.downloader_id)
|
|
}, 5000)
|
|
},
|
|
handleButtonClick(id) {
|
|
console.log(id.$el)
|
|
id.active = true
|
|
{#handleButtonClick({value, $event}) {#}
|
|
this.loading = true
|
|
this.downloader_id = id.name
|
|
clearInterval(this.timer)
|
|
this.timer = null
|
|
this.mainData = []
|
|
this.categories = []
|
|
this.get_downloader_categories(this.downloader_id)
|
|
this.timer = setInterval(() => {
|
|
this.get_downloading(this.downloader_id)
|
|
}, 5000)
|
|
this.refresh = false
|
|
},
|
|
get_downloaders() {
|
|
axios.get(
|
|
"{% url "get_downloaders" %}"
|
|
).then(res => {
|
|
this.loading = true
|
|
if (res.data.code === 0) {
|
|
console.log('获取下载器列表成功', res.data.data)
|
|
this.downloaders = res.data.data
|
|
this.downloader_id = this.downloaders[0].id
|
|
this.get_downloader_categories(this.downloader_id)
|
|
this.timer = setInterval(() => {
|
|
this.get_downloading(this.downloader_id)
|
|
}, 5000)
|
|
} else {
|
|
this.$message({
|
|
type: 'warning', message: '获取下载器列表失败!'
|
|
});
|
|
}
|
|
}).catch(res => {
|
|
console.log('获取下载器列表失败', res)
|
|
this.$message({type: 'warning', message: '获取下载器列表失败!' + res});
|
|
})
|
|
},
|
|
get_downloader_categories(downloader_id) {
|
|
axios.get(
|
|
"{% url "get_downloader_categories" %}",
|
|
{
|
|
params: {
|
|
id: downloader_id
|
|
}
|
|
}
|
|
).then(res => {
|
|
this.loading = true
|
|
if (res.data.code === 0) {
|
|
console.log('获取下载器分类列表成功', res.data.data)
|
|
this.tracker_list = res.data.data.tracker_list;
|
|
const trackerFilter = [{label: '无', value: ''}]
|
|
this.tracker_list.forEach((value, index, array) => {
|
|
{#console.log(value, index)#}
|
|
trackerFilter.push({'label': value.name, 'value': value.tracker})
|
|
})
|
|
let categoryFilters = [{label: '未分类', value: ''}]
|
|
let categories = res.data.data.categories
|
|
this.categories = []
|
|
categories.forEach((value, index, array) => {
|
|
categoryFilters.push({'label': value, 'value': value})
|
|
this.categories.push({'title': value, 'value': value})
|
|
{#this.menuCategories.push({code: 'set_category', name: value},)#}
|
|
})
|
|
// 异步加载筛选数据
|
|
{#this.table = this.$refs.dataTable#}
|
|
if (this.table) {
|
|
const categoryColumn = this.table.getColumnByField('category')
|
|
{#console.log(nameColumn)#}
|
|
if (categoryColumn) {
|
|
this.table.setFilter(categoryColumn, categoryFilters)
|
|
}
|
|
const trackerColumn = this.table.getColumnByField('tracker')
|
|
{#console.log(trackerColumn)#}
|
|
if (trackerColumn) {
|
|
this.table.setFilter(trackerColumn, trackerFilter)
|
|
}
|
|
}
|
|
} else {
|
|
this.$message({
|
|
type: 'warning', message: '获取下载器列表失败!'
|
|
});
|
|
}
|
|
}).catch(res => {
|
|
console.log('获取下载器列表失败', res)
|
|
this.$message({type: 'warning', message: '获取下载器列表失败!' + res});
|
|
})
|
|
},
|
|
get_downloading(downloader_id) {
|
|
axios.get(
|
|
"{% url "downloading" %}",
|
|
{
|
|
params: {
|
|
id: downloader_id
|
|
}
|
|
}
|
|
).then(res => {
|
|
if (res.data.code === 0) {
|
|
this.mainData = res.data.data
|
|
this.searchEvent()
|
|
{#console.log(res.data.data.tracker_filters)#}
|
|
this.server_state = res.data.data.server_state
|
|
this.loading = false
|
|
|
|
// 获取种子
|
|
//this.$message({
|
|
// type: 'success',
|
|
// message: '任务加载成功!!'
|
|
// })
|
|
} else {
|
|
{#console.log(res.data.data)#}
|
|
this.$message({
|
|
type: 'warning', message: '任务加载出错!!'
|
|
})
|
|
}
|
|
})
|
|
|
|
},
|
|
handlerTrackerFilter({column, property, values, datas, filterList, $event}) {
|
|
console.log(column, property, values, datas, filterList, $event)
|
|
},
|
|
handleSize({row, column, cellValue, index}) {
|
|
return this.renderSize(cellValue)
|
|
},
|
|
// 执行格式化文件大小
|
|
handleSpeed({row, column, cellValue, index}) {
|
|
return this.renderSize(cellValue) !== 0 ? this.renderSize(cellValue) + '/S' : ''
|
|
},
|
|
// 格式化文件大小
|
|
renderSize(value) {
|
|
if (null == value || value == '') {
|
|
return 0;
|
|
}
|
|
var unitArr = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
var index = 0;
|
|
var srcsize = parseFloat(value);
|
|
index = Math.floor(Math.log(srcsize) / Math.log(1024));
|
|
var size = srcsize / Math.pow(1024,
|
|
index);
|
|
size = size.toFixed(2);//保留的小数位数
|
|
return size + ' ' + unitArr[index];
|
|
},
|
|
// 格式化进度
|
|
handlePercent({row, column, cellValue, index}) {
|
|
return (cellValue * 100).toFixed(2) + '%'
|
|
},
|
|
// 格式化分享率
|
|
handleRatio({row, column, cellValue, index}) {
|
|
return cellValue.toFixed(4)
|
|
},
|
|
handleTracker({row, column, cellValue, index}) {
|
|
// 格式化输出tracker所属的站点
|
|
let site = this.tracker_list.find(site => cellValue.includes(site.tracker))
|
|
{#console.log(row)#}
|
|
{#console.log(cellValue.includes('joy'))#}
|
|
{#return cellValue#}
|
|
return null != site ? site.name : cellValue
|
|
},
|
|
handleState({row, column, cellValue, index}) {
|
|
return download_state[cellValue]
|
|
},
|
|
filterStateMethod({value, row, column}) {
|
|
const property = column['property'];
|
|
return row[property] === value;
|
|
},
|
|
filterCategoryMethod({value, row, column}) {
|
|
const property = column['property'];
|
|
return row[property] === value;
|
|
},
|
|
filterTrackerMethod({value, row, column}) {
|
|
const property = column['property'];
|
|
return row[property].includes(value);
|
|
},
|
|
handleDeleteForm() {
|
|
if (this.table.getCheckboxRecords().length <= 0) {
|
|
this.$message({type: 'warning', message: '未选中种子!!'})
|
|
return
|
|
}
|
|
this.deleteForm = true
|
|
},
|
|
handleSetCategory() {
|
|
if (this.table.getCheckboxRecords().length <= 0) {
|
|
this.$message({type: 'warning', message: '未选中种子!!'})
|
|
return
|
|
}
|
|
this.categoryForm = true
|
|
},
|
|
handleSelected(command, category = '', delete_files = false, enable = 'True') {
|
|
let ids = []
|
|
const selectedRows = this.table.getCheckboxRecords()
|
|
if (selectedRows.length <= 0) {
|
|
this.$message({type: 'warning', message: '未选中任何种子!!'})
|
|
return
|
|
}
|
|
console.log('enable', enable)
|
|
selectedRows.forEach((item, index) => {
|
|
console.log(item['hash'], index)
|
|
ids.push(item['hash'])
|
|
})
|
|
let data = new FormData()
|
|
data.append('ids', ids)
|
|
data.append('command', command)
|
|
data.append('enable', enable)
|
|
data.append('category', category)
|
|
data.append('downloader_id', this.downloader_id)
|
|
axios.post(
|
|
"{% url "control_torrent" %}",
|
|
data
|
|
).then(res => {
|
|
console.log(res.data)
|
|
this.get_downloading(this.downloader_id)
|
|
this.$message({type: 'success', message: '指令发送成功!!'})
|
|
this.selected_rows = []
|
|
{#this.$refs.dataTable.clearSelection()#}
|
|
this.table.clearCheckboxRow()
|
|
}).catch(() => {
|
|
this.$message({type: 'warning', message: '指令发送失败!!'})
|
|
})
|
|
},
|
|
tableSelected({checked, row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event}) {
|
|
this.selected_rows = this.table.getCheckboxRecords()
|
|
},
|
|
rowKey(row) {
|
|
console.log(row.hash)
|
|
return row.hash
|
|
},
|
|
handleDelete() {
|
|
console.log(this.delete_files)
|
|
// { #this.deleteForm = true# }
|
|
this.handleSelected('delete', '', this.delete_files)
|
|
this.deleteForm = false
|
|
this.delete_files = false
|
|
},
|
|
setCategory() {
|
|
this.handleSelected('set_category', this.category)
|
|
this.categoryForm = false
|
|
this.category = ''
|
|
},
|
|
limitSpeed() {
|
|
},
|
|
setLocation() {
|
|
},
|
|
setCategoryFilter(fieldOrColumn, options) {
|
|
console.log(fieldOrColumn, options)
|
|
},
|
|
menuVisibleMethod({options, column}) {
|
|
console.log(options)
|
|
return true
|
|
},
|
|
contextMenuClickEvent({menu, type, row, rowIndex, column, columnIndex, $event}) {
|
|
/**
|
|
* 如果选中任务列表为空,则选中当前任务
|
|
*/
|
|
{#const selectedRows = this.table.getCheckboxRecords()#}
|
|
if (this.table.getCheckboxRecords().length <= 0) {
|
|
this.table.setCheckboxRow(row, true)
|
|
}
|
|
console.log(menu, type, row, rowIndex, column, columnIndex, $event)
|
|
switch (menu.code) {
|
|
case 'copy':
|
|
// 示例
|
|
if (row && column) {
|
|
if (XEClipboard.copy(row[column.property])) {
|
|
VXETable.modal.message({content: '已复制到剪贴板!', status: 'success'})
|
|
}
|
|
}
|
|
break
|
|
case 'name':
|
|
case 'hash':
|
|
case 'magnet_uri':
|
|
let content = []
|
|
//将要复制的字段放到数组中,然后把数组写入剪贴板
|
|
Array.from(this.table.getCheckboxRecords()).forEach((value, index, array) => {
|
|
content.push(value[menu.code])
|
|
})
|
|
console.log(content)
|
|
if (XEClipboard.copy(content)) {
|
|
VXETable.modal.message({content: '已复制到剪贴板!', status: 'success'})
|
|
}
|
|
content = []
|
|
/**
|
|
if (row && column) {
|
|
if (XEClipboard.copy(row[menu.code])) {
|
|
VXETable.modal.message({content: '已复制到剪贴板!', status: 'success'})
|
|
}
|
|
} */
|
|
break
|
|
case 'resume':
|
|
case 'set_force_start':
|
|
case 'pause':
|
|
case 'set_auto_management':
|
|
case 'recheck':
|
|
case 'reannounce':
|
|
this.handleSelected(menu.code)
|
|
break
|
|
case 'set_super_seeding':
|
|
let enable = !row['super_seeding']
|
|
console.log('enable1', enable)
|
|
this.handleSelected(menu.code, '', '', enable)
|
|
break
|
|
case 'deleteForm':
|
|
this.handleDeleteForm()
|
|
break
|
|
case 'categoryForm':
|
|
this.handleSetCategory()
|
|
break
|
|
case 'clearSort':
|
|
this.table.clearSort()
|
|
break
|
|
case 'clearFilter':
|
|
this.table.clearFilter()
|
|
break
|
|
case 'clearCheckboxRow':
|
|
this.table.clearCheckboxRow()
|
|
break
|
|
case 'setAllCheckboxRow':
|
|
this.table.setAllCheckboxRow(true)
|
|
break
|
|
case 'filterSelect':
|
|
|
|
break
|
|
default:
|
|
VXETable.modal.message(`点击了 ${menu.name} 选项,该功能尚未开发完成!`)
|
|
}
|
|
},
|
|
}
|
|
})
|
|
;
|
|
</script>
|
|
</body>
|
|
</html>
|