Python (6 files in klausur-service): - rbac.py (1,132 → 4), admin_api.py (1,012 → 4) - routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5) Python (2 files in backend-lehrer): - unit_api.py (1,226 → 6), game_api.py (1,129 → 5) Website (6 page files): - 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components in website/components/klausur-korrektur/ (17 shared files) - companion (1,057 → 10), magic-help (1,017 → 8) All re-export barrels preserve backward compatibility. Zero import errors verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
141 lines
5.2 KiB
TypeScript
141 lines
5.2 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* Korrektur-Workspace (Admin Route)
|
|
*
|
|
* Main correction interface with 2/3 - 1/3 layout:
|
|
* - Left (2/3): Document viewer with annotation overlay
|
|
* - Right (1/3): Criteria scoring, Gutachten editor, Annotations
|
|
*/
|
|
|
|
import { useParams, useRouter } from 'next/navigation'
|
|
import AdminLayout from '@/components/admin/AdminLayout'
|
|
import { useKorrekturWorkspace } from '@/components/klausur-korrektur/useKorrekturWorkspace'
|
|
import WorkspaceTopBar from '@/components/klausur-korrektur/WorkspaceTopBar'
|
|
import DocumentViewer from '@/components/klausur-korrektur/DocumentViewer'
|
|
import CorrectionPanel from '@/components/klausur-korrektur/CorrectionPanel'
|
|
import EinigungModal from '@/components/klausur-korrektur/EinigungModal'
|
|
import ErrorBanner from '@/components/klausur-korrektur/ErrorBanner'
|
|
import AnnotationLayer from '../../components/AnnotationLayer'
|
|
import AnnotationToolbar from '../../components/AnnotationToolbar'
|
|
import AnnotationPanel from '../../components/AnnotationPanel'
|
|
import EHSuggestionPanel from '../../components/EHSuggestionPanel'
|
|
|
|
export default function KorrekturWorkspacePage() {
|
|
const params = useParams()
|
|
const router = useRouter()
|
|
const klausurId = params.klausurId as string
|
|
const studentId = params.studentId as string
|
|
|
|
const ws = useKorrekturWorkspace({ klausurId, studentId })
|
|
|
|
const goToStudent = (direction: 'prev' | 'next') => {
|
|
const newIndex = direction === 'prev' ? ws.currentIndex - 1 : ws.currentIndex + 1
|
|
if (newIndex >= 0 && newIndex < ws.students.length) {
|
|
router.push(`/admin/klausur-korrektur/${klausurId}/${ws.students[newIndex].id}`)
|
|
}
|
|
}
|
|
|
|
if (ws.loading) {
|
|
return (
|
|
<AdminLayout title="Laedt..." description="">
|
|
<div className="flex items-center justify-center h-[calc(100vh-200px)]">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
|
|
</div>
|
|
</AdminLayout>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<AdminLayout
|
|
title={`Korrektur: ${ws.student?.anonym_id || 'Student'}`}
|
|
description={ws.klausur?.title || ''}
|
|
>
|
|
<WorkspaceTopBar
|
|
klausurId={klausurId}
|
|
backPath={`/admin/klausur-korrektur/${klausurId}`}
|
|
currentIndex={ws.currentIndex}
|
|
studentCount={ws.students.length}
|
|
workflow={ws.workflow}
|
|
saving={ws.saving}
|
|
totals={ws.totals}
|
|
onGoToStudent={goToStudent}
|
|
/>
|
|
|
|
{ws.showEinigungModal && ws.workflow && (
|
|
<EinigungModal
|
|
workflow={ws.workflow}
|
|
einigungGrade={ws.einigungGrade}
|
|
einigungNotes={ws.einigungNotes}
|
|
submittingWorkflow={ws.submittingWorkflow}
|
|
onGradeChange={ws.setEinigungGrade}
|
|
onNotesChange={ws.setEinigungNotes}
|
|
onSubmit={ws.submitEinigung}
|
|
onClose={() => ws.setShowEinigungModal(false)}
|
|
/>
|
|
)}
|
|
|
|
{ws.error && <ErrorBanner error={ws.error} onDismiss={() => ws.setError(null)} />}
|
|
|
|
<div className="flex gap-6 h-[calc(100vh-280px)]">
|
|
<DocumentViewer
|
|
student={ws.student}
|
|
documentUrl={ws.documentUrl}
|
|
zoom={ws.zoom}
|
|
currentPage={ws.currentPage}
|
|
totalPages={ws.totalPages}
|
|
annotations={ws.annotations}
|
|
selectedTool={ws.selectedTool}
|
|
selectedAnnotation={ws.selectedAnnotation}
|
|
annotationCounts={ws.annotationCounts}
|
|
onZoomChange={ws.setZoom}
|
|
onPageChange={ws.setCurrentPage}
|
|
onSelectTool={ws.setSelectedTool}
|
|
onCreateAnnotation={ws.createAnnotation}
|
|
onSelectAnnotation={(ann) => {
|
|
ws.setSelectedAnnotation(ann)
|
|
ws.setActiveTab('annotationen')
|
|
}}
|
|
AnnotationToolbarComponent={AnnotationToolbar}
|
|
AnnotationLayerComponent={AnnotationLayer}
|
|
/>
|
|
|
|
<CorrectionPanel
|
|
activeTab={ws.activeTab}
|
|
onTabChange={ws.setActiveTab}
|
|
annotations={ws.annotations}
|
|
gradeInfo={ws.gradeInfo}
|
|
criteriaScores={ws.criteriaScores}
|
|
gutachten={ws.gutachten}
|
|
totals={ws.totals}
|
|
workflow={ws.workflow}
|
|
saving={ws.saving}
|
|
generatingGutachten={ws.generatingGutachten}
|
|
exporting={ws.exporting}
|
|
submittingWorkflow={ws.submittingWorkflow}
|
|
selectedAnnotation={ws.selectedAnnotation}
|
|
studentId={studentId}
|
|
klausurId={klausurId}
|
|
klausurEhId={ws.klausur?.eh_id}
|
|
onCriteriaChange={ws.handleCriteriaChange}
|
|
onGutachtenChange={ws.setGutachten}
|
|
onSaveGutachten={ws.saveGutachten}
|
|
onGenerateGutachten={ws.generateGutachten}
|
|
onExportGutachtenPDF={ws.exportGutachtenPDF}
|
|
onSelectAnnotation={ws.setSelectedAnnotation}
|
|
onUpdateAnnotation={ws.updateAnnotation}
|
|
onDeleteAnnotation={ws.deleteAnnotation}
|
|
onSelectTool={ws.setSelectedTool}
|
|
onSetActiveTab={ws.setActiveTab}
|
|
onSubmitErstkorrektur={ws.submitErstkorrektur}
|
|
onStartZweitkorrektur={ws.startZweitkorrektur}
|
|
onSubmitZweitkorrektur={ws.submitZweitkorrektur}
|
|
onShowEinigungModal={() => ws.setShowEinigungModal(true)}
|
|
AnnotationPanelComponent={AnnotationPanel}
|
|
EHSuggestionPanelComponent={EHSuggestionPanel}
|
|
/>
|
|
</div>
|
|
</AdminLayout>
|
|
)
|
|
}
|