feat(textbooks): 教材模块审计重构 — 跨模块解耦 + 权限 + i18n + 错误边界 + 纯函数抽取

P0 修复:
- 解耦跨模块 UI 依赖:knowledge-point-dialogs 不再直接 import questions,
  改为 renderQuestionCreator render prop 由页面注入
- 接入 usePermission Hook 替换 canEdit 硬编码
- 全模块 i18n 改造:新增 en/zh-CN 翻译文件,替换所有硬编码文案
- Server Action 资源归属校验:新增 verifyChapterBelongsToTextbook/
  verifyKnowledgePointBelongsToTextbook,在 reorder/update/delete/create 中校验

P1 改进:
- 补齐 Error Boundary:4 个 error.tsx + TextbookSectionErrorBoundary 区块包裹
- 抽取纯函数到 utils.ts/graph-layout.ts/constants.ts 并补单测(26 用例全通过)
- 消除重复组件:删除 knowledge-point-panel/create-knowledge-point-dialog
- 修复类型断言:chapter.children! → 守卫式访问
- 图谱 a11y:添加 role/aria-label/aria-pressed
- 统一删除确认:confirm() → AlertDialog
- 数据范围过滤:getTextbooksWithScope 支持学生端按年级过滤

P2 预留:
- TextbookAnalytics 埋点接口 + Provider + Hook

同步 005 架构数据 JSON:补充 getTextbooksWithScope/verify*/ChapterTreeNode 等
This commit is contained in:
SpecialX
2026-06-22 16:25:59 +08:00
parent 45ee1ae43c
commit 22d3f07fcf
35 changed files with 2043 additions and 792 deletions

View File

