mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-18 02:40:44 +08:00
修复资源搜索结果在大样本下超时后重复追加,导致重复渲染与计数膨胀的问题
- 前端:引入搜索 “会话号 + validating” 双重校验,超时立即取消当前会话,并在批处理/渲染前校验,阻断超时后的继续写入;保留稳定 v-for key 确保渲染一致性 - 后端:`get_detail` 增强容错,避免无 `code`/网络异常引发 KeyError;`/get_share_detail` 统一错误返回结构,前端稳定处理
This commit is contained in:
parent
3ccaeeae15
commit
5216fa981d
@ -1200,6 +1200,10 @@ def get_share_detail():
|
||||
if not is_sharing:
|
||||
return jsonify({"success": False, "data": {"error": stoken}})
|
||||
share_detail = account.get_detail(pwd_id, stoken, pdir_fid, _fetch_share=1)
|
||||
# 统一错误返回,避免前端崩溃
|
||||
if isinstance(share_detail, dict) and share_detail.get("error"):
|
||||
return jsonify({"success": False, "data": {"error": share_detail.get("error")}})
|
||||
|
||||
share_detail["paths"] = paths
|
||||
share_detail["stoken"] = stoken
|
||||
|
||||
|
||||
@ -1032,7 +1032,7 @@
|
||||
<div class="dropdown-item text-muted" v-else style="font-size:14px; padding-left: 8px; text-align: left;">
|
||||
{{ smart_param.taskSuggestions.message ? smart_param.taskSuggestions.message : smart_param.taskSuggestions.data && smart_param.taskSuggestions.data.length ? `以下资源由 ${(smart_param.taskSuggestions.source || '').replace(/,\s*/g, '、')} 搜索提供(仅显示有效链接,共 ${(smart_param.taskSuggestions.data || []).length} 个),如有侵权请联系资源发布方` : "未搜索到有效资源" }}
|
||||
</div>
|
||||
<div v-for="suggestion in smart_param.taskSuggestions.data || []" :key="suggestion.taskname" class="dropdown-item cursor-pointer" @click.prevent="selectSuggestion(index, suggestion)" style="font-size: 14px;" :title="getSuggestionHoverTitle(suggestion)">
|
||||
<div v-for="suggestion in smart_param.taskSuggestions.data || []" :key="(suggestion.shareurl || '') + '_' + (suggestion.taskname || '') + '_' + (suggestion.publish_date || '')" class="dropdown-item cursor-pointer" @click.prevent="selectSuggestion(index, suggestion)" style="font-size: 14px;" :title="getSuggestionHoverTitle(suggestion)">
|
||||
<span v-html="suggestion.verify ? '✅': ''"></span> {{ suggestion.taskname }}
|
||||
<small class="text-muted">
|
||||
<a :href="suggestion.shareurl" target="_blank" @click.stop> · {{ suggestion.shareurl.replace(/^https?:\/\/pan\.quark\.cn\/s\//, '') }}</a>
|
||||
@ -1960,7 +1960,7 @@
|
||||
<div class="dropdown-item text-muted" v-else style="font-size:14px; padding-left: 8px; text-align: left;">
|
||||
{{ smart_param.taskSuggestions.message ? smart_param.taskSuggestions.message : smart_param.taskSuggestions.data && smart_param.taskSuggestions.data.length ? `以下资源由 ${(smart_param.taskSuggestions.source || '').replace(/,\s*/g, '、')} 搜索提供(仅显示有效链接,共 ${(smart_param.taskSuggestions.data || []).length} 个),如有侵权请联系资源发布方` : "未搜索到有效资源" }}
|
||||
</div>
|
||||
<div v-for="suggestion in smart_param.taskSuggestions.data || []" :key="suggestion.taskname" class="dropdown-item cursor-pointer" @click.prevent="selectSuggestion(-1, suggestion)" style="font-size: 14px;" :title="getSuggestionHoverTitle(suggestion)">
|
||||
<div v-for="suggestion in smart_param.taskSuggestions.data || []" :key="(suggestion.shareurl || '') + '_' + (suggestion.taskname || '') + '_' + (suggestion.publish_date || '')" class="dropdown-item cursor-pointer" @click.prevent="selectSuggestion(-1, suggestion)" style="font-size: 14px;" :title="getSuggestionHoverTitle(suggestion)">
|
||||
<span v-html="suggestion.verify ? '✅': ''"></span> {{ suggestion.taskname }}
|
||||
<small class="text-muted">
|
||||
<a :href="suggestion.shareurl" target="_blank" @click.stop> · {{ suggestion.shareurl.replace(/^https?:\/\/pan\.quark\.cn\/s\//, '') }}</a>
|
||||
@ -2251,6 +2251,8 @@
|
||||
valid: 0
|
||||
},
|
||||
searchTimer: null,
|
||||
// 新增:搜索会话号用于取消上一次验证/渲染,避免卡死和重复
|
||||
searchSessionId: 0
|
||||
},
|
||||
activeTab: 'config',
|
||||
configModified: false,
|
||||
@ -4274,6 +4276,8 @@
|
||||
// 确保显示下拉菜单
|
||||
this.smart_param.showSuggestions = true;
|
||||
try {
|
||||
// 启动新的搜索会话,后续增量结果仅在会话一致时才渲染
|
||||
const sessionId = ++this.smart_param.searchSessionId;
|
||||
axios.get('/task_suggestions', {
|
||||
params: {
|
||||
q: taskname,
|
||||
@ -4281,9 +4285,10 @@
|
||||
}
|
||||
}).then(response => {
|
||||
// 接收到数据后,过滤无效链接
|
||||
if (sessionId !== this.smart_param.searchSessionId) return; // 旧会话结果忽略
|
||||
if (response.data.success && response.data.data && response.data.data.length > 0) {
|
||||
// 使用新增的方法验证链接有效性
|
||||
this.validateSearchResults(response.data);
|
||||
this.validateSearchResults(response.data, sessionId);
|
||||
} else {
|
||||
this.smart_param.taskSuggestions = response.data;
|
||||
// 重新确认设置为true
|
||||
@ -4294,6 +4299,7 @@
|
||||
}).catch(error => {
|
||||
this.smart_param.isSearching = false;
|
||||
this.smart_param.validating = false; // 重置验证状态
|
||||
|
||||
});
|
||||
} catch (e) {
|
||||
this.smart_param.taskSuggestions = {
|
||||
@ -4301,10 +4307,11 @@
|
||||
};
|
||||
this.smart_param.isSearching = false;
|
||||
this.smart_param.validating = false; // 重置验证状态
|
||||
|
||||
}
|
||||
},
|
||||
// 添加新方法来验证搜索结果
|
||||
validateSearchResults(searchData) {
|
||||
validateSearchResults(searchData, sessionId) {
|
||||
const invalidTerms = [
|
||||
"分享者用户封禁链接查看受限",
|
||||
"好友已取消了分享",
|
||||
@ -4347,6 +4354,7 @@
|
||||
return new Promise((resolve) => {
|
||||
if (!link.shareurl) {
|
||||
// 没有分享链接,直接跳过
|
||||
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
@ -4358,6 +4366,10 @@
|
||||
.then(response => {
|
||||
// 更新进度
|
||||
this.smart_param.validateProgress.current++;
|
||||
if (sessionId !== this.smart_param.searchSessionId) {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.data.success) {
|
||||
// 检查文件列表是否为空
|
||||
@ -4365,6 +4377,7 @@
|
||||
if (shareDetail.list && shareDetail.list.length > 0) {
|
||||
// 链接有效,添加到有效结果列表
|
||||
this.smart_param.validateProgress.valid++;
|
||||
|
||||
resolve(link);
|
||||
return;
|
||||
}
|
||||
@ -4390,18 +4403,21 @@
|
||||
// 如果不是已知的失效原因,保留该结果
|
||||
if (!isInvalid) {
|
||||
this.smart_param.validateProgress.valid++;
|
||||
|
||||
resolve(link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 链接无效
|
||||
|
||||
resolve(null);
|
||||
})
|
||||
.catch(error => {
|
||||
// 验证出错,保守处理为有效
|
||||
this.smart_param.validateProgress.current++;
|
||||
this.smart_param.validateProgress.valid++;
|
||||
|
||||
resolve(link);
|
||||
});
|
||||
});
|
||||
@ -4409,6 +4425,8 @@
|
||||
|
||||
// 修改processBatch函数,增加快速显示功能
|
||||
const processBatch = async () => {
|
||||
// 新会话已开始或已被取消(validating=false)则停止当前批次
|
||||
if (sessionId !== this.smart_param.searchSessionId || !this.smart_param.validating) return;
|
||||
// 取下一批处理
|
||||
const batch = toProcess.splice(0, batchSize);
|
||||
if (batch.length === 0) {
|
||||
@ -4431,6 +4449,7 @@
|
||||
validResults.sort((a, b) => getItemTs(b) - getItemTs(a));
|
||||
|
||||
// 每批次都增量更新到界面,显示当前有效数量并保持正在验证状态
|
||||
if (sessionId !== this.smart_param.searchSessionId || !this.smart_param.validating) return; // 渲染前再次检查会话
|
||||
this.smart_param.taskSuggestions = {
|
||||
success: searchData.success,
|
||||
source: searchData.source,
|
||||
@ -4449,7 +4468,10 @@
|
||||
// 设置超时,避免永久等待
|
||||
setTimeout(() => {
|
||||
// 如果验证还在进行中,强制完成
|
||||
if (this.smart_param.validating) {
|
||||
if (this.smart_param.validating && sessionId === this.smart_param.searchSessionId) {
|
||||
// 在收尾前立即取消会话,避免后续批次继续追加导致重复
|
||||
this.smart_param.validating = false;
|
||||
this.smart_param.searchSessionId++;
|
||||
// 将剩余未验证的链接添加到结果中
|
||||
const remaining = toProcess.filter(item => item.shareurl);
|
||||
validResults.push(...remaining);
|
||||
@ -4460,6 +4482,7 @@
|
||||
|
||||
// 完成验证
|
||||
this.finishValidation(searchData, validResults);
|
||||
|
||||
}
|
||||
}, 30000); // 30秒超时
|
||||
},
|
||||
@ -4480,6 +4503,7 @@
|
||||
message: validResults.length === 0 ? "未找到有效的分享链接" : searchData.message
|
||||
};
|
||||
|
||||
|
||||
this.smart_param.taskSuggestions = result;
|
||||
this.smart_param.isSearching = false;
|
||||
this.smart_param.validating = false;
|
||||
|
||||
@ -1225,18 +1225,39 @@ class Quark:
|
||||
"_fetch_total": "1",
|
||||
"_sort": "file_type:asc,updated_at:desc",
|
||||
}
|
||||
response = self._send_request("GET", url, params=querystring).json()
|
||||
if response["code"] != 0:
|
||||
return {"error": response["message"]}
|
||||
if response["data"]["list"]:
|
||||
list_merge += response["data"]["list"]
|
||||
# 兼容网络错误或服务端异常
|
||||
try:
|
||||
response = self._send_request("GET", url, params=querystring).json()
|
||||
except Exception:
|
||||
return {"error": "request error"}
|
||||
|
||||
# 统一判错:某些情况下返回没有 code 字段
|
||||
code = response.get("code")
|
||||
status = response.get("status")
|
||||
if code not in (0, None):
|
||||
return {"error": response.get("message", "unknown error")}
|
||||
if status not in (None, 200):
|
||||
return {"error": response.get("message", "request error")}
|
||||
|
||||
data = response.get("data") or {}
|
||||
metadata = response.get("metadata") or {}
|
||||
|
||||
if data.get("list"):
|
||||
list_merge += data["list"]
|
||||
page += 1
|
||||
else:
|
||||
break
|
||||
if len(list_merge) >= response["metadata"]["_total"]:
|
||||
# 防御性:metadata 或 _total 缺失时不再访问嵌套键
|
||||
total = metadata.get("_total") if isinstance(metadata, dict) else None
|
||||
if isinstance(total, int) and len(list_merge) >= total:
|
||||
break
|
||||
response["data"]["list"] = list_merge
|
||||
return response["data"]
|
||||
# 统一输出结构,缺失字段时提供默认值
|
||||
if not isinstance(data, dict):
|
||||
return {"error": response.get("message", "request error")}
|
||||
data["list"] = list_merge
|
||||
if "paths" not in data:
|
||||
data["paths"] = []
|
||||
return data
|
||||
|
||||
def get_fids(self, file_paths):
|
||||
fids = []
|
||||
|
||||
Loading…
Reference in New Issue
Block a user