为转存记录添加状态筛选功能

This commit is contained in:
x1ao4 2025-11-25 15:01:27 +08:00
parent 85da3ec023
commit 0c81dd48b7
3 changed files with 159 additions and 10 deletions

View File

@ -3626,6 +3626,18 @@ def get_history_records():
# 获取筛选参数
task_name_filter = request.args.get("task_name", "")
keyword_filter = request.args.get("keyword", "")
task_names_raw = request.args.get("task_names", "")
task_name_list = []
if task_names_raw:
try:
decoded_names = json.loads(task_names_raw)
if isinstance(decoded_names, list):
task_name_list = [
str(name).strip() for name in decoded_names
if isinstance(name, (str, bytes)) and str(name).strip()
]
except Exception:
task_name_list = []
# 是否只请求所有任务名称
get_all_task_names = request.args.get("get_all_task_names", "").lower() in ["true", "1", "yes"]
@ -3648,6 +3660,7 @@ def get_history_records():
order=order,
task_name_filter=task_name_filter,
keyword_filter=keyword_filter,
task_name_list=task_name_list,
exclude_task_names=["rename", "undo_rename"]
)
# 添加所有任务名称到结果中
@ -3669,6 +3682,7 @@ def get_history_records():
order=order,
task_name_filter=task_name_filter,
keyword_filter=keyword_filter,
task_name_list=task_name_list,
exclude_task_names=["rename", "undo_rename"]
)

View File

@ -167,7 +167,8 @@ class RecordDB:
@retry_on_locked(max_retries=3, base_delay=0.1)
def get_records(self, page=1, page_size=20, sort_by="transfer_time", order="desc",
task_name_filter="", keyword_filter="", exclude_task_names=None):
task_name_filter="", keyword_filter="", exclude_task_names=None,
task_name_list=None):
"""获取转存记录列表,支持分页、排序和筛选
Args:
@ -178,6 +179,7 @@ class RecordDB:
task_name_filter: 任务名称筛选条件精确匹配
keyword_filter: 关键字筛选条件模糊匹配任务名转存为名称
exclude_task_names: 需要排除的任务名称列表
task_name_list: 任务名称集合包含多个任务名时使用IN筛选
"""
cursor = self.conn.cursor()
offset = (page - 1) * page_size
@ -208,6 +210,11 @@ class RecordDB:
where_clauses.append("task_name NOT IN ({})".format(",".join(["?" for _ in exclude_task_names])))
params.extend(exclude_task_names)
if task_name_list:
placeholders = ",".join(["?" for _ in task_name_list])
where_clauses.append(f"task_name IN ({placeholders})")
params.extend(task_name_list)
where_clause = " AND ".join(where_clauses)
where_sql = f"WHERE {where_clause}" if where_clause else ""

View File

