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:
@@ -53,12 +53,6 @@ export interface TextbookReaderProps {
|
||||
* 必传,否则知识点面板将始终为空。
|
||||
*/
|
||||
textbookId: string
|
||||
/**
|
||||
* 是否可编辑。已废弃——改由内部 usePermission() 自动判断。
|
||||
* 保留 prop 仅为向后兼容,传入值会被忽略。
|
||||
* @deprecated 改用权限系统自动判断
|
||||
*/
|
||||
canEdit?: boolean
|
||||
/**
|
||||
* 题目创建器渲染函数(P0-1 解耦)。
|
||||
* 由页面层注入 questions 模块的 CreateQuestionDialog 实现。
|
||||
@@ -176,8 +170,11 @@ export function TextbookReader({
|
||||
|
||||
const onCreateKnowledgePoint = async (formData: FormData) => {
|
||||
setIsCreating(true)
|
||||
await handleCreateKnowledgePoint(formData)
|
||||
setIsCreating(false)
|
||||
try {
|
||||
await handleCreateKnowledgePoint(formData)
|
||||
} finally {
|
||||
setIsCreating(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveContent = async () => {
|
||||
@@ -224,19 +221,13 @@ export function TextbookReader({
|
||||
return highlightKnowledgePoints(effectiveContent, currentChapterKPs)
|
||||
}, [effectiveContent, currentChapterKPs])
|
||||
|
||||
// P2 状态驱动:仅保留 scrollIntoView(滚动无法声明式实现),
|
||||
// 视觉高亮已由 TextbookContentPanel 中 isHighlighted 状态驱动,无需命令式 classList 操作
|
||||
useEffect(() => {
|
||||
if (!highlightedKpId) return
|
||||
const el = document.querySelector(`[data-kp-id="${highlightedKpId}"]`)
|
||||
if (!el) return
|
||||
|
||||
el.scrollIntoView({ behavior: "smooth", block: "center" })
|
||||
el.classList.add("ring-2", "ring-primary", "ring-offset-2")
|
||||
const timer = setTimeout(() => {
|
||||
el.classList.remove("ring-2", "ring-primary", "ring-offset-2")
|
||||
}, 2000)
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [highlightedKpId])
|
||||
|
||||
// P2-4 侧边栏内容(章节/知识点/图谱 Tabs),桌面端内联、移动端抽屉复用同一份
|
||||
@@ -422,24 +413,29 @@ export function TextbookReader({
|
||||
retryLabel={t("error.retry")}
|
||||
>
|
||||
<TextbookContentPanel
|
||||
selected={selected}
|
||||
isEditing={isEditing}
|
||||
editContent={editContent}
|
||||
setEditContent={setEditContent}
|
||||
chapter={{ selected, processedContent }}
|
||||
editing={{
|
||||
isEditing,
|
||||
editContent,
|
||||
setEditContent,
|
||||
isSaving,
|
||||
startEditing,
|
||||
cancelEditing: () => setIsEditing(false),
|
||||
saveContent: handleSaveContent,
|
||||
}}
|
||||
selection={{
|
||||
contentRef,
|
||||
onPointerDown: handleContentPointerDown,
|
||||
onContextMenuChange: handleContextMenuChange,
|
||||
selectedText,
|
||||
setCreateDialogOpen,
|
||||
}}
|
||||
highlight={{
|
||||
highlightedKpId,
|
||||
onHighlight: setHighlightedKpId,
|
||||
onSwitchToKnowledgeTab: () => setActiveTab("knowledge"),
|
||||
}}
|
||||
canEdit={canEdit}
|
||||
highlightedKpId={highlightedKpId}
|
||||
onHighlight={setHighlightedKpId}
|
||||
onSwitchToKnowledgeTab={() => setActiveTab("knowledge")}
|
||||
contentRef={contentRef}
|
||||
onPointerDown={handleContentPointerDown}
|
||||
onContextMenuChange={handleContextMenuChange}
|
||||
selectedText={selectedText}
|
||||
setCreateDialogOpen={setCreateDialogOpen}
|
||||
startEditing={startEditing}
|
||||
cancelEditing={() => setIsEditing(false)}
|
||||
saveContent={handleSaveContent}
|
||||
isSaving={isSaving}
|
||||
processedContent={processedContent}
|
||||
/>
|
||||
</TextbookSectionErrorBoundary>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user