"use client" import { type ReactNode } from "react" import { Checkbox } from "@/shared/components/ui/checkbox" import { Label } from "@/shared/components/ui/label" import { RadioGroup, RadioGroupItem } from "@/shared/components/ui/radio-group" import { Textarea } from "@/shared/components/ui/textarea" import { useTranslations } from "next-intl" import { extractAnswerValue, getOptions, getQuestionText, type QuestionOption, type QuestionType, } from "../lib/question-content-utils" import { isRecord } from "@/shared/lib/type-guards" /** * 题目渲染模式 * - `take`: 学生作答交互 * - `review`: 学生查看批改结果(只读 + 正确答案高亮) * - `grade`: 教师批改(只读学生答案 + 正确答案 + 评分面板 slot) */ export type QuestionRenderMode = "take" | "review" | "grade" export interface QuestionRendererProps { questionId: string questionType: QuestionType questionContent: unknown maxScore: number index: number mode: QuestionRenderMode /** 学生答案(take 模式下为当前值,review/grade 模式下为已提交值) */ value?: unknown /** take 模式下的禁用状态 */ disabled?: boolean /** take 模式下答案变更回调 */ onChange?: (answer: unknown) => void /** review/grade 模式下是否显示正确答案 */ showCorrectAnswer?: boolean /** review/grade 模式下是否显示批改反馈 */ feedback?: string | null /** 题目头部右侧额外内容(如分数 Badge) */ headerExtra?: ReactNode /** 题目底部额外内容(如批改面板) */ footerExtra?: ReactNode /** 题目卡片额外 className */ className?: string } /** * 题目渲染器(只读展示 + 答案输入组合) * * 通过 `mode` 切换交互行为: * - `take`: 渲染可编辑的作答输入控件 * - `review`: 渲染只读答案 + 正确答案高亮 * - `grade`: 渲染只读学生答案 + 正确答案(由父组件通过 `footerExtra` 注入批改面板) */ export function QuestionRenderer({ questionId, questionType, questionContent, maxScore, index, mode, value, disabled, onChange, showCorrectAnswer, feedback, headerExtra, footerExtra, className, }: QuestionRendererProps) { const t = useTranslations("examHomework") const text = getQuestionText(questionContent) const options = getOptions(questionContent) const isReadOnly = mode !== "take" const showFeedback = isReadOnly && Boolean(feedback) return (

{t("homework.take.question", { index: index + 1 })}

{questionType.replace("_", " ").replace(/\b\w/g, (l) => l.toUpperCase())} • {maxScore} {t("homework.take.points")}

{headerExtra}
{text || "—"}
{showFeedback && (
{t("homework.take.teacherFeedback")}
{feedback}
)} {footerExtra}
) } interface QuestionAnswerInputProps { questionId: string questionType: QuestionType options: QuestionOption[] value: unknown disabled?: boolean readOnly?: boolean onChange?: (answer: unknown) => void showCorrectAnswer?: boolean questionContent: unknown } function QuestionAnswerInput({ questionId, questionType, options, value, disabled, readOnly, onChange, showCorrectAnswer, questionContent, }: QuestionAnswerInputProps) { const t = useTranslations("examHomework") if (questionType === "text") { if (readOnly) { const textValue = typeof value === "string" ? value : "" return (
{textValue || ( {t("homework.review.noAnswer")} )}
{showCorrectAnswer && ( )}
) } return (