@ -967,7 +967,7 @@
<div v-if="activeTab === 'tasklist'">
<div style="height: 20px;"></div>
<div class="row tasklist-filter-row" style="margin-bottom: 8px;">
<div class="row tasklist-filter-row" style="margin-bottom: 20px;">
<div class="col-xl-4 col-lg-4 col-md-6 mb-2 mb-lg-0">
<div class="input-group">
<div class="input-group-prepend">
@ -1425,8 +1425,8 @@
<div v-if="activeTab === 'history'">
<div style="height: 20px;"></div>
<div class="row" style="margin-bottom: 20px;">
<div class="col-lg-6 col-md-6 mb-2 mb-md-0">
<div class="row tasklist-filter-row" style="margin-bottom: 20px;">
<div class="col-xl-4 col-lg-4 col-md-6 mb-2 mb-lg-0">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">名称筛选</span>
@ -1437,23 +1437,47 @@
</div>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="col-xl-4 col-lg-4 col-md-6 mb-2 mb-lg-0">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">任务筛选</span>
</div>
<div class="position-relative" style="flex: 1;">
<select class="form-control task-filter-select" v-model="historyTaskSelected" style="padding-left: 8px !important; text-indent: 0 !important; display: flex !important; align-items: center !important; line-height: 1.5 !important; padding-right: 24px !important;">
<select class="form-control task-filter-select" v-model="historyTaskSelected" style="padding-left: 8px !important; text-indent: 0 !important; display: flex !important; align-items: center !important; line-height: 1.5 !important; padding-right: 8px !important;">
<option value="">全部</option>
<option v-for="task in historyTasks" :value="task" v-html="task"></option>
</select>
<!-- <i class="bi bi-chevron-down select-arrow" style="position: absolute; pointer-events: none; color: var(--dark-text-color);"></i> -->
</div>
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary filter-btn-square" @click="clearData('historyTaskSelected')"><i class="bi bi-x-lg"></i></button>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-4 col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">状态筛选</span>
</div>
<div class="position-relative" style="flex: 1;">
<select class="form-control task-filter-select"
v-model="historyStatusFilter"
style="padding-left: 8px !important; text-indent: 0 !important; display: flex !important; align-items: center !important; line-height: 1.5 !important; padding-right: 8px !important;">
<option value="">全部</option>
<option value="incomplete">未完成</option>
<option value="ongoing">进行中</option>
<option value="completed">已完成</option>
<option value="airing">播出中</option>
<option value="finale">本季终</option>
<option value="ended">已完结</option>
<option value="unmatched">未匹配</option>
<option value="ended_task">已结束</option>
</select>
</div>
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary filter-btn-square" @click="clearData('historyStatusFilter')"><i class="bi bi-x-lg"></i></button>
</div>
</div>
</div>
</div>
<div class="table-responsive">
@ -3120,6 +3144,13 @@
},
historyNameFilter: "",
historyTaskSelected: "",
historyStatusFilter: (() => {
try {
return localStorage.getItem('history_status_filter') || '';
} catch (e) {
return '';
}
})(),
gotoPage: 1,
totalPages: 1,
displayedPages: [],
@ -3127,6 +3158,9 @@
toastMessage: "",
selectedRecords: [],
lastSelectedRecordIndex: -1, // 记录最后选择的记录索引用于Shift选择
_lastTaskFilter: "",
_lastNameFilter: "",
_lastStatusFilter: "",
fileManager: {
hasLoaded: false, // 标记是否已完成首次加载
// 当前文件夹ID - 根据localStorage和账号索引决定初始目录
@ -3566,7 +3600,6 @@
filteredHistoryRecords() {
// 直接返回服务器端已筛选的数据
if (!this.history.records || this.history.records.length === 0) {
return [];
}
@ -3735,6 +3768,14 @@
this.loadHistoryRecords();
}
},
historyStatusFilter: {
handler(newVal) {
try {
localStorage.setItem('history_status_filter', newVal || '');
} catch (e) {}
this.loadHistoryRecords();
}
},
activeTab(newValue, oldValue) {
// 如果切换到任务列表页面,则刷新任务最新信息和元数据
if (newValue === 'tasklist') {
@ -9221,10 +9262,16 @@
params.keyword = this.historyNameFilter;
}
// 追加状态筛选
if (!this.prepareStatusFilterParams(params, true)) {
return;
}
// 判断筛选条件是否变化,只有变化时才重置页码
const isFilterChanged =
(this._lastTaskFilter !== this.historyTaskSelected) ||
(this._lastNameFilter !== this.historyNameFilter);
(this._lastNameFilter !== this.historyNameFilter) ||
(this._lastStatusFilter !== this.historyStatusFilter);
if (isFilterChanged) {
// 筛选条件变化时重置为第一页
@ -9235,6 +9282,7 @@
// 记录当前筛选条件
this._lastTaskFilter = this.historyTaskSelected;
this._lastNameFilter = this.historyNameFilter;
this._lastStatusFilter = this.historyStatusFilter;
// 更新当前参数
this.historyParams = {
@ -9263,6 +9311,74 @@
this.history.hasLoaded = true;
});
},
prepareStatusFilterParams(params, handleEmptyResult = false) {
if (!this.historyStatusFilter) {
return true;
}
const taskNames = this.getStatusFilteredTaskNames(this.historyStatusFilter);
if (!taskNames || taskNames.length === 0) {
if (handleEmptyResult) {
this.handleEmptyHistoryResult(params.page_size);
}
return false;
}
params.task_names = JSON.stringify(taskNames);
return true;
},
getStatusFilteredTaskNames(filterValue) {
if (!filterValue) {
return [];
}
if (filterValue === 'ended_task') {
const allTaskNames = (this.allTaskNames && this.allTaskNames.length > 0)
? this.allTaskNames
: this.extractTaskNamesFromHistory();
if (!this.allTaskNames || this.allTaskNames.length === 0) {
this.loadAllTaskNames();
}
const currentNames = new Set();
(this.formData.tasklist || []).forEach(task => {
if (task && task.taskname) {
currentNames.add(task.taskname);
}
});
return allTaskNames.filter(name => name && !currentNames.has(name));
}
const matchedNames = new Set();
(this.formData.tasklist || []).forEach(task => {
if (!task || !task.taskname) {
return;
}
if (this.filterTaskByStatus(task, filterValue)) {
matchedNames.add(task.taskname);
}
});
return Array.from(matchedNames);
},
extractTaskNamesFromHistory() {
const names = new Set();
(this.history.records || []).forEach(record => {
if (record && record.task_name) {
names.add(record.task_name);
}
});
return Array.from(names);
},
handleEmptyHistoryResult(pageSize) {
const resolvedPageSize = pageSize || parseInt(this.historyParams.page_size || 15);
this.history.records = [];
this.history.pagination = {
total_records: 0,
total_pages: 1,
current_page: 1,
page_size: resolvedPageSize
};
this.history.hasLoaded = true;
this.totalPages = 1;
this.historyParams.page = 1;
this.gotoPage = 1;
this.selectedRecords = [];
},
sortHistory(field) {
// 更新排序参数
@ -9291,6 +9407,10 @@
params.keyword = this.historyNameFilter;
}
if (!this.prepareStatusFilterParams(params, true)) {
return;
}
// 重新加载数据,使用当前页和当前设置的排序方式
axios.get('/history_records', { params })
.then(response => {
@ -9333,6 +9453,10 @@
params.keyword = this.historyNameFilter;
}
if (!this.prepareStatusFilterParams(params, true)) {
return;
}
axios.get('/history_records', { params })
.then(response => {
if (response.data.success) {
@ -9372,6 +9496,10 @@
params.keyword = this.historyNameFilter;
}
if (!this.prepareStatusFilterParams(params, true)) {
return;
}
// 重新加载数据
axios.get('/history_records', { params })
.then(response => {
@ -9399,8 +9527,8 @@
},
getVisiblePageNumbers() {
const current = parseInt(this.historyParams.page) || 1;
const total = parseInt(this.totalPages) || 1;
const current = parseInt(this.historyParams.page) || 1;
// 根据屏幕宽度动态调整显示的页码数:移动端显示较少页码,桌面端显示较多页码
const isMobile = window.innerWidth <= 768;
const delta = isMobile ? 1 : 2; // 移动端左右各显示1个页码桌面端左右各显示2个页码