feat(学习材料):多 URL 支持 + 网页标题自动抓取
TaskForm.vue: - 学习材料输入从单行改为 textarea,每行一个链接 Study.vue: - 改为迭代多 URL 展示,每行显示网页标题(通过 lpt-ai /fetch-title 获取)或回退到 URL 本身 - 选中不同任务时自动刷新标题 新增 src/utils/fetchTitle.ts: - fetchTitle(url) / fetchTitles(urls) 工具函数 - 内存缓存避免重复请求 - 失败时回退到 URL,不阻塞页面 后端: - V20260704_1 迁移:material_url varchar(255) → TEXT
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 网页标题抓取工具。
|
||||
* 调用 lpt-ai 的 /fetch-title 接口获取 URL 对应的 <title> 标签内容。
|
||||
*
|
||||
* 设计要点:
|
||||
* - 内存缓存避免同页面重复请求
|
||||
* - 失败时回退到 URL 本身
|
||||
* - 仅在 lpt-ai 运行时可用
|
||||
*/
|
||||
|
||||
const LPT_AI_URL = "http://localhost:5199";
|
||||
|
||||
const titleCache: Record<string, string> = {};
|
||||
|
||||
export async function fetchTitle(url: string): Promise<string> {
|
||||
if (titleCache[url]) return titleCache[url];
|
||||
try {
|
||||
const res = await fetch(`${LPT_AI_URL}/fetch-title`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ url }),
|
||||
signal: AbortSignal.timeout(12_000),
|
||||
});
|
||||
if (!res.ok) return url;
|
||||
const data = await res.json();
|
||||
titleCache[url] = data.title || url;
|
||||
return titleCache[url];
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/** 批量获取标题 */
|
||||
export async function fetchTitles(urls: string[]): Promise<string[]> {
|
||||
return Promise.all(urls.map((url) => fetchTitle(url)));
|
||||
}
|
||||
Reference in New Issue
Block a user