mirror of
https://github.com/CzBiX/qb-web.git
synced 2026-05-04 04:40:44 +08:00
Add state fileter
This commit is contained in:
@@ -75,7 +75,50 @@ import FilterGroup from './drawer/FilterGroup.vue';
|
||||
import { api } from '../Api';
|
||||
import { mapState, mapMutations, mapGetters } from 'vuex';
|
||||
import { formatSize } from '../filters';
|
||||
import { SiteMap } from '../consts';
|
||||
import { SiteMap, StateType, AllStateTypes } from '../consts';
|
||||
|
||||
const stateList = [
|
||||
{
|
||||
title: 'Downloading',
|
||||
state: StateType.Downloading,
|
||||
icon: 'download',
|
||||
},
|
||||
{
|
||||
title: 'Seeding',
|
||||
state: StateType.Seeding,
|
||||
icon: 'upload',
|
||||
},
|
||||
{
|
||||
title: 'Completed',
|
||||
state: StateType.Completed,
|
||||
icon: 'check',
|
||||
},
|
||||
{
|
||||
title: 'Resumed',
|
||||
state: StateType.Resumed,
|
||||
icon: 'play',
|
||||
},
|
||||
{
|
||||
title: 'Paused',
|
||||
state: StateType.Paused,
|
||||
icon: 'pause',
|
||||
},
|
||||
{
|
||||
title: 'Active',
|
||||
state: StateType.Active,
|
||||
icon: 'filter',
|
||||
},
|
||||
{
|
||||
title: 'Inactive',
|
||||
state: StateType.Inactive,
|
||||
icon: 'filter-outline',
|
||||
},
|
||||
{
|
||||
title: 'Errored',
|
||||
state: StateType.Errored,
|
||||
icon: 'alert',
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -89,23 +132,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
basicItems: null,
|
||||
// {
|
||||
// 'icon': 'mdi-menu-up',
|
||||
// 'icon-alt': 'mdi-menu-down',
|
||||
// 'text': 'Status',
|
||||
// 'model': true,
|
||||
// 'children': [
|
||||
// { icon: 'mdi-filter-remove', text: 'All' },
|
||||
// { icon: 'mdi-download', text: 'Downloading' },
|
||||
// { icon: 'mdi-upload', text: 'Seeding' },
|
||||
// { icon: 'mdi-check', text: 'Completed' },
|
||||
// { icon: 'mdi-play', text: 'Resumed' },
|
||||
// { icon: 'mdi-pause', text: 'Paused' },
|
||||
// { icon: 'mdi-filter', text: 'Active' },
|
||||
// { icon: 'mdi-filter-outline', text: 'Inactive' },
|
||||
// { icon: 'mdi-alert', text: 'Errored' },
|
||||
// ],
|
||||
// },
|
||||
endItems: null,
|
||||
};
|
||||
},
|
||||
@@ -126,19 +152,44 @@ export default {
|
||||
'allTorrents',
|
||||
'torrentGroupByCategory',
|
||||
'torrentGroupBySite',
|
||||
'torrentGroupByState',
|
||||
]),
|
||||
items() {
|
||||
if (!this.isDataReady) {
|
||||
return _.concat(this.basicItems, this.endItems);
|
||||
}
|
||||
|
||||
const filterGroups = [];
|
||||
const totalSize = formatSize(_.sumBy(this.allTorrents, 'size'));
|
||||
|
||||
const states = stateList.map((item) => {
|
||||
let value = this.torrentGroupByState[item.state];
|
||||
if (_.isUndefined(value)) {
|
||||
value = [];
|
||||
}
|
||||
const size = formatSize(_.sumBy(value, 'size'));
|
||||
const title = item.title + ` (${value.length})`;
|
||||
const append = `[${size}]`;
|
||||
return { icon: 'mdi-' + item.icon, title, key: item.state, append};
|
||||
});
|
||||
filterGroups.push({
|
||||
'icon': 'mdi-menu-up',
|
||||
'icon-alt': 'mdi-menu-down',
|
||||
'title': 'State',
|
||||
'model': true,
|
||||
'select': 'state',
|
||||
'children': [
|
||||
{ icon: 'mdi-filter-remove', title: `All (${this.allTorrents.length})`, key: null, append: `[${totalSize}]` },
|
||||
...states,
|
||||
],
|
||||
});
|
||||
|
||||
const categories: any[] = _.sortBy(Object.entries(this.torrentGroupByCategory).map(([key, value]) => {
|
||||
const size = formatSize(_.sumBy(value, 'size'));
|
||||
const title = key ? key : 'Uncategorized';
|
||||
const append = `(${value.length})[${size}]`;
|
||||
const title = (key ? key : 'Uncategorized') + ` (${value.length})`;
|
||||
const append = `[${size}]`;
|
||||
return { icon: 'mdi-folder-open', title, key, append};
|
||||
}), 'key');
|
||||
const totalSize = formatSize(_.sumBy(this.allTorrents, 'size'));
|
||||
filterGroups.push({
|
||||
'icon': 'mdi-menu-up',
|
||||
'icon-alt': 'mdi-menu-down',
|
||||
@@ -146,7 +197,6 @@ export default {
|
||||
'model': false,
|
||||
'select': 'category',
|
||||
'children': [
|
||||
{ icon: 'mdi-folder-open', title: 'All', key: null, append: `(${this.allTorrents.length})[${totalSize}]` },
|
||||
...categories,
|
||||
],
|
||||
});
|
||||
@@ -154,9 +204,9 @@ export default {
|
||||
const sites: any[] = _.sortBy(Object.entries(this.torrentGroupBySite).map(([key, value]) => {
|
||||
const size = formatSize(_.sumBy(value, 'size'));
|
||||
const site = (SiteMap as any)[key];
|
||||
const title = site ? site.name : 'Others';
|
||||
const title = (site ? site.name : 'Others') + ` (${value.length})`;
|
||||
const icon = _.defaultTo(site ? site.icon : null, 'mdi-server');
|
||||
const append = `(${value.length})[${size}]`;
|
||||
const append = `[${size}]`;
|
||||
return { icon, title, key, append };
|
||||
}), 'title');
|
||||
filterGroups.push({
|
||||
|
||||
@@ -13,20 +13,20 @@
|
||||
hide-details
|
||||
@click.stop="selectedRows = []"
|
||||
></v-checkbox>
|
||||
<v-btn icon @click="confirmDelete">
|
||||
<v-btn icon @click="confirmDelete" title="Delete">
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
<v-divider vertical inset />
|
||||
<v-btn icon @click="resumeTorrents">
|
||||
<v-btn icon @click="resumeTorrents" title="Resume">
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon @click="pauseTorrents">
|
||||
<v-btn icon @click="pauseTorrents" title="Pause">
|
||||
<v-icon>mdi-pause</v-icon>
|
||||
</v-btn>
|
||||
<v-divider vertical inset />
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn icon v-on="on">
|
||||
<v-btn icon v-on="on" title="Category">
|
||||
<v-icon>mdi-folder</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
@@ -157,6 +157,7 @@ export default Vue.extend({
|
||||
'allTorrents',
|
||||
'torrentGroupByCategory',
|
||||
'torrentGroupBySite',
|
||||
'torrentGroupByState',
|
||||
]),
|
||||
...mapState({
|
||||
filter(state, getters) {
|
||||
@@ -183,6 +184,9 @@ export default Vue.extend({
|
||||
if (this.filter.category !== null) {
|
||||
list = _.intersection(list, this.torrentGroupByCategory[this.filter.category]);
|
||||
}
|
||||
if (this.filter.state !== null) {
|
||||
list = _.intersection(list, this.torrentGroupByState[this.filter.state]);
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-list-group
|
||||
v-model="group.model"
|
||||
:prepend-icon="group.model ? group.icon : group['icon-alt']"
|
||||
v-model="model"
|
||||
:prepend-icon="model ? group.icon : group['icon-alt']"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<v-list-tile>
|
||||
@@ -51,6 +51,7 @@ export default Vue.extend({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
model: this.group.model,
|
||||
selected: null,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,30 +1,25 @@
|
||||
export const SiteMap = {
|
||||
'tp.m-team.cc': {
|
||||
name: 'M-Team',
|
||||
icon: 'https://tp.m-team.cc/favicon.ico',
|
||||
},
|
||||
'pt.keepfrds.com': {
|
||||
name: 'FRDS',
|
||||
icon: 'https://pt.keepfrds.com/static/favicon.ico',
|
||||
},
|
||||
'hdcmct.org': {
|
||||
name: 'CMCT',
|
||||
icon: 'https://hdcmct.org/favicon.ico',
|
||||
},
|
||||
'hdchina.org': {
|
||||
name: 'HDChina',
|
||||
icon: 'https://hdchina.org/favicon.ico',
|
||||
},
|
||||
'chdbits.co': {
|
||||
name: 'CHDBits',
|
||||
icon: 'https://chdbits.co/favicon.ico',
|
||||
},
|
||||
'hdhome.org': {
|
||||
name: 'HDHome',
|
||||
icon: 'https://hdhome.org/favicon.ico',
|
||||
},
|
||||
'u2.dmhy.org': {
|
||||
name: 'U2',
|
||||
icon: 'https://u2.dmhy.org/favicon.ico',
|
||||
},
|
||||
};
|
||||
import sites from './sites';
|
||||
|
||||
export const SiteMap = sites;
|
||||
|
||||
export const enum StateType {
|
||||
Downloading = 'downloading',
|
||||
Seeding = 'seeding',
|
||||
Completed = 'completed',
|
||||
Resumed = 'resumed',
|
||||
Paused = 'pasued',
|
||||
Active = 'active',
|
||||
Inactive = 'inactive',
|
||||
Errored = 'errored',
|
||||
}
|
||||
|
||||
export const AllStateTypes = [
|
||||
StateType.Downloading,
|
||||
StateType.Seeding,
|
||||
StateType.Completed,
|
||||
StateType.Resumed,
|
||||
StateType.Paused,
|
||||
StateType.Active,
|
||||
StateType.Inactive,
|
||||
StateType.Errored,
|
||||
];
|
||||
|
||||
30
src/sites.ts
Normal file
30
src/sites.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export default {
|
||||
'tp.m-team.cc': {
|
||||
name: 'M-Team',
|
||||
icon: 'https://tp.m-team.cc/favicon.ico',
|
||||
},
|
||||
'pt.keepfrds.com': {
|
||||
name: 'FRDS',
|
||||
icon: 'https://pt.keepfrds.com/static/favicon.ico',
|
||||
},
|
||||
'hdcmct.org': {
|
||||
name: 'CMCT',
|
||||
icon: 'https://hdcmct.org/favicon.ico',
|
||||
},
|
||||
'hdchina.org': {
|
||||
name: 'HDChina',
|
||||
icon: 'https://hdchina.org/favicon.ico',
|
||||
},
|
||||
'chdbits.co': {
|
||||
name: 'CHDBits',
|
||||
icon: 'https://chdbits.co/favicon.ico',
|
||||
},
|
||||
'hdhome.org': {
|
||||
name: 'HDHome',
|
||||
icon: 'https://hdhome.org/favicon.ico',
|
||||
},
|
||||
'u2.dmhy.org': {
|
||||
name: 'U2',
|
||||
icon: 'https://u2.dmhy.org/favicon.ico',
|
||||
},
|
||||
};
|
||||
25
src/store.ts
25
src/store.ts
@@ -1,6 +1,8 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import _ from 'lodash';
|
||||
import { AllStateTypes } from './consts';
|
||||
import { torrentIsState } from './utils';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
@@ -10,7 +12,7 @@ const defaultConfig = {
|
||||
rowsPerPage: 100,
|
||||
},
|
||||
filter: {
|
||||
type: null,
|
||||
state: null,
|
||||
category: null,
|
||||
site: null,
|
||||
},
|
||||
@@ -95,5 +97,26 @@ export default new Vuex.Store({
|
||||
return url.hostname;
|
||||
});
|
||||
},
|
||||
torrentGroupByState(__, getters) {
|
||||
const result: any = {};
|
||||
const put = (state: any, torrent: any) => {
|
||||
let list: any[] = result[state];
|
||||
if (!list) {
|
||||
list = [];
|
||||
result[state] = list;
|
||||
}
|
||||
list.push(torrent);
|
||||
};
|
||||
|
||||
for (const torrent of getters.allTorrents) {
|
||||
for (const type of AllStateTypes) {
|
||||
if (torrentIsState(type, torrent.state)) {
|
||||
put(type, torrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
44
src/utils.ts
Normal file
44
src/utils.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import _ from 'lodash';
|
||||
import { StateType } from './consts';
|
||||
|
||||
const dlState = ['downloading', 'metaDL', 'stalledDL', 'checkingDL', 'pausedDL', 'queuedDL', 'forceDL'];
|
||||
const upState = ['uploading', 'stalledUP', 'checkingUP', 'queuedUP', 'forceUP'];
|
||||
const completeState = ['uploading', 'stalledUP', 'checkingUP', 'pausedUP', 'queuedUP', 'forceUP'];
|
||||
const activeState = ['metaDL', 'downloading', 'forceDL', 'uploading', 'forcedUP', 'moving'];
|
||||
const errorState = ['error', 'missingFiles'];
|
||||
|
||||
export function torrentIsState(type: StateType, state: string) {
|
||||
let result;
|
||||
switch (type) {
|
||||
case StateType.Downloading: {
|
||||
result = dlState.includes(state);
|
||||
break;
|
||||
}
|
||||
case StateType.Seeding: {
|
||||
result = upState.includes(state);
|
||||
break;
|
||||
}
|
||||
case StateType.Completed: {
|
||||
result = completeState.includes(state);
|
||||
break;
|
||||
}
|
||||
case StateType.Resumed:
|
||||
case StateType.Paused: {
|
||||
const paused = state.startsWith('paused');
|
||||
result = type === StateType.Paused ? paused : !paused;
|
||||
break;
|
||||
}
|
||||
case StateType.Active:
|
||||
case StateType.Inactive: {
|
||||
const active = activeState.includes(state);
|
||||
result = type === StateType.Active ? active : !active;
|
||||
break;
|
||||
}
|
||||
case StateType.Errored: {
|
||||
result = errorState.includes(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user