新增功能: 1. AI智能评分系统 - 集成OpenAI兼容API进行简答题评分 - 提供分数、评语和改进建议 - 支持自定义AI服务配置(BaseURL、APIKey、Model) 2. 题目列表页面 - 展示所有题目和答案 - Tab标签页形式的题型筛选(选择题、多选题、判断题、填空题、简答题) - 关键词搜索功能(支持题目内容和编号搜索) - 填空题特殊渲染:****显示为下划线 - 判断题不显示选项,界面更简洁 3. UI优化 - 答题结果组件重构,支持AI评分显示 - 首页新增"题目列表"快速入口 - 响应式设计,适配移动端和PC端 技术改进: - 添加AI评分服务层(internal/services/ai_grading.go) - 扩展题目模型支持AI评分结果 - 更新配置管理支持AI服务配置 - 添加AI评分测试脚本和文档 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
172 lines
5.7 KiB
TypeScript
172 lines
5.7 KiB
TypeScript
import React from 'react'
|
||
import { Alert, Typography, Card, Space, Progress } from 'antd'
|
||
import { CheckOutlined, CloseOutlined, TrophyOutlined, CommentOutlined, BulbOutlined } from '@ant-design/icons'
|
||
import type { AnswerResult as AnswerResultType } from '../types/question'
|
||
|
||
const { Text, Paragraph } = Typography
|
||
|
||
interface AnswerResultProps {
|
||
answerResult: AnswerResultType
|
||
selectedAnswer: string | string[]
|
||
questionType: string
|
||
}
|
||
|
||
const AnswerResult: React.FC<AnswerResultProps> = ({
|
||
answerResult,
|
||
selectedAnswer,
|
||
questionType,
|
||
}) => {
|
||
// 格式化答案显示(判断题特殊处理)
|
||
const formatAnswer = (answer: string | string[] | boolean) => {
|
||
// 处理判断题的布尔值和字符串
|
||
if (questionType === 'true-false') {
|
||
if (typeof answer === 'boolean') {
|
||
return answer ? '正确' : '错误'
|
||
}
|
||
if (typeof answer === 'string') {
|
||
return answer === 'true' ? '正确' : answer === 'false' ? '错误' : answer
|
||
}
|
||
}
|
||
|
||
// 处理数组答案
|
||
if (Array.isArray(answer)) {
|
||
return answer.join(', ')
|
||
}
|
||
|
||
return String(answer)
|
||
}
|
||
|
||
// 获取评分等级颜色
|
||
const getScoreColor = (score: number) => {
|
||
if (score >= 90) return '#52c41a' // 优秀 - 绿色
|
||
if (score >= 80) return '#1890ff' // 良好 - 蓝色
|
||
if (score >= 60) return '#faad14' // 及格 - 橙色
|
||
return '#ff4d4f' // 不及格 - 红色
|
||
}
|
||
|
||
// 获取评分等级
|
||
const getScoreLevel = (score: number) => {
|
||
if (score >= 90) return '优秀'
|
||
if (score >= 80) return '良好'
|
||
if (score >= 60) return '及格'
|
||
return '不及格'
|
||
}
|
||
|
||
return (
|
||
<div style={{ marginTop: 20 }}>
|
||
<Alert
|
||
type={answerResult.correct ? 'success' : 'error'}
|
||
icon={answerResult.correct ? <CheckOutlined /> : <CloseOutlined />}
|
||
message={
|
||
<div>
|
||
<strong>{answerResult.correct ? '回答正确!' : '回答错误'}</strong>
|
||
</div>
|
||
}
|
||
description={
|
||
<div>
|
||
<div style={{ marginBottom: 8 }}>
|
||
<Text type="secondary">你的答案:</Text>
|
||
<Text strong={answerResult.correct} type={answerResult.correct ? undefined : 'danger'}>
|
||
{formatAnswer(answerResult.user_answer || selectedAnswer)}
|
||
</Text>
|
||
</div>
|
||
<div style={{ marginBottom: 8 }}>
|
||
<Text strong style={{ color: '#52c41a' }}>
|
||
正确答案:
|
||
</Text>
|
||
<Text strong style={{ color: '#52c41a' }}>
|
||
{formatAnswer(
|
||
answerResult.correct_answer || (answerResult.correct ? selectedAnswer : '暂无')
|
||
)}
|
||
</Text>
|
||
</div>
|
||
{answerResult.explanation && (
|
||
<div>
|
||
<Text type="secondary">解析:</Text>
|
||
<div style={{ marginTop: 4 }}>{answerResult.explanation}</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
}
|
||
/>
|
||
|
||
{/* AI评分结果 - 仅简答题显示 */}
|
||
{answerResult.ai_grading && (
|
||
<Card
|
||
style={{
|
||
marginTop: 16,
|
||
borderColor: getScoreColor(answerResult.ai_grading.score),
|
||
borderWidth: 2,
|
||
}}
|
||
title={
|
||
<Space>
|
||
<TrophyOutlined style={{ color: getScoreColor(answerResult.ai_grading.score) }} />
|
||
<Text strong>AI智能评分</Text>
|
||
</Space>
|
||
}
|
||
>
|
||
{/* 分数和进度条 */}
|
||
<div style={{ marginBottom: 20 }}>
|
||
<Space align="center" size="large">
|
||
<div>
|
||
<Text type="secondary" style={{ fontSize: 14 }}>得分</Text>
|
||
<div>
|
||
<Text
|
||
strong
|
||
style={{
|
||
fontSize: 32,
|
||
color: getScoreColor(answerResult.ai_grading.score),
|
||
}}
|
||
>
|
||
{answerResult.ai_grading.score}
|
||
</Text>
|
||
<Text type="secondary" style={{ fontSize: 18 }}> / 100</Text>
|
||
</div>
|
||
</div>
|
||
<div style={{ flex: 1, minWidth: 200 }}>
|
||
<Progress
|
||
percent={answerResult.ai_grading.score}
|
||
strokeColor={getScoreColor(answerResult.ai_grading.score)}
|
||
format={(percent) => `${getScoreLevel(percent || 0)}`}
|
||
/>
|
||
</div>
|
||
</Space>
|
||
</div>
|
||
|
||
{/* 评语 */}
|
||
{answerResult.ai_grading.feedback && (
|
||
<div style={{ marginBottom: 16 }}>
|
||
<Space align="start">
|
||
<CommentOutlined style={{ fontSize: 16, color: '#1890ff', marginTop: 2 }} />
|
||
<div style={{ flex: 1 }}>
|
||
<Text strong style={{ fontSize: 14 }}>评语:</Text>
|
||
<Paragraph style={{ marginTop: 4, marginBottom: 0, color: '#595959' }}>
|
||
{answerResult.ai_grading.feedback}
|
||
</Paragraph>
|
||
</div>
|
||
</Space>
|
||
</div>
|
||
)}
|
||
|
||
{/* 改进建议 */}
|
||
{answerResult.ai_grading.suggestion && (
|
||
<div>
|
||
<Space align="start">
|
||
<BulbOutlined style={{ fontSize: 16, color: '#faad14', marginTop: 2 }} />
|
||
<div style={{ flex: 1 }}>
|
||
<Text strong style={{ fontSize: 14 }}>改进建议:</Text>
|
||
<Paragraph style={{ marginTop: 4, marginBottom: 0, color: '#595959' }}>
|
||
{answerResult.ai_grading.suggestion}
|
||
</Paragraph>
|
||
</div>
|
||
</Space>
|
||
</div>
|
||
)}
|
||
</Card>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default AnswerResult
|