Compare commits

...

6 Commits

Author SHA1 Message Date
Cp0204
21ee9dab48 🔧 添加 taskname 替换逻辑
Some checks are pending
Docker Publish / build-and-push (push) Waiting to run
2024-12-12 18:18:33 +08:00
Cp0204
5d355acfff ️ 优化任务建议显示逻辑 2024-12-12 18:12:06 +08:00
Cp0204
7a04bf9f48 🎨 任务建议改为显示在上方 2024-12-12 17:42:42 +08:00
Cp0204
53bc670b3d 🐛 修复一些交互问题 2024-12-12 17:27:57 +08:00
Cp0204
f1db510957 添加任务建议
- 新增 `/task_suggestions` 路由,用于获取任务建议
- 添加任务建议的下拉菜单和搜索按钮
- 实现前端逻辑,支持根据任务名称搜索建议并显示结果
2024-12-12 16:43:10 +08:00
Cp0204
2687de5428 保存路径和任务名称智能关联填写 2024-12-12 15:18:30 +08:00
2 changed files with 114 additions and 13 deletions

View File

@ -15,8 +15,10 @@ from flask import (
from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
import subprocess import subprocess
import requests
import hashlib import hashlib
import logging import logging
import base64
import json import json
import sys import sys
import os import os
@ -139,7 +141,9 @@ def logout():
def index(): def index():
if not is_login(): if not is_login():
return redirect(url_for("login")) return redirect(url_for("login"))
return render_template("index.html", version=app.config["APP_VERSION"], plugin_flags=PLUGIN_FLAGS) return render_template(
"index.html", version=app.config["APP_VERSION"], plugin_flags=PLUGIN_FLAGS
)
# 获取配置数据 # 获取配置数据
@ -212,6 +216,21 @@ def run_script_now():
) )
@app.route("/task_suggestions")
def get_task_suggestions():
if not is_login():
return jsonify({"error": "未登录"})
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
query = request.args.get("q", "").lower()
deep = request.args.get("d", "").lower()
url = f"{base_url}/task_suggestions?q={query}&d={deep}"
try:
response = requests.get(url)
return jsonify(response.json())
except Exception as e:
return jsonify({"error": str(e)})
@app.route("/get_share_detail") @app.route("/get_share_detail")
def get_share_files(): def get_share_files():
if not is_login(): if not is_login():

View File

