Files
ptools/templates/auto_pt/downloading.html

687 lines
30 KiB
HTML

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务管理</title>
{% include 'admin/includes/css-part.html' %}
<link rel="stylesheet" href="https://unpkg.com/umy-ui/lib/theme-chalk/index.css">
<!-- 引入样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vxe-table@legacy/lib/style.css">
<style>
/* 用来设置当前页面element全局table 选中某行时的背景色*/
.el-table__body tr.current-row > td {
background-color: #69A8EA !important;
color: #fff;
}
/* 用来设置当前页面element全局table 鼠标滑过某行时的背景色*/
.el-table__body .el-table__row.hover-row td {
background-color: #aaaaaa !important;
}
</style>
</head>
<body>
<div id="app">
<el-tabs type="border-card" @tab-click="handleTabClick">
<el-tab-pane
v-for="downloader in downloaders"
:title="downloader.name"
{# :name="downloader.id"#}
:id="downloader.id">
<div>
<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>
<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"
width="30%"
center>
<div style="text-align: center">
<el-select v-model="category" filterable placeholder="请选择分类">
<el-option
v-for="item in categories"
:key="item.value"
:title="item.title"
:value="item.value">
</el-option>
</el-select>
</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 style="font-size: 13px;margin: 5px auto -5px;text-align: center;">
<span>
<el-tag size="medium" type="danger" v-text="'总分享率:' + server_state.global_ratio"></el-tag>
</span>
<span>
<el-tag size="medium" type="success"
v-text="'剩余空间:' + renderSize(server_state.free_space_on_disk)"></el-tag>
</span>
<span>
<el-tag size="medium" type="" v-text="'历史下载:' + renderSize(server_state.alltime_dl)"></el-tag>
</span>
<span>
<el-tag size="medium" type="warning"
v-text="'历史上传:' + renderSize(server_state.alltime_ul)"></el-tag>
</span>
<span>
<el-tag size="medium" effect="plain" color="#233223"
v-text="'本次下载:' + renderSize(server_state.dl_info_data)"></el-tag>
</span>
<span>
<el-tag size="medium" effect="plain" color="#296969"
v-text="'下载速度:' + renderSize(server_state.dl_info_speed)"></el-tag>
</span>
<span>
<el-tag size="medium" effect="plain" color="#545454"
v-text="'本次上传:' + renderSize(server_state.up_info_data)"></el-tag>
</span>
<span>
<el-tag size="medium" color="#696969"
v-text="'上传速度:' + renderSize(server_state.up_info_speed) + '/S'"></el-tag>
</span>
</div>
</div>
<hr/>
<vxe-table
:ref="'table' + downloader.id"
row-height="55"
use-virtual
showBodyOverflow="title"
showHeaderOverflow="title"
@row-dblclick="handleRow"
@row-contextmenu="rtClick"
@selection-change="tableSelected"
:data="torrents"
height="700"
size="mini"
:row-key="(row) => row.hash"
round
border
stripe
:column-config="{isCurrent: true, isHover: true, resizable: true}"
:row-config="{isCurrent: true, isHover: true}"
beautify-table
highlight-current-row
style="width: 100%">
<vxe-table-column
fixed
:reserve-selection="true"
type="checkbox">
</vxe-table-column>
<vxe-table-column type="seq" fixed></vxe-table-column>
<vxe-table-column
field="name"
fixed
sortable
show-header-overflow show-overflow="tooltip" show-footer-overflow
title="种子名称" 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="downloaded" :formatter="handleSize"#}
{# title="已下载"></vxe-table-column>#}
<vxe-table-column field="uploaded"
:formatter="handleSize"
sortable
width="85"
title="上传"></vxe-table-column>
<vxe-table-column field="dlspeed"
sortable
width="95"
:formatter="handleSpeed"
title="下载速度"></vxe-table-column>
<vxe-table-column field="upspeed"
sortable
width="95"
:formatter="handleSpeed"
title="上传速度"></vxe-table-column>
<vxe-table-column
field="progress"
sortable
width="90"
title="进度">
<template slot-scope="scope">
<el-progress
v-if="scope.row.progress==1"
status="success"
{# type="circle"#}
width="20"
{# :text-inside="true"#}
{# :stroke-width="20"#}
{# stroke-linecap="butt"#}
:percentage="scope.row.progress * 100">
</el-progress>
<el-progress
v-else="scope.row.progress==1"
{# :text-inside="true"#}
{# type="circle"#}
width="20"
:color="customColors"
{# :stroke-width="18"#}
:percentage="scope.row.progress * 100">
</el-progress>
</template>
</vxe-table-column>
<vxe-table-column field="save_path"
show-header-overflow show-overflow="tooltip" show-footer-overflow
sortable
width="150"
title="保存路径"></vxe-table-column>
<vxe-table-column field="ratio"
sortable
width="85"
{# :formatter="handlePercent"#}
title="分享率"></vxe-table-column>
{# <vxe-table-column field="seeding_time"#}
{# title="做种时间"></vxe-table-column>#}
<vxe-table-column field="state"
sortable
width="85"
:formatter="handleState"
column-key="state"
:filter-method="filterStateMethod"
{# :filters="[{text: '做种中', value: 'stalledUP'}, {text: '上传中', value: 'uploading'}, {text: '下载中', value: 'downloading'}]"#}
:filters="stateFilters"
:filter-multiple="false"
title="状态"></vxe-table-column>
<vxe-table-column field="last_activity"
sortable
width="105"
show-header-overflow show-overflow="tooltip" show-footer-overflow
title="最后活动"></vxe-table-column>
{# <vxe-table-column field="added_on"#}
{# title="添加时间"></vxe-table-column>#}
<vxe-table-column field="category"
sortable
width="85"
:filters="categoryFilters"
{# :filters="setCategoryFilter"#}
:filter-method="filterStateMethod"
:filter-multiple="false"
title="分类"></vxe-table-column>
{# <vxe-table-column field="tracker"#}
{# title="Tracker"></vxe-table-column>#}
{# <vxe-table-column#}
{# width="120"#}
{# fixed="right"#}
{# title="操作">#}
{# #}
{# </vxe-table-column>#}
</vxe-table>
</el-tab-pane>
</el-tabs>
<el-dialog title="任务详情" :visible.sync="dialogFormVisible">
<el-form :model="torrent">
<el-form-item title="种子名称">
<el-input v-model="torrent.name"></el-input>
</el-form-item>
<el-form-item title="大小">
<el-input v-model="torrent.size"></el-input>
</el-form-item>
<el-form-item title="已下载">
<el-input v-model="torrent.downloaded"></el-input>
</el-form-item>
<el-form-item title="已上传">
<el-input v-model="torrent.uploaded"></el-input>
</el-form-item>
<el-form-item title="下载速度">
<el-input v-model="torrent.dlspeed"></el-input>
</el-form-item>
<el-form-item title="上传速度">
<el-input v-model="torrent.upspeed"></el-input>
</el-form-item>
<el-form-item title="下载进度">
<el-input v-model="torrent.progress"></el-input>
</el-form-item>
<el-form-item
:formatter="handleRatio"
title="分享率">
<el-input v-model="torrent.ratio"></el-input>
</el-form-item>
<el-form-item title="做种时间">
<el-input v-model="torrent.seeding_time"></el-input>
</el-form-item>
<el-form-item title="当前状态">
<el-input v-model="torrent.state"></el-input>
</el-form-item>
<el-form-item title="最后活动">
<el-input v-model="torrent.last_activity"></el-input>
</el-form-item>
<el-form-item title="添加时间">
<el-input v-model="torrent.added_on"></el-input>
</el-form-item>
<el-form-item title="分类">
<el-input v-model="torrent.added_on"></el-input>
</el-form-item>
<el-form-item title="Tracker">
<el-input v-model="torrent.tracker"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
</div>
{% include 'admin/includes/js-part.html' %}
<script src="https://unpkg.com/umy-ui@1.1.6/lib/index.js"></script>
<!-- 引入脚本 -->
<script src="https://cdn.jsdelivr.net/npm/xe-utils"></script>
<script src="https://cdn.jsdelivr.net/npm/vxe-table@legacy"></script>
<script src="{% static 'admin/simpleui-x/js/axios.min.js' %}"></script>
<script>
const download_state = {
'allocating': '分配',
'checkingDL': '校验中',
'checkingResumeData': '校验恢复数据',
{#'checkingUP': '',#}
'downloading': '下载中',
'error': '错误',
'forcedDL': '强制下载',
'forcedMetaDL': '强制下载元数据',
'forcedUP': '强制上传',
'metaDL': '下载元数据',
'missingFiles': '文件丢失',
'moving': '移动中',
'pausedDL': '暂停下载',
'pausedUP': '完成',
'queuedDL': '下载队列中',
'queuedUP': '下载队列中',
'stalledDL': '等待下载',
'stalledUP': '做种',
'unknown': '未知',
'uploading': '上传中',
}
const vm = new Vue({
// 配置选项(option)
// element: 指定用vue来管理页面中的哪个标签区域
el: '#app',
data: {
downloaders: '',
loading: false,
torrents: [],
dialogFormVisible: false,
timer: {},
deleteForm: false,
categoryForm: false,
refresh: false,
downloader_id: 0,
torrent: {
name: '',
category: '',
size: '',
downloaded: '',
uploaded: '',
dlspeed: '',
upspeed: '',
progress: '',
ratio: '',
seeding_time: '',
state: '',
last_activity: '',
added_on: '',
tracker: '',
},
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: [],
category: '',
server_state: {},
delete_files: false,
},
beforeMount() {
},
mounted() {
window.vm = this
// 任务状态过滤器数据
let data = []
for (let x in download_state) {
{#console.log(download_state[x])#}
data.push({
'label': download_state[x],
'value': x
})
}
this.stateFilters = data
{#console.log(this.stateFilters)#}
this.get_downloader()
console.log("下载器:", this.downloaders.length)
this.timer = setInterval(() => {
this.get_downloading(this.downloaders[0].id)
}, 1500)
},
// 清除定时器,不然页面会卡死
beforeDestroy() {
this.$once('hook:beforeDestroy',
() => {
clearInterval(this.timer)
this.timer = null
}
)
},
watch: {},
methods: {
tableSelected(rows) {
this.selected_rows = rows
console.log(this.selected_rows)
},
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(){},#}
handleSelected(command, category = '', delete_files = false, enable = 'True') {
let ids = []
if (this.selected_rows.length <= 0) {
this.$message({
type: 'warning',
message: '未选中任何种子!!'
})
return
}
this.selected_rows.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.plTable.clearSelection()
}).catch(res => {
this.$message({
type: 'warning',
message: '指令发送失败!!'
})
})
},
get_downloader() {
axios.get(
"{% url "get_downloader" %}"
).then(res => {
this.loading = true
console.log('获取下载器列表成功', res.data)
if (res.data.code === 0) {
this.downloaders = res.data.data
console.log(this.torrents)
this.downloader_id = this.downloaders[0].id
this.get_downloading(this.downloader_id)
{#console.log(this.torrents.length)#}
this.loading = false
} else {
this.loading = false
this.$message({
type: 'warning',
message: '获取下载器列表失败!'
});
}
}).catch(res => {
console.log('获取下载器列表失败', res)
this.$message({
type: 'warning',
message: '获取下载器列表失败!' + res
});
})
},
handleTabClick(tab, event) {
const loading = this.$loading({
lock: true,//lock的修改符--默认是false
text: 'Loading',//显示在加载图标下方的加载文案
spinner: 'el-icon-loading',//自定义加载图标类名
background: 'rgba(0, 0, 0, 0.7)',//遮罩层颜色
target: document.querySelector('#table')//loadin覆盖的dom元素节点
});
{#console.log(tab)#}
console.log(tab.$attrs.id)
this.loading = true
{#this.torrents = []#}
this.downloader_id = tab.$attrs.id
this.torrents = []
this.get_downloading(this.downloader_id)
loading.close()
},
get_downloading(downloader_id) {
clearInterval(this.timer)
this.timer = null
axios.get(
"{% url "downloading" %}",
{
params: {
id: downloader_id
}
}
).then(res => {
{#console.log(res.data.data.torrents)#}
if (res.data.code === 0) {
{#// 获取分类列表#}
{#let categories = res.data.data.categories#}
// 任务状态过滤器数据
this.categoryFilters = [{label: '未分类', value: ''}]
this.categories = []
for (let x in res.data.data.categories) {
{#console.log(download_state[x])#}
this.categoryFilters.push({
'label': x,
'value': x
})
this.categories.push({
'title': x,
'value': x
})
}
// 异步加载筛选数据
const $table = this.$refs['table' + this.downloader_id][0]
console.log($table)
if ($table) {
const nameColumn = $table.getColumnByField('category')
if (nameColumn) {
$table.setFilter(nameColumn, this.categoryFilters)
}
}
{#console.log(this.categoryFilters)#}
this.server_state = res.data.data.server_state
// 获取种子
this.torrents = res.data.data.torrents
//this.$message({
// type: 'success',
// message: '任务加载成功!!'
//})
} else {
{#console.log(res.data.data)#}
this.$message({
type: 'warning',
message: '任务加载出错!!'
})
}
})
this.timer = setInterval(() => {
this.get_downloading(downloader_id)
}, 1500)
},
// 执行格式化文件大小
handleSize(row, column, cellValue, index) {
return this.renderSize(cellValue)
},
handleSpeed(row, column, cellValue, index) {
return this.renderSize(cellValue) != 0 ? this.renderSize(cellValue) + '/S' : ''
},
// 执行格式化文件大小
handleState(row, column, cellValue, index) {
{#('state'))#}
return download_state[cellValue]
},
// 格式化文件大小
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)
},
// 双击任务事件
handleRow(row, column, event) {
console.log(row)
this.torrent = row
console.log(this.torrent)
this.dialogFormVisible = true
console.log(row.name)
console.log(column)
console.log(event)
},
// 阻止默认右键菜单弹出
rtClick(row, column, event) {
// 阻止默认右键菜单弹出
event.preventDefault()
},
{#handleRefresh(command) {#}
{# console.log(this.refresh)#}
{# this.refresh = true#}
{# this.interval = command * 1000#}
{# this.$message({#}
{# type: 'success',#}
{# message: '下载任务将每' + command + '秒刷新一次,如需暂停,请点击按钮!'#}
{# });#}
{# this.timer = setInterval(() => {#}
{# this.get_downloading(this.downloader_id)#}
{# }, this.interval)#}
{##}
//},
clearTimer() {
this.refresh = false
console.log(this.refresh)
this.$message({
type: 'warning',
message: '任务刷新已暂停!'
});
window.clearInterval(this.timer)
this.timer = null
},
filterStateMethod({value, row, column}) {
{#console.log(value,)#}
{#console.log(row)#}
{#console.log(column)#}
const property = column['property'];
return row[property] === value;
},
setCategoryFilter(fieldOrColumn, options) {
console.log(fieldOrColumn, options)
}
}
});
</script>
</body>
</html>