优化考试管理界面布局和交互
- 在考试失败页面添加"再考一次"按钮,支持快速重新开始考试 - 移除试卷卡片中的考试时长、及格分数和题目数量显示 - 优化试卷卡片布局:减少内边距和卡片间距,使界面更紧凑 - 修复统计标签样式:覆盖antd Tag默认间距,防止图标在文字溢出时缩小 - 实现响应式布局:移动端1列、平板2列、桌面端3列 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
023ab1cc55
commit
e3e0671204
@ -136,7 +136,7 @@
|
|||||||
|
|
||||||
// 卡片内容样式
|
// 卡片内容样式
|
||||||
.cardContent {
|
.cardContent {
|
||||||
padding: 16px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.examInfo {
|
.examInfo {
|
||||||
@ -208,6 +208,12 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center; // 内容居中
|
justify-content: center; // 内容居中
|
||||||
|
|
||||||
|
// 覆盖 antd Tag 的默认图标间距
|
||||||
|
:global(.anticon) + span,
|
||||||
|
span + :global(.anticon) {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
@ -230,7 +236,12 @@
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center; // 内容居中
|
justify-content: center; // 内容居中
|
||||||
width: 100%;
|
|
||||||
|
// 覆盖 antd Tag 的默认图标间距
|
||||||
|
:global(.anticon) + span,
|
||||||
|
span + :global(.anticon) {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -353,7 +364,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cardContent {
|
.cardContent {
|
||||||
margin-top: 12px;
|
|
||||||
|
|
||||||
.infoRow {
|
.infoRow {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -388,6 +398,7 @@
|
|||||||
// 旧版兼容样式 - divider已合并,不再重复定义
|
// 旧版兼容样式 - divider已合并,不再重复定义
|
||||||
|
|
||||||
// 响应式适配
|
// 响应式适配
|
||||||
|
// 移动端:1列
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.container {
|
.container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -395,7 +406,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.examGrid {
|
.examGrid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr; // 移动端显示1列
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,7 +483,7 @@
|
|||||||
|
|
||||||
.examStats {
|
.examStats {
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
gap: 10px;
|
gap: 6px;
|
||||||
|
|
||||||
.statItem {
|
.statItem {
|
||||||
.valueTag {
|
.valueTag {
|
||||||
@ -571,6 +582,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 平板端:2列
|
||||||
|
@media (min-width: 769px) and (max-width: 1024px) {
|
||||||
|
.examGrid {
|
||||||
|
grid-template-columns: repeat(2, 1fr); // 平板显示2列
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.container {
|
.container {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
|||||||
@ -368,22 +368,6 @@ const ExamManagement: React.FC = () => {
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<div className={styles.cardContent}>
|
<div className={styles.cardContent}>
|
||||||
<div className={styles.examInfo}>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<ClockCircleOutlined className={styles.infoIcon} />
|
|
||||||
<span className={styles.infoText}>{exam.duration} 分钟</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<CheckCircleOutlined className={styles.infoIcon} />
|
|
||||||
<span className={styles.infoText}>及格 {exam.pass_score} 分</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<FileTextOutlined className={styles.infoIcon} />
|
|
||||||
<span className={styles.infoText}>{exam.question_count || 0} 题</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Divider className={styles.divider} />
|
|
||||||
|
|
||||||
<div className={styles.examStats}>
|
<div className={styles.examStats}>
|
||||||
<div className={styles.statItem}>
|
<div className={styles.statItem}>
|
||||||
@ -400,7 +384,7 @@ const ExamManagement: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
{exam.participant_count > 0 && (
|
{exam.participant_count > 0 && (
|
||||||
<div className={styles.statItem}>
|
<div className={styles.statItem}>
|
||||||
<Tag color="blue" className={styles.participantTag}>
|
<Tag className={styles.valueTag}>
|
||||||
<TeamOutlined />
|
<TeamOutlined />
|
||||||
<span>{exam.participant_count} 人参与</span>
|
<span>{exam.participant_count} 人参与</span>
|
||||||
</Tag>
|
</Tag>
|
||||||
|
|||||||
@ -348,6 +348,16 @@ const ExamResultNew: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
{/* 顶部返回按钮 */}
|
||||||
|
<div style={{ marginBottom: 16 }}>
|
||||||
|
<Button
|
||||||
|
icon={<LeftOutlined />}
|
||||||
|
onClick={() => navigate(-1)}
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 成绩展示 */}
|
{/* 成绩展示 */}
|
||||||
<Result
|
<Result
|
||||||
status={isPassed ? "success" : "warning"}
|
status={isPassed ? "success" : "warning"}
|
||||||
@ -359,6 +369,29 @@ const ExamResultNew: React.FC = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
|
extra={
|
||||||
|
!isPassed && record.exam?.id ? (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
icon={<FileTextOutlined />}
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
const res = await examApi.startExam(record.exam!.id);
|
||||||
|
if (res.success && res.data) {
|
||||||
|
navigate(`/exam/${record.exam!.id}/taking/${res.data.record_id}`);
|
||||||
|
} else {
|
||||||
|
message.error(res.message || "开始考试失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
message.error("开始考试失败");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
再考一次
|
||||||
|
</Button>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 成绩统计 */}
|
{/* 成绩统计 */}
|
||||||
@ -548,39 +581,6 @@ const ExamResultNew: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* 操作按钮 */}
|
|
||||||
<Card className={styles.actionsCard}>
|
|
||||||
<Space size="large">
|
|
||||||
<Button
|
|
||||||
size="large"
|
|
||||||
icon={<LeftOutlined />}
|
|
||||||
onClick={() => navigate("/exam/management")}
|
|
||||||
>
|
|
||||||
返回
|
|
||||||
</Button>
|
|
||||||
{record.exam?.id && (
|
|
||||||
<Button
|
|
||||||
size="large"
|
|
||||||
icon={<FileTextOutlined />}
|
|
||||||
onClick={async () => {
|
|
||||||
try {
|
|
||||||
const res = await examApi.startExam(record.exam!.id);
|
|
||||||
if (res.success && res.data) {
|
|
||||||
navigate(
|
|
||||||
`/exam/${record.exam!.id}/taking/${res.data.record_id}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message.error("开始考试失败");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
再考一次
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user