@@ -0,0 +1,186 @@
{
"list": {
"title": "Textbooks",
"subtitle": "Manage your digital curriculum resources and chapters.",
"add": "Add Textbook",
"empty": {
"withFilters": "No textbooks match your filters",
"withoutFilters": "No textbooks yet",
"withFiltersDesc": "Try clearing filters or adjusting keywords.",
"withoutFiltersDesc": "Create your first textbook to start organizing chapters."
},
"clearFilters": "Clear filters",
"chapters": "Chapters"
},
"student": {
"list": {
"title": "Textbooks",
"subtitle": "Browse your course textbooks.",
"empty": {
"withFilters": "No textbooks match your filters",
"withoutFilters": "No textbooks yet",
"withFiltersDesc": "Try clearing filters or adjusting keywords.",
"withoutFiltersDesc": "No textbooks are available right now."
}
},
"noUser": "No user found",
"noUserDesc": "Create a student user to see textbooks."
},
"reader": {
"back": "Back to textbooks",
"tabs": {
"chapters": "Chapters",
"knowledge": "Knowledge Points",
"graph": "Graph"
},
"selectChapter": "Please select a chapter to start reading.",
"selectChapterKnowledge": "Please select a chapter to view knowledge points.",
"selectChapterGraph": "Please select a chapter to view the knowledge graph.",
"emptyKnowledge": "No knowledge points in this chapter yet.",
"emptyContent": "No content yet",
"editContent": "Edit Content",
"cancel": "Cancel",
"save": "Save",
"saving": "Saving...",
"addKnowledgePoint": "Add Knowledge Point",
"clickToViewKp": "Click to view knowledge point details",
"noChapters": "No chapters",
"noChaptersDesc": "This textbook has no chapters yet."
},
"dialog": {
"create": {
"title": "Add New Textbook",
"description": "Create a new digital textbook. Click save when you're done.",
"submit": "Save changes",
"saving": "Saving..."
},
"settings": {
"title": "Textbook Settings",
"description": "Update textbook details or delete this textbook.",
"delete": "Delete Textbook",
"deleteConfirmTitle": "Delete Textbook?",
"deleteConfirmDesc": "This action cannot be undone. This will permanently delete the textbook and all its chapters and knowledge points.",
"save": "Save Changes",
"processing": "Processing...",
"trigger": "Settings"
},
"chapter": {
"createTitle": "Add New Chapter",
"createDesc": "Create a new chapter or section.",
"submit": "Create Chapter",
"creating": "Creating...",
"deleteTitle": "Delete Chapter?",
"deleteDesc": "This will permanently delete {title}. This action cannot be undone.",
"delete": "Delete",
"deleting": "Deleting...",
"cannotDeleteWithSubchapters": "Cannot delete chapter with subchapters",
"addSubchapter": "Add Subchapter",
"titlePlaceholder": "e.g. Chapter 1: Introduction"
},
"knowledge": {
"createTitle": "Add Knowledge Point",
"createDesc": "Create a knowledge point from the selected text.",
"editTitle": "Edit Knowledge Point",
"editDesc": "Modify the knowledge point name and description.",
"name": "Name",
"description": "Description (optional)",
"descriptionPlaceholder": "Enter description...",
"displayName": "Display Name",
"anchorText": "Advanced: Anchor Text (affects highlighting)",
"anchorTextHint": "Changing this field will change the text highlighted in the content. Usually keep it consistent with the original.",
"create": "Create",
"creating": "Creating...",
"save": "Save",
"saving": "Saving...",
"cancel": "Cancel",
"deleteTitle": "Confirm Delete",
"deleteDesc": "Are you sure you want to delete this knowledge point? This action cannot be undone.",
"delete": "Delete",
"createQuestion": "Create Related Question",
"editKp": "Edit Knowledge Point",
"deleteKp": "Delete Knowledge Point"
}
},
"field": {
"title": "Title",
"subject": "Subject",
"grade": "Grade",
"publisher": "Publisher",
"titlePlaceholder": "e.g. Advanced Calculus",
"publisherPlaceholder": "e.g. Next Education",
"subjectPlaceholder": "Select subject",
"gradePlaceholder": "Select grade"
},
"filters": {
"searchPlaceholder": "Search by title, publisher...",
"allSubjects": "All Subjects",
"allGrades": "All Grades"
},
"card": {
"chapters": "Chapters",
"updated": "Updated",
"gradeNA": "Grade N/A",
"publisherNA": "Publisher N/A",
"editContent": "Edit Content",
"delete": "Delete",
"moreOptions": "More options"
},
"panel": {
"knowledgePoints": "Knowledge Points",
"noPointsYet": "No points yet",
"noPointsDesc": "Add knowledge points to tag content in this chapter.",
"selectChapter": "Select a chapter to manage knowledge points",
"level": "Lv."
},
"subject": {
"mathematics": "Mathematics",
"physics": "Physics",
"chemistry": "Chemistry",
"biology": "Biology",
"english": "English",
"history": "History",
"geography": "Geography"
},
"grade": {
"grade7": "Grade 7",
"grade8": "Grade 8",
"grade9": "Grade 9",
"grade10": "Grade 10",
"grade11": "Grade 11",
"grade12": "Grade 12"
},
"error": {
"loadFailed": "Failed to load textbook",
"loadFailedDesc": "An error occurred while loading the textbook content. Please try again.",
"retry": "Retry"
},
"action": {
"createSuccess": "Textbook created successfully.",
"createFailed": "Failed to create textbook.",
"updateSuccess": "Textbook updated successfully.",
"updateFailed": "Failed to update textbook.",
"deleteSuccess": "Textbook deleted successfully.",
"deleteFailed": "Failed to delete textbook.",
"chapterCreateSuccess": "Chapter created successfully",
"chapterCreateFailed": "Failed to create chapter",
"chapterDeleteSuccess": "Chapter deleted successfully",
"chapterDeleteFailed": "Failed to delete chapter",
"contentUpdateSuccess": "Content updated successfully",
"contentUpdateFailed": "Failed to update content",
"kpCreateSuccess": "Knowledge point created successfully",
"kpCreateFailed": "Failed to create knowledge point",
"kpUpdateSuccess": "Knowledge point updated successfully",
"kpUpdateFailed": "Failed to update knowledge point",
"kpDeleteSuccess": "Knowledge point deleted successfully",
"kpDeleteFailed": "Failed to delete knowledge point",
"reorderSuccess": "Order updated",
"reorderFailed": "Failed to reorder chapters",
"fillRequired": "Please fill in all required fields.",
"titleRequired": "Title is required",
"nameRequired": "Name is required",
"invalidContent": "Invalid chapter content data",
"errorOccurred": "An error occurred",
"deleteFailed": "Deletion failed",
"updateFailedGeneric": "Update failed"
}
}