feat: Study 页面应用场景链接标题抓取

- 替换 fetchTitles 导入为 getUrlTitle
- 新增 appUrlTitles 响应式映射缓存
- loadTaskApplications 中并行抓取应用场景 URL 标题
- 模板中应用场景链接显示抓取到的标题
- 移除旧的 loadUrlTitles 调用逻辑
This commit is contained in:
developer
2026-07-12 13:47:22 +08:00
parent a67d092805
commit 39bf6b7426
+13 -4
View File
@@ -5,6 +5,7 @@ import router from "@/router";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { getReviewTaskStatsByTask } from "@/api/review"; import { getReviewTaskStatsByTask } from "@/api/review";
import { getActiveSession } from "@/api/studySessions"; import { getActiveSession } from "@/api/studySessions";
import { import {
getPriorityWeights, getPriorityWeights,
getTaskApplications, getTaskApplications,
@@ -13,7 +14,7 @@ import {
type PriorityWeights, type PriorityWeights,
type TaskApplication, type TaskApplication,
} from "@/api/tasks"; } from "@/api/tasks";
import { fetchTitles } from "@/utils/fetchTitle"; import { getUrlTitle } from "@/utils/fetchTitle";
interface TaskItem { interface TaskItem {
title: string; title: string;
@@ -39,6 +40,7 @@ const selectedTaskId = ref<number | null>(null);
const loading = ref(false); const loading = ref(false);
const taskApplications = ref<TaskApplication[]>([]); const taskApplications = ref<TaskApplication[]>([]);
const applicationsLoading = ref(false); const applicationsLoading = ref(false);
const appUrlTitles = ref<Record<number, string>>({});
const applicationStatusOptions: { label: string; value: TaskApplication["status"] }[] = [ const applicationStatusOptions: { label: string; value: TaskApplication["status"] }[] = [
{ label: "待应用", value: "TODO" }, { label: "待应用", value: "TODO" },
@@ -97,6 +99,15 @@ async function loadTaskApplications(taskNum: string) {
try { try {
const res = await getTaskApplications(taskNum); const res = await getTaskApplications(taskNum);
taskApplications.value = res?.data || []; taskApplications.value = res?.data || [];
const map: Record<number, string> = {};
await Promise.all(
taskApplications.value
.filter((a) => a.resourceUrl)
.map(async (a) => {
map[a.id] = await getUrlTitle(a.resourceUrl!);
})
);
appUrlTitles.value = map;
} catch (error: any) { } catch (error: any) {
taskApplications.value = []; taskApplications.value = [];
ElMessage.error(error?.message || "应用场景加载失败"); ElMessage.error(error?.message || "应用场景加载失败");
@@ -168,10 +179,8 @@ watch(selectedTaskId, (newId) => {
if (task) { if (task) {
loadTaskStats(task.taskNum); loadTaskStats(task.taskNum);
loadTaskApplications(task.taskNum); loadTaskApplications(task.taskNum);
loadUrlTitles();
} else { } else {
taskApplications.value = []; taskApplications.value = [];
urlTitles.value = [];
} }
}); });
@@ -409,7 +418,7 @@ onMounted(() => {
</div> </div>
<p v-if="item.description">{{ item.description }}</p> <p v-if="item.description">{{ item.description }}</p>
<el-link v-if="item.resourceUrl" :href="item.resourceUrl" target="_blank" type="primary"> <el-link v-if="item.resourceUrl" :href="item.resourceUrl" target="_blank" type="primary">
{{ item.resourceUrl }} {{ appUrlTitles[item.id] || item.resourceUrl }}
</el-link> </el-link>
</div> </div>
</div> </div>