重构题目练习模式,优化用户体验
主要变更: - 移除独立的随机题目 API 和快速开始卡片 - 添加应用图标 (icon.svg) 和品牌标识 - 优化首页布局,添加 logo 和"安全保密考试题库"标语 - 将随机模式改为答题页面内的可选开关(默认关闭) - 改进错题练习逻辑,单独处理随机错题功能 - 同步更新 README.md 文档 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
ac3249a4a4
commit
b30647d81b
@ -64,7 +64,6 @@ yarn dev
|
|||||||
|
|
||||||
#### 练习题相关
|
#### 练习题相关
|
||||||
- `GET /api/practice/questions` - 获取练习题目列表 (支持分页和类型过滤)
|
- `GET /api/practice/questions` - 获取练习题目列表 (支持分页和类型过滤)
|
||||||
- `GET /api/practice/questions/random` - 获取随机练习题目
|
|
||||||
- `GET /api/practice/questions/:id` - 获取指定练习题目
|
- `GET /api/practice/questions/:id` - 获取指定练习题目
|
||||||
- `POST /api/practice/submit` - 提交练习答案 (简答题自动AI评分)
|
- `POST /api/practice/submit` - 提交练习答案 (简答题自动AI评分)
|
||||||
- `GET /api/practice/types` - 获取题型列表
|
- `GET /api/practice/types` - 获取题型列表
|
||||||
@ -224,7 +223,7 @@ yarn build
|
|||||||
## 页面结构
|
## 页面结构
|
||||||
|
|
||||||
- **登录页** (`/login`) - 用户登录和注册,支持密码可见性切换
|
- **登录页** (`/login`) - 用户登录和注册,支持密码可见性切换
|
||||||
- **首页** (`/`) - 题目练习、随机题目、题目列表、筛选等功能
|
- **首页** (`/`) - 题型选择、错题本、题目列表等功能
|
||||||
- **我的** (`/profile`) - 用户信息、退出登录
|
- **我的** (`/profile`) - 用户信息、退出登录
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
@ -238,7 +237,6 @@ yarn build
|
|||||||
- 密码bcrypt加密存储
|
- 密码bcrypt加密存储
|
||||||
- 练习题管理系统(236道练习题,5种题型)
|
- 练习题管理系统(236道练习题,5种题型)
|
||||||
- 支持分页查询和题型筛选
|
- 支持分页查询和题型筛选
|
||||||
- 随机题目推送功能
|
|
||||||
- **AI智能评分系统** - 使用deepseek-v3对简答题进行智能评分和反馈
|
- **AI智能评分系统** - 使用deepseek-v3对简答题进行智能评分和反馈
|
||||||
|
|
||||||
### 前端特性
|
### 前端特性
|
||||||
|
|||||||
17
main.go
17
main.go
@ -43,22 +43,21 @@ func main() {
|
|||||||
auth.PUT("/user/type", handlers.UpdateUserType) // 更新用户类型
|
auth.PUT("/user/type", handlers.UpdateUserType) // 更新用户类型
|
||||||
|
|
||||||
// 练习题相关API(需要登录)
|
// 练习题相关API(需要登录)
|
||||||
auth.GET("/practice/questions", handlers.GetPracticeQuestions) // 获取练习题目列表
|
auth.GET("/practice/questions", handlers.GetPracticeQuestions) // 获取练习题目列表
|
||||||
auth.GET("/practice/questions/random", handlers.GetRandomPracticeQuestion) // 获取随机练习题目
|
auth.GET("/practice/questions/:id", handlers.GetPracticeQuestionByID) // 获取指定练习题目
|
||||||
auth.GET("/practice/questions/:id", handlers.GetPracticeQuestionByID) // 获取指定练习题目
|
auth.POST("/practice/explain", handlers.ExplainQuestion) // 生成题目解析(AI)
|
||||||
auth.POST("/practice/explain", handlers.ExplainQuestion) // 生成题目解析(AI)
|
|
||||||
|
|
||||||
// 练习题提交(需要登录才能记录错题)
|
// 练习题提交(需要登录才能记录错题)
|
||||||
auth.POST("/practice/submit", handlers.SubmitPracticeAnswer) // 提交练习答案
|
auth.POST("/practice/submit", handlers.SubmitPracticeAnswer) // 提交练习答案
|
||||||
auth.GET("/practice/statistics", handlers.GetStatistics) // 获取统计数据
|
auth.GET("/practice/statistics", handlers.GetStatistics) // 获取统计数据
|
||||||
|
|
||||||
// 错题本相关API
|
// 错题本相关API
|
||||||
auth.GET("/wrong-questions", handlers.GetWrongQuestions) // 获取错题列表
|
auth.GET("/wrong-questions", handlers.GetWrongQuestions) // 获取错题列表
|
||||||
auth.GET("/wrong-questions/stats", handlers.GetWrongQuestionStats) // 获取错题统计
|
auth.GET("/wrong-questions/stats", handlers.GetWrongQuestionStats) // 获取错题统计
|
||||||
auth.GET("/wrong-questions/random", handlers.GetRandomWrongQuestion) // 获取随机错题
|
auth.GET("/wrong-questions/random", handlers.GetRandomWrongQuestion) // 获取随机错题
|
||||||
auth.DELETE("/wrong-questions/:id", handlers.DeleteWrongQuestion) // 删除单个错题
|
auth.DELETE("/wrong-questions/:id", handlers.DeleteWrongQuestion) // 删除单个错题
|
||||||
auth.PUT("/wrong-questions/:id/mastered", handlers.MarkWrongQuestionMastered) // 标记已掌握
|
auth.PUT("/wrong-questions/:id/mastered", handlers.MarkWrongQuestionMastered) // 标记已掌握
|
||||||
auth.DELETE("/wrong-questions", handlers.ClearWrongQuestions) // 清空错题本
|
auth.DELETE("/wrong-questions", handlers.ClearWrongQuestions) // 清空错题本
|
||||||
}
|
}
|
||||||
|
|
||||||
// 题库管理API(需要管理员权限)
|
// 题库管理API(需要管理员权限)
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="description" content="AnKao 移动端应用" />
|
<meta name="description" content="AnKao - 安全保密考试系统" />
|
||||||
<title>AnKao</title>
|
<meta name="keywords" content="安全考试,保密考试,在线答题,考试系统" />
|
||||||
|
<meta name="theme-color" content="#1890ff" />
|
||||||
|
<title>AnKao - 安全保密考试</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
117
web/public/icon.svg
Normal file
117
web/public/icon.svg
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="shieldGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#1890ff;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#096dd9;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="lockGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#52c41a;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#389e0d;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
|
||||||
|
<feOffset dx="0" dy="2" result="offsetblur"/>
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA type="linear" slope="0.3"/>
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode/>
|
||||||
|
<feMergeNode in="SourceGraphic"/>
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- 背景圆形 -->
|
||||||
|
<circle cx="100" cy="100" r="95" fill="#f0f5ff" stroke="#d6e4ff" stroke-width="2"/>
|
||||||
|
|
||||||
|
<!-- 主盾牌形状 -->
|
||||||
|
<path d="M 100 25
|
||||||
|
C 80 25, 60 30, 45 40
|
||||||
|
L 45 85
|
||||||
|
C 45 120, 65 145, 100 165
|
||||||
|
C 135 145, 155 120, 155 85
|
||||||
|
L 155 40
|
||||||
|
C 140 30, 120 25, 100 25 Z"
|
||||||
|
fill="url(#shieldGradient)"
|
||||||
|
stroke="#0050b3"
|
||||||
|
stroke-width="2.5"
|
||||||
|
filter="url(#shadow)"/>
|
||||||
|
|
||||||
|
<!-- 盾牌内部高光 -->
|
||||||
|
<path d="M 100 30
|
||||||
|
C 82 30, 65 34, 52 42
|
||||||
|
L 52 85
|
||||||
|
C 52 115, 70 138, 100 156"
|
||||||
|
fill="none"
|
||||||
|
stroke="rgba(255,255,255,0.4)"
|
||||||
|
stroke-width="2.5"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- 文档/试卷图标 -->
|
||||||
|
<rect x="75" y="60" width="50" height="65" rx="3" ry="3"
|
||||||
|
fill="#ffffff"
|
||||||
|
stroke="#0050b3"
|
||||||
|
stroke-width="2"/>
|
||||||
|
|
||||||
|
<!-- 试卷标题线 -->
|
||||||
|
<line x1="82" y1="70" x2="118" y2="70"
|
||||||
|
stroke="#1890ff"
|
||||||
|
stroke-width="2.5"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- 试卷内容线条 -->
|
||||||
|
<line x1="82" y1="80" x2="112" y2="80"
|
||||||
|
stroke="#8cc5ff"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
<line x1="82" y1="88" x2="115" y2="88"
|
||||||
|
stroke="#8cc5ff"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
<line x1="82" y1="96" x2="108" y2="96"
|
||||||
|
stroke="#8cc5ff"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- 锁的主体 -->
|
||||||
|
<rect x="88" y="105" width="24" height="15" rx="2" ry="2"
|
||||||
|
fill="url(#lockGradient)"
|
||||||
|
stroke="#237804"
|
||||||
|
stroke-width="1.5"/>
|
||||||
|
|
||||||
|
<!-- 锁的U形环 -->
|
||||||
|
<path d="M 93 105
|
||||||
|
L 93 98
|
||||||
|
A 7 7 0 0 1 107 98
|
||||||
|
L 107 105"
|
||||||
|
fill="none"
|
||||||
|
stroke="url(#lockGradient)"
|
||||||
|
stroke-width="3"
|
||||||
|
stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- 锁孔 -->
|
||||||
|
<circle cx="100" cy="110" r="2" fill="#ffffff"/>
|
||||||
|
<rect x="99" y="110" width="2" height="4" rx="1" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- 装饰性星星(表示重要性) -->
|
||||||
|
<path d="M 135 45 l 2 6 l 6 1 l -5 4 l 2 6 l -5 -3 l -5 3 l 2 -6 l -5 -4 l 6 -1 Z"
|
||||||
|
fill="#faad14"
|
||||||
|
stroke="#d48806"
|
||||||
|
stroke-width="0.5"
|
||||||
|
opacity="0.9"/>
|
||||||
|
|
||||||
|
<!-- 感叹号(警示标志) -->
|
||||||
|
<g opacity="0.9">
|
||||||
|
<rect x="140" y="130" width="3.5" height="15" rx="1.5" fill="#ff4d4f"/>
|
||||||
|
<circle cx="141.75" cy="148" r="2" fill="#ff4d4f"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 对勾标记(考试通过) -->
|
||||||
|
<path d="M 60 135 L 65 142 L 75 128"
|
||||||
|
fill="none"
|
||||||
|
stroke="#52c41a"
|
||||||
|
stroke-width="3"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
opacity="0.85"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@ -6,11 +6,6 @@ export const getQuestions = (params?: { type?: string; search?: string }) => {
|
|||||||
return request.get<ApiResponse<Question[]>>('/practice/questions', { params })
|
return request.get<ApiResponse<Question[]>>('/practice/questions', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取随机题目
|
|
||||||
export const getRandomQuestion = () => {
|
|
||||||
return request.get<ApiResponse<Question>>('/practice/questions/random')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取指定题目
|
// 获取指定题目
|
||||||
export const getQuestionById = (id: number) => {
|
export const getQuestionById = (id: number) => {
|
||||||
return request.get<ApiResponse<Question>>(`/practice/questions/${id}`)
|
return request.get<ApiResponse<Question>>(`/practice/questions/${id}`)
|
||||||
|
|||||||
@ -15,6 +15,20 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logoArea {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.08));
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: #1d1d1f !important;
|
color: #1d1d1f !important;
|
||||||
margin-bottom: 4px !important;
|
margin-bottom: 4px !important;
|
||||||
@ -183,6 +197,15 @@
|
|||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logoArea {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 22px !important;
|
font-size: 22px !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -200,8 +200,13 @@ const Home: React.FC = () => {
|
|||||||
{/* 头部 */}
|
{/* 头部 */}
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.headerLeft}>
|
<div className={styles.headerLeft}>
|
||||||
<Title level={2} className={styles.title}>AnKao 刷题</Title>
|
<div className={styles.logoArea}>
|
||||||
<Paragraph className={styles.subtitle}>选择题型开始练习</Paragraph>
|
<img src="/icon.svg" alt="AnKao Logo" className={styles.logo} />
|
||||||
|
<div>
|
||||||
|
<Title level={2} className={styles.title}>AnKao 刷题</Title>
|
||||||
|
<Paragraph className={styles.subtitle}>安全保密考试题库</Paragraph>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 用户信息 */}
|
{/* 用户信息 */}
|
||||||
{userInfo && (
|
{userInfo && (
|
||||||
@ -300,24 +305,6 @@ const Home: React.FC = () => {
|
|||||||
<RocketOutlined /> 快速开始
|
<RocketOutlined /> 快速开始
|
||||||
</Title>
|
</Title>
|
||||||
<Row gutter={[12, 12]}>
|
<Row gutter={[12, 12]}>
|
||||||
<Col xs={24} sm={24} md={12} lg={8}>
|
|
||||||
<Card
|
|
||||||
hoverable
|
|
||||||
className={styles.quickCard}
|
|
||||||
onClick={() => navigate('/question')}
|
|
||||||
>
|
|
||||||
<Space align="center" size="middle" style={{ width: '100%' }}>
|
|
||||||
<div className={styles.quickIcon}>
|
|
||||||
<RocketOutlined style={{ fontSize: '32px', color: '#722ed1' }} />
|
|
||||||
</div>
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Title level={5} style={{ margin: 0 }}>随机练习</Title>
|
|
||||||
<Paragraph type="secondary" style={{ margin: 0, fontSize: '13px' }}>从所有题型中随机抽取</Paragraph>
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col xs={24} sm={24} md={12} lg={8}>
|
<Col xs={24} sm={24} md={12} lg={8}>
|
||||||
<Card
|
<Card
|
||||||
hoverable
|
hoverable
|
||||||
|
|||||||
@ -48,6 +48,12 @@ const QuestionPage: React.FC = () => {
|
|||||||
return saved !== null ? parseInt(saved, 10) : 2;
|
return saved !== null ? parseInt(saved, 10) : 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 随机题目开关(默认关闭)
|
||||||
|
const [randomMode, setRandomMode] = useState(() => {
|
||||||
|
const saved = localStorage.getItem('randomModeEnabled');
|
||||||
|
return saved !== null ? saved === 'true' : false;
|
||||||
|
});
|
||||||
|
|
||||||
// 切换自动跳转开关
|
// 切换自动跳转开关
|
||||||
const toggleAutoNext = () => {
|
const toggleAutoNext = () => {
|
||||||
const newValue = !autoNext;
|
const newValue = !autoNext;
|
||||||
@ -55,6 +61,13 @@ const QuestionPage: React.FC = () => {
|
|||||||
localStorage.setItem('autoNextEnabled', String(newValue));
|
localStorage.setItem('autoNextEnabled', String(newValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 切换随机模式开关
|
||||||
|
const toggleRandomMode = () => {
|
||||||
|
const newValue = !randomMode;
|
||||||
|
setRandomMode(newValue);
|
||||||
|
localStorage.setItem('randomModeEnabled', String(newValue));
|
||||||
|
};
|
||||||
|
|
||||||
// 修改自动跳转延迟时间
|
// 修改自动跳转延迟时间
|
||||||
const handleDelayChange = (value: number | null) => {
|
const handleDelayChange = (value: number | null) => {
|
||||||
if (value !== null && value >= 1 && value <= 10) {
|
if (value !== null && value >= 1 && value <= 10) {
|
||||||
@ -121,16 +134,11 @@ const QuestionPage: React.FC = () => {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载随机题目
|
// 加载随机错题
|
||||||
const loadRandomQuestion = async () => {
|
const loadRandomWrongQuestion = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
// 检查是否是错题练习模式
|
const res = await questionApi.getRandomWrongQuestion();
|
||||||
const mode = searchParams.get("mode");
|
|
||||||
const res =
|
|
||||||
mode === "wrong"
|
|
||||||
? await questionApi.getRandomWrongQuestion()
|
|
||||||
: await questionApi.getRandomQuestion();
|
|
||||||
|
|
||||||
if (res.success && res.data) {
|
if (res.success && res.data) {
|
||||||
setCurrentQuestion(res.data);
|
setCurrentQuestion(res.data);
|
||||||
@ -258,16 +266,26 @@ const QuestionPage: React.FC = () => {
|
|||||||
// 下一题
|
// 下一题
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
if (allQuestions.length > 0) {
|
if (allQuestions.length > 0) {
|
||||||
// 检查是否完成所有题目
|
let nextIndex: number;
|
||||||
if (currentIndex + 1 >= allQuestions.length) {
|
|
||||||
// 显示统计摘要
|
// 随机模式:从题库中随机选择一题
|
||||||
setShowSummary(true);
|
if (randomMode) {
|
||||||
// 清除进度
|
// 生成一个不等于当前索引的随机索引
|
||||||
localStorage.removeItem(getStorageKey());
|
do {
|
||||||
return;
|
nextIndex = Math.floor(Math.random() * allQuestions.length);
|
||||||
|
} while (nextIndex === currentIndex && allQuestions.length > 1);
|
||||||
|
} else {
|
||||||
|
// 顺序模式:检查是否完成所有题目
|
||||||
|
if (currentIndex + 1 >= allQuestions.length) {
|
||||||
|
// 显示统计摘要
|
||||||
|
setShowSummary(true);
|
||||||
|
// 清除进度
|
||||||
|
localStorage.removeItem(getStorageKey());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextIndex = currentIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextIndex = currentIndex + 1;
|
|
||||||
setCurrentIndex(nextIndex);
|
setCurrentIndex(nextIndex);
|
||||||
setCurrentQuestion(allQuestions[nextIndex]);
|
setCurrentQuestion(allQuestions[nextIndex]);
|
||||||
setSelectedAnswer(
|
setSelectedAnswer(
|
||||||
@ -310,7 +328,7 @@ const QuestionPage: React.FC = () => {
|
|||||||
|
|
||||||
// 错题练习模式
|
// 错题练习模式
|
||||||
if (mode === "wrong") {
|
if (mode === "wrong") {
|
||||||
loadRandomQuestion();
|
loadRandomWrongQuestion();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,6 +480,24 @@ const QuestionPage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<span style={{ fontSize: 15, fontWeight: 500 }}>随机题目</span>
|
||||||
|
<span style={{ marginLeft: 8, fontSize: 13, color: '#8c8c8c' }}>
|
||||||
|
开启后点击下一题时随机跳转
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12, paddingLeft: 8 }}>
|
||||||
|
<Switch
|
||||||
|
checked={randomMode}
|
||||||
|
onChange={toggleRandomMode}
|
||||||
|
/>
|
||||||
|
<span style={{ fontSize: 14, color: randomMode ? '#52c41a' : '#8c8c8c' }}>
|
||||||
|
{randomMode ? '已开启' : '已关闭'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -277,7 +277,6 @@ const QuestionList: React.FC = () => {
|
|||||||
<List
|
<List
|
||||||
dataSource={filteredQuestions}
|
dataSource={filteredQuestions}
|
||||||
renderItem={(question, index) => {
|
renderItem={(question, index) => {
|
||||||
const typeConfig = questionTypeConfig[question.type]
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={question.id}
|
key={question.id}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user