diff --git a/src/components/TaskForm.vue b/src/components/TaskForm.vue index 21e04c9..25dc812 100644 --- a/src/components/TaskForm.vue +++ b/src/components/TaskForm.vue @@ -40,7 +40,11 @@ const applicationLoading = ref(false); const appUrlTitles = ref>({}); const applicationDialogVisible = ref(false); const applicationSaving = ref(false); +const deletingApplicationId = ref(null); const editingApplicationId = ref(null); +const pageLoading = ref(false); +const submitting = ref(false); +const previewLoading = ref(false); const applicationForm = ref<{ title: string; description: string; @@ -135,13 +139,19 @@ const editApplication = (item: TaskApplication) => { }; const removeApplication = async (item: TaskApplication) => { - await deleteTaskApplication(item.id); - ElMessage.success("应用场景已删除"); - if (editingApplicationId.value === item.id) { - resetApplicationForm(); - } - if (taskNum.value) { - await loadApplications(taskNum.value); + if (deletingApplicationId.value !== null) return; + deletingApplicationId.value = item.id; + try { + await deleteTaskApplication(item.id); + ElMessage.success("应用场景已删除"); + if (editingApplicationId.value === item.id) { + resetApplicationForm(); + } + if (taskNum.value) { + await loadApplications(taskNum.value); + } + } finally { + deletingApplicationId.value = null; } }; @@ -168,71 +178,80 @@ const convertMaterialUrls = async () => { materialUrl.value = result; }; -const createTask = () => { - convertMaterialUrls().then(() => { - request - .post("/tasks", { +const createTask = async () => { + if (submitting.value) return; + submitting.value = true; + try { + await convertMaterialUrls(); + const result = await request.post("/tasks", { taskName: taskName.value, taskDescription: taskDescription.value, materialUrl: materialUrl.value, ...priority.value, - }) - .then((result) => { - if (result.code === 200) { - ElMessage.success("创建任务成功"); - router.push({ name: "study" }); - } else { - ElMessage.error("任务创建失败:" + result.message); - } - }); - }); -}; - -const loadTask = () => { - if (taskId !== null) { - request.get(`/tasks/${taskId}`, {}).then((result) => { - if (result.code === 200) { - const data = result.data; - taskNum.value = data.taskNum || ""; - taskName.value = data.taskName; - taskDescription.value = data.taskDescription; - materialUrl.value = data.materialUrl || ""; - priority.value = { - urgency: data.urgency, - importance: data.importance, - contentDifficulty: data.contentDifficulty, - futureValue: data.futureValue, - subjectivePriority: data.subjectivePriority, - }; - if (taskNum.value) { - loadApplications(taskNum.value); - } - } else { - ElMessage.error(`任务加载失败:${result.message}`); - } }); + if (result.code === 200) { + ElMessage.success("创建任务成功"); + await router.push({ name: "study" }); + } else { + ElMessage.error("任务创建失败:" + result.message); + } + } finally { + submitting.value = false; } }; -const updateTask = () => { - convertMaterialUrls().then(() => { - request - .put("/tasks/" + taskId, { +const loadTask = async () => { + if (taskId === null) return; + pageLoading.value = true; + try { + const result = await request.get(`/tasks/${taskId}`, {}); + if (result.code === 200) { + const data = result.data; + taskNum.value = data.taskNum || ""; + taskName.value = data.taskName; + taskDescription.value = data.taskDescription; + materialUrl.value = data.materialUrl || ""; + priority.value = { + urgency: data.urgency, + importance: data.importance, + contentDifficulty: data.contentDifficulty, + futureValue: data.futureValue, + subjectivePriority: data.subjectivePriority, + }; + if (taskNum.value) { + loadApplications(taskNum.value); + } + } else { + ElMessage.error(`任务加载失败:${result.message}`); + } + } catch (error: any) { + ElMessage.error(error?.message || "任务加载失败,请重试"); + } finally { + pageLoading.value = false; + } +}; + +const updateTask = async () => { + if (submitting.value) return; + submitting.value = true; + try { + await convertMaterialUrls(); + const result = await request.put("/tasks/" + taskId, { id: taskId, taskName: taskName.value, taskDescription: taskDescription.value, materialUrl: materialUrl.value, ...priority.value, - }) - .then((result) => { - if (result.code === 200) { - ElMessage.success("更新任务成功"); - router.push({ name: "study" }); - } else { - ElMessage.error("任务更新失败:" + result.message); - } }); - }); + if (result.code === 200) { + ElMessage.success("更新任务成功"); + await router.push({ name: "study" }); + } else { + ElMessage.error("任务更新失败:" + result.message); + } + } finally { + submitting.value = false; + } }; const cancelTask = () => { @@ -240,13 +259,14 @@ const cancelTask = () => { router.push({ name: "study" }); }; -const submitTask = () => { +const submitTask = async () => { + if (submitting.value) return; switch (route.name) { case "add-task": - createTask(); + await createTask(); break; case "update-task": - updateTask(); + await updateTask(); break; default: ElMessage.error("该功能暂不可用,请刷新后重试"); @@ -275,18 +295,28 @@ const showPreview = ref(false); const materialPreview = ref(""); async function previewMaterial() { - showPreview.value = true; - const raw = materialUrl.value || ""; - if (!raw.trim()) { materialPreview.value = ""; return; } - const titles: Record = {}; - const bareUrls = new Set(); - raw.replace(/https?:\/\/[^\s)\u3001\uFF09\u300D\u300B<>]+/g, (url) => { - bareUrls.add(url.replace(/[.。,,;;!!??)】」』\]]+$/, "")); - return url; - }); - const results = await Promise.all([...bareUrls].map(async (u) => ({ u, t: await getUrlTitle(u) }))); - results.forEach(({ u, t }) => { titles[u] = t; }); - materialPreview.value = renderMarkdown(raw, titles); + if (previewLoading.value) return; + previewLoading.value = true; + try { + const raw = materialUrl.value || ""; + if (!raw.trim()) { + materialPreview.value = ""; + showPreview.value = true; + return; + } + const titles: Record = {}; + const bareUrls = new Set(); + raw.replace(/https?:\/\/[^\s)\u3001\uFF09\u300D\u300B<>]+/g, (url) => { + bareUrls.add(url.replace(/[.。,,;;!!??)】」』\]]+$/, "")); + return url; + }); + const results = await Promise.all([...bareUrls].map(async (u) => ({ u, t: await getUrlTitle(u) }))); + results.forEach(({ u, t }) => { titles[u] = t; }); + materialPreview.value = renderMarkdown(raw, titles); + showPreview.value = true; + } finally { + previewLoading.value = false; + } } defineExpose({ @@ -306,7 +336,7 @@ defineExpose({