fix: 提交列表和删除提交的慢查询,素材上传、登出和几处前端加载问题
性能(6 万条提交、18 万条消息的测试库上测的) - 提交列表 join task_task 时用 +s.task_id,不再从任务表出发经 task_id 单列索引回表读 html/css/js 大行,改走 slim 覆盖索引:翻页 260-700ms → 4-18ms - 删除提交时先查出 id 再按等值删关联行:prompt_message.submission_id 几乎全是 NULL, 写成 IN (子查询) 时统计信息会让 SQLite 扫整张表 bug - 提交列表排序加 rowid 作次级键,同分的提交翻页不再重复或遗漏 - 素材文件名只允许字母数字和 - _ .(否则 422),覆盖同名文件改成写临时文件再 rename; 前端删除时对名字做 URL 编码 - 刷新 token 只是网络失败时不再强制登出;退出请求失败时界面也显示为已退出 - 历史面板加载中收到的刷新不再丢掉;成绩册只用最后一次请求的结果,打开时不再加载两次 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
40f3063b91
commit
03878f6cc2
8 files changed
+124
-41
No files matched your search
+13
-3
@@ -60,6 +60,8 @@ http.interceptors.response.use(
|
||||
) {
|
||||
err.config._retried = true
|
||||
if (await refreshAccessToken()) return http(err.config)
|
||||
// 刷新失败但 refresh token 还在,说明只是网络问题:保留登录,下次请求再试
|
||||
if (hasLogin()) return Promise.reject(err)
|
||||
}
|
||||
switch (err.response.status) {
|
||||
case 401: // 未授权
|
||||
@@ -277,7 +279,7 @@ export const Submission = {
|
||||
username?: string
|
||||
user_id?: number
|
||||
flag?: string | null
|
||||
zone?: string
|
||||
zone?: string | null
|
||||
task_id?: number
|
||||
task_type?: string
|
||||
score_min?: number
|
||||
@@ -553,7 +555,11 @@ export const TaskAssets = {
|
||||
).data
|
||||
},
|
||||
async deleteChallenge(display: number, name: string) {
|
||||
return (await http.delete(`/assets/challenge/${display}/${name}`)).data
|
||||
return (
|
||||
await http.delete(
|
||||
`/assets/challenge/${display}/${encodeURIComponent(name)}`,
|
||||
)
|
||||
).data
|
||||
},
|
||||
async listTutorial(display: number): Promise<TaskAsset[]> {
|
||||
return (await http.get<TaskAsset[]>(`/assets/tutorial/${display}`)).data
|
||||
@@ -573,6 +579,10 @@ export const TaskAssets = {
|
||||
).data
|
||||
},
|
||||
async deleteTutorial(display: number, name: string) {
|
||||
return (await http.delete(`/assets/tutorial/${display}/${name}`)).data
|
||||
return (
|
||||
await http.delete(
|
||||
`/assets/tutorial/${display}/${encodeURIComponent(name)}`,
|
||||
)
|
||||
).data
|
||||
},
|
||||
}
|
||||
@@ -210,8 +210,15 @@ function selectItem(item: HistoryViewItem) {
|
||||
})
|
||||
}
|
||||
|
||||
// 加载中又要求刷新(比如自动提交了新代码、换了任务),等这次完成后再加载一次
|
||||
let reloadAfter = false
|
||||
|
||||
async function load(force = true) {
|
||||
if (!props.taskId || loading.value) return
|
||||
if (!props.taskId) return
|
||||
if (loading.value) {
|
||||
reloadAfter = true
|
||||
return
|
||||
}
|
||||
if (!force && loadedTaskId === props.taskId) return
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -230,6 +237,10 @@ async function load(force = true) {
|
||||
loadedTaskId = props.taskId
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (reloadAfter) {
|
||||
reloadAfter = false
|
||||
load(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,9 +107,13 @@ function handleLogin() {
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
await Account.logout()
|
||||
user.username = ""
|
||||
user.role = Role.Normal
|
||||
// token 已经先清掉了,退出请求失败(比如断网)界面也要显示为已退出
|
||||
try {
|
||||
await Account.logout()
|
||||
} finally {
|
||||
user.username = ""
|
||||
user.role = Role.Normal
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
@@ -317,20 +317,28 @@ async function loadClasses() {
|
||||
}
|
||||
}
|
||||
|
||||
// 快速切换班级时只用最后一次请求的结果
|
||||
let loadSeq = 0
|
||||
|
||||
async function loadGradebook() {
|
||||
const seq = ++loadSeq
|
||||
if (!query.classname) {
|
||||
gradebook.value = null
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ""
|
||||
try {
|
||||
gradebook.value = await Gradebook.get(query)
|
||||
classes.value = gradebook.value.classes
|
||||
const data = await Gradebook.get(query)
|
||||
if (seq !== loadSeq) return
|
||||
gradebook.value = data
|
||||
classes.value = data.classes
|
||||
} catch (err: any) {
|
||||
if (seq !== loadSeq) return
|
||||
loadError.value = err.response?.data?.detail ?? "成绩册加载失败"
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (seq === loadSeq) loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +366,10 @@ watchDebounced(
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
const before = query.classname
|
||||
await loadClasses()
|
||||
await loadGradebook()
|
||||
// loadClasses 选了默认班级时,上面的 watch 已经会加载
|
||||
if (query.classname === before) loadGradebook()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in new issue
Block a user