feat(settings,questions,school,textbooks): add brand config, question components, school dialogs, textbooks hooks
settings: - Add actions-brand, brand-config, data-access-brand for brand management - Add admin-file-upload-card, admin-notification-config-card, admin-school-info-card, admin-security-policy-card - Add ai-provider-delete-dialog, ai-provider-selector, brand-config-card - Add security-recent-logins-section, security-two-factor-section - Add config/profile-overview-config, data-access-profile-overview, lib/system-settings-utils questions: - Add batch-operations, import-export-buttons, knowledge-point-selector, options-editor - Add question-bank-results-client, question-cascade-filter, question-content-renderer, utils school: - Add grade-delete-dialog, grade-form-dialog, grade-list-toolbar, grade-overview-cards - Add use-grade-data hook textbooks: - Add textbook-form-fields component - Add use-kp-create, use-kp-delete, use-kp-update hooks
This commit is contained in:
@@ -37,6 +37,7 @@ import {
|
||||
import { Button } from "@/shared/components/ui/button"
|
||||
import type { GraphViewMode, GraphNodeData } from "../types"
|
||||
import { computeGraphLayout } from "../graph-layout"
|
||||
import type { GraphLayoutNodeData } from "../graph-layout"
|
||||
import { useGraphData } from "../hooks/use-graph-data"
|
||||
import {
|
||||
createPrerequisiteAction,
|
||||
@@ -202,35 +203,44 @@ function KnowledgeGraphInner({ textbookId, initialViewMode = "structure" }: Know
|
||||
const handleAddPrerequisite = useCallback(async () => {
|
||||
if (!selectedKpId || !newPrereqId || !textbookId) return
|
||||
setIsSavingPrereq(true)
|
||||
const formData = new FormData()
|
||||
formData.set("knowledgePointId", selectedKpId)
|
||||
formData.set("prerequisiteKpId", newPrereqId)
|
||||
formData.set("textbookId", textbookId)
|
||||
const result = await createPrerequisiteAction(formData)
|
||||
setIsSavingPrereq(false)
|
||||
if (result.success) {
|
||||
toast.success(t("graph.detail.prerequisiteAdded"))
|
||||
setAddPrereqOpen(false)
|
||||
setNewPrereqId("")
|
||||
reload()
|
||||
} else {
|
||||
toast.error(result.message)
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.set("knowledgePointId", selectedKpId)
|
||||
formData.set("prerequisiteKpId", newPrereqId)
|
||||
formData.set("textbookId", textbookId)
|
||||
const result = await createPrerequisiteAction(formData)
|
||||
if (result.success) {
|
||||
toast.success(t("graph.detail.prerequisiteAdded"))
|
||||
setAddPrereqOpen(false)
|
||||
setNewPrereqId("")
|
||||
reload()
|
||||
} else {
|
||||
toast.error(result.message)
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error(e instanceof Error ? e.message : t("graph.detail.prerequisiteAddFailed"))
|
||||
} finally {
|
||||
setIsSavingPrereq(false)
|
||||
}
|
||||
}, [selectedKpId, newPrereqId, textbookId, t, reload])
|
||||
|
||||
// 删除前置依赖
|
||||
const handleRemovePrerequisite = useCallback(async (prereqId: string) => {
|
||||
if (!selectedKpId || !textbookId) return
|
||||
const formData = new FormData()
|
||||
formData.set("knowledgePointId", selectedKpId)
|
||||
formData.set("prerequisiteKpId", prereqId)
|
||||
formData.set("textbookId", textbookId)
|
||||
const result = await deletePrerequisiteAction(formData)
|
||||
if (result.success) {
|
||||
toast.success(t("graph.detail.prerequisiteRemoved"))
|
||||
reload()
|
||||
} else {
|
||||
toast.error(result.message)
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.set("knowledgePointId", selectedKpId)
|
||||
formData.set("prerequisiteKpId", prereqId)
|
||||
formData.set("textbookId", textbookId)
|
||||
const result = await deletePrerequisiteAction(formData)
|
||||
if (result.success) {
|
||||
toast.success(t("graph.detail.prerequisiteRemoved"))
|
||||
reload()
|
||||
} else {
|
||||
toast.error(result.message)
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error(e instanceof Error ? e.message : t("graph.detail.prerequisiteRemoveFailed"))
|
||||
}
|
||||
}, [selectedKpId, textbookId, t, reload])
|
||||
|
||||
@@ -306,9 +316,10 @@ function KnowledgeGraphInner({ textbookId, initialViewMode = "structure" }: Know
|
||||
<MiniMap
|
||||
className="!bg-background !border !rounded-lg"
|
||||
nodeColor={(node) => {
|
||||
// node.data 是 Record<string, unknown>;从 unknown 安全转换读取 graphData
|
||||
const graphData = (node.data as unknown as { graphData?: { chapterColor: string } })?.graphData
|
||||
return graphData?.chapterColor ?? "#6b7280"
|
||||
// 安全的类型收窄:node.data 是 Record<string, unknown>,
|
||||
// GraphLayoutNodeData 有索引签名 [key: string]: unknown,是 Record 的子类型
|
||||
const data = node.data as GraphLayoutNodeData
|
||||
return data.graphData?.chapterColor ?? "#6b7280"
|
||||
}}
|
||||
/>
|
||||
</ReactFlow>
|
||||
|
||||
Reference in New Issue
Block a user