@ -176,10 +176,23 @@
<label class="col-sm-2 col-form-label">任务名称</label> <label class="col-sm-2 col-form-label">任务名称</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <div class="input-group">
<input type="text" name="taskname[]" class="form-control" v-model="task.taskname" placeholder="必填"> <input type="text" name="taskname[]" class="form-control" v-model="task.taskname" placeholder="必填" @focus="smart_param.showSuggestions=true;focusTaskname(index, task)" @input="changeTaskname(index, task)">
<div class="input-group-append" v-if="task.taskname"> <div class="dropdown-menu show" v-if="smart_param.showSuggestions && smart_param.taskSuggestions.length && smart_param.index === index" style="width: 100%; max-height: 500px; overflow-y: auto; transform: translate(0, -100%); top: 0; margin-top: -5px;">
<div class="text-muted text-center" style="font-size: small;">以下资源来自第三方,网络公开搜集,请自行辨识,如有侵权请联系夸克官方</div>
<div v-for="suggestion in smart_param.taskSuggestions" :key="suggestion.taskname" class="dropdown-item" @click.prevent="selectSuggestion(task, suggestion)" style="cursor: pointer;">
<span v-html="suggestion.verify ? '✅': '❔'"></span> {{ suggestion.taskname }}
<small class="text-muted">
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
</small>
</div>
</div>
<div class="input-group-append">
<button class="btn btn-primary" type="button" @click="searchSuggestions(index, task.taskname)">
<i v-if="smart_param.isSearching && smart_param.index === index" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></i>
<i v-else class="bi bi-search-heart"></i>
</button>
<div class="input-group-text"> <div class="input-group-text">
<a target="_blank" :href="`https://www.google.com/search?q=%22pan.quark%22+${task.taskname}`"><i class="bi bi-search"></i></a> <a target="_blank" :href="`https://www.google.com/search?q=%22pan.quark.cn/s%22+${task.taskname}`"><i class="bi bi-google"></i></a>
</div> </div>
</div> </div>
</div> </div>
@ -202,8 +215,10 @@
<label class="col-sm-2 col-form-label">保存路径</label> <label class="col-sm-2 col-form-label">保存路径</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <div class="input-group">
<input type="text" name="savepath[]" class="form-control" v-model="task.savepath" placeholder="必填"> <input type="text" name="savepath[]" class="form-control" v-model="task.savepath" placeholder="必填" @focus="focusTaskname(index, task)">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-secondary" type="button" v-if="smart_param.savepath && smart_param.index == index && task.savepath != smart_param.origin_savepath" @click="task.savepath = smart_param.origin_savepath"><i class="
bi bi-reply"></i></button>
<button class="btn btn-outline-secondary dropdown-toggle" type="button" @click="getSavepathDirs(task.savepath)" data-toggle="dropdown" aria-expanded="false">选择</button> <button class="btn btn-outline-secondary dropdown-toggle" type="button" @click="getSavepathDirs(task.savepath)" data-toggle="dropdown" aria-expanded="false">选择</button>
<div class="dropdown-menu" style="max-height: 300px; overflow-y: auto;"> <div class="dropdown-menu" style="max-height: 300px; overflow-y: auto;">
<a class="dropdown-item" @click.stop.prevent="selectSavepath(index,getParentDirectory(task.savepath),'..')" href="#">..</a> <a class="dropdown-item" @click.stop.prevent="selectSavepath(index,getParentDirectory(task.savepath),'..')" href="#">..</a>
@ -391,7 +406,7 @@
newTask: { newTask: {
taskname: "", taskname: "",
shareurl: "", shareurl: "",
savepath: "", savepath: "/",
pattern: "", pattern: "",
replace: "", replace: "",
enddate: "", enddate: "",
@ -406,7 +421,16 @@
savepaths: [], savepaths: [],
modalLoading: false, modalLoading: false,
shareFiles: [], shareFiles: [],
forceTaskIndex: null forceTaskIndex: null,
smart_param: {
index: null,
savepath: "",
origin_savepath: "",
taskSuggestions: [],
showSuggestions: false,
lastSuggestionsTime: 0,
isSearching: false,
},
}, },
filters: { filters: {
ts2date: function (value) { ts2date: function (value) {
@ -429,6 +453,11 @@
this.checkNewVersion(); this.checkNewVersion();
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
document.addEventListener('keydown', this.handleKeyDown); document.addEventListener('keydown', this.handleKeyDown);
document.addEventListener('click', (e) => {
if (!e.target.closest('.input-group')) {
this.smart_param.showSuggestions = false;
}
});
}, },
methods: { methods: {
checkNewVersion() { checkNewVersion() {
@ -511,11 +540,16 @@
addTask() { addTask() {
newTask = { ...this.newTask } newTask = { ...this.newTask }
newTask.taskname = this.taskNameFilter newTask.taskname = this.taskNameFilter
lastTask = this.formData.tasklist[this.formData.tasklist.length - 1] if (this.formData.tasklist.length > 0) {
if (this.formData.tasklist.length > 0 && lastTask.taskname) { lastTask = this.formData.tasklist[this.formData.tasklist.length - 1]
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, 'TASKNAME') if (this.taskDirSelected) {
} else { newTask.savepath = this.taskDirSelected + '/TASKNAME'
newTask.savepath = this.taskDirSelected + "/" + newTask.taskname } else {
newTask.savepath = lastTask.savepath.replace(lastTask.taskname, 'TASKNAME')
if(newTask.taskname){
newTask.savepath = newTask.savepath.replace('TASKNAME', newTask.taskname)
}
}
} }
this.formData.tasklist.push(newTask); this.formData.tasklist.push(newTask);
// 滚到最下 // 滚到最下
@ -525,6 +559,23 @@
}); });
}, 1); }, 1);
}, },
focusTaskname(index, task) {
this.smart_param.index = index
this.smart_param.origin_savepath = task.savepath
regex = new RegExp(`/${task.taskname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(/|$)`)
if (task.savepath.includes('TASKNAME')) {
this.smart_param.savepath = task.savepath;
} else if (task.savepath.match(regex)) {
this.smart_param.savepath = task.savepath.replace(task.taskname, 'TASKNAME');
} else {
this.smart_param.savepath = undefined;
}
},
changeTaskname(index, task) {
this.searchSuggestions(index, task.taskname, 500);
if (this.smart_param.savepath)
task.savepath = this.smart_param.savepath.replace('TASKNAME', task.taskname);
},
removeTask(index) { removeTask(index) {
if (confirm("确认删除任务 [#" + (index + 1) + ": " + this.formData.tasklist[index].taskname + "] 吗?")) if (confirm("确认删除任务 [#" + (index + 1) + ": " + this.formData.tasklist[index].taskname + "] 吗?"))
this.formData.tasklist.splice(index, 1); this.formData.tasklist.splice(index, 1);
@ -665,7 +716,38 @@
} else { } else {
task.runweek = [1, 2, 3, 4, 5, 6, 7]; task.runweek = [1, 2, 3, 4, 5, 6, 7];
} }
} },
searchSuggestions(index, taskname, limit_msec = 0) {
if (taskname.length == 0)
return
if (limit_msec > 0) {
const now = Date.now();
if (now - this.smart_param.lastSuggestionsTime < limit_msec)
return;
this.smart_param.lastSuggestionsTime = now;
}
this.smart_param.isSearching = true
this.smart_param.index = index;
axios.get('/task_suggestions', {
params: {
q: taskname,
d: limit_msec == 0 ? 1 : 0
}
}).then(response => {
this.smart_param.taskSuggestions = response.data;
this.smart_param.showSuggestions = true;
}).catch(error => {
console.error('Error fetching suggestions:', error);
}).finally(() => {
this.smart_param.isSearching = false;
});
},
selectSuggestion(task, suggestion) {
task.taskname = suggestion.taskname;
task.shareurl = suggestion.shareurl;
this.changeShareurl(task);
this.smart_param.showSuggestions = false;
},
} }
}); });
</script> </script>