feat: 添加LOGO文件,修改考试界面的比例
添加多个LOGO文件,修改用户看到的考试界面的比例,并且调整了部分元素尺寸
This commit is contained in:
@@ -4,7 +4,8 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { useUser } from '../contexts';
|
||||
import { userAPI } from '../services/api';
|
||||
import { validateUserForm } from '../utils/validation';
|
||||
import { Logo } from '../components/common/Logo';
|
||||
import 主要LOGO from '../assets/主要LOGO.svg';
|
||||
import 纯字母LOGO from '../assets/纯字母LOGO.svg';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
const { Title } = Typography;
|
||||
@@ -120,7 +121,7 @@ const HomePage = () => {
|
||||
return (
|
||||
<Layout className="min-h-screen bg-gray-50">
|
||||
<Header className="bg-white shadow-sm flex items-center px-6 h-16 sticky top-0 z-10">
|
||||
<Logo variant="primary" />
|
||||
<img src={主要LOGO} alt="主要LOGO" style={{ width: '180px', height: '72px' }} />
|
||||
</Header>
|
||||
|
||||
<Content className="flex items-center justify-center p-4 bg-gradient-to-br from-mars-50 to-white">
|
||||
@@ -219,7 +220,7 @@ const HomePage = () => {
|
||||
<div className="mb-4 md:mb-0">
|
||||
© {new Date().getFullYear()} Boonlive OA System. All Rights Reserved.
|
||||
</div>
|
||||
<Logo variant="secondary" />
|
||||
<img src={纯字母LOGO} alt="纯字母LOGO" style={{ width: '136px', height: '51px' }} />
|
||||
</Footer>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -450,7 +450,7 @@ const QuizPage = () => {
|
||||
/>
|
||||
|
||||
<div className="flex-1 overflow-y-auto pb-24 safe-area-bottom">
|
||||
<div className="max-w-4xl mx-auto p-4">
|
||||
<div className="max-w-md mx-auto px-4">
|
||||
<div
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
@@ -464,13 +464,13 @@ const QuizPage = () => {
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-100 p-5 md:p-8 min-h-[400px]">
|
||||
<div className="mb-6">
|
||||
<span className={`inline-block px-3 py-1 rounded-md text-sm font-medium border ${getTagColor(currentQuestion.type)}`}>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-100 p-4 min-h-[350px]">
|
||||
<div className="mb-4">
|
||||
<span className={`inline-block px-2 py-0.5 rounded-md text-xs font-medium border ${getTagColor(currentQuestion.type)}`}>
|
||||
{questionTypeMap[currentQuestion.type]}
|
||||
</span>
|
||||
{currentQuestion.category && (
|
||||
<span className="ml-2 inline-block px-2 py-1 bg-gray-50 text-gray-600 text-xs rounded border border-gray-100">
|
||||
<span className="ml-2 inline-block px-1.5 py-0.5 bg-gray-50 text-gray-600 text-xs rounded border border-gray-100">
|
||||
{currentQuestion.category}
|
||||
</span>
|
||||
)}
|
||||
@@ -479,7 +479,7 @@ const QuizPage = () => {
|
||||
<h2
|
||||
ref={questionHeadingRef}
|
||||
tabIndex={-1}
|
||||
className="text-lg md:text-xl font-medium text-gray-900 leading-relaxed mb-8 outline-none"
|
||||
className="text-base font-medium text-gray-900 leading-relaxed mb-6 outline-none"
|
||||
>
|
||||
{currentQuestion.content}
|
||||
</h2>
|
||||
@@ -511,28 +511,28 @@ const QuizPage = () => {
|
||||
onCancel={() => setAnswerSheetOpen(false)}
|
||||
footer={null}
|
||||
centered
|
||||
width={560}
|
||||
width={340}
|
||||
destroyOnClose
|
||||
>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="text-sm text-gray-700">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="text-xs text-gray-700">
|
||||
已答 <span className="text-[#00897B] font-medium">{answeredCount}</span> / {questions.length}
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => setAnswerSheetOpen(false)}
|
||||
className="bg-[#00897B] hover:bg-[#00796B]"
|
||||
className="bg-[#00897B] hover:bg-[#00796B] text-xs h-7 px-3"
|
||||
>
|
||||
回到当前题
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-5 sm:grid-cols-6 gap-3">
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{questions.map((q, idx) => {
|
||||
const isCurrent = idx === currentQuestionIndex;
|
||||
const isAnswered = !!answers[q.id];
|
||||
|
||||
let className = 'h-10 w-10 rounded-full flex items-center justify-center text-sm font-medium border transition-colors ';
|
||||
let className = 'h-9 w-9 rounded-full flex items-center justify-center text-xs font-medium border transition-colors ';
|
||||
if (isCurrent) {
|
||||
className += 'border-[#00897B] bg-[#E0F2F1] text-[#00695C]';
|
||||
} else if (isAnswered) {
|
||||
|
||||
@@ -155,10 +155,10 @@ const ResultPage = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<UserLayout>
|
||||
<div className="flex justify-center items-center h-full min-h-[500px]">
|
||||
<div className="flex justify-center items-center h-full min-h-[400px]">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-mars-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-600">正在加载答题结果...</p>
|
||||
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-mars-600 mx-auto mb-3"></div>
|
||||
<p className="text-gray-600 text-sm">正在加载答题结果...</p>
|
||||
</div>
|
||||
</div>
|
||||
</UserLayout>
|
||||
@@ -168,10 +168,10 @@ const ResultPage = () => {
|
||||
if (!record) {
|
||||
return (
|
||||
<UserLayout>
|
||||
<div className="flex justify-center items-center h-full min-h-[500px]">
|
||||
<div className="flex justify-center items-center h-full min-h-[400px]">
|
||||
<div className="text-center">
|
||||
<p className="text-gray-600 mb-4">答题记录不存在</p>
|
||||
<Button type="primary" onClick={handleBackToHome} className="bg-mars-500 hover:bg-mars-600">
|
||||
<p className="text-gray-600 mb-4 text-sm">答题记录不存在</p>
|
||||
<Button type="primary" onClick={handleBackToHome} className="bg-mars-500 hover:bg-mars-600 text-sm">
|
||||
返回首页
|
||||
</Button>
|
||||
</div>
|
||||
@@ -185,15 +185,15 @@ const ResultPage = () => {
|
||||
|
||||
return (
|
||||
<UserLayout>
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="max-w-md mx-auto px-4">
|
||||
{/* 结果概览 */}
|
||||
<Card className="shadow-lg mb-8 rounded-xl border-t-4 border-t-mars-500">
|
||||
<Card className="shadow-lg mb-6 rounded-xl border-t-4 border-t-mars-500">
|
||||
<Result
|
||||
status={status as any}
|
||||
title={`答题完成!您的得分是 ${record.totalScore} 分`}
|
||||
subTitle={`正确率 ${correctRate}% (${record.correctCount}/${record.totalCount})`}
|
||||
extra={[
|
||||
<Button key="back" type="primary" onClick={handleBackToHome} className="bg-mars-500 hover:bg-mars-600 border-none px-8 h-10">
|
||||
<Button key="back" type="primary" onClick={handleBackToHome} className="bg-mars-500 hover:bg-mars-600 border-none px-6 h-9 text-sm">
|
||||
返回首页
|
||||
</Button>
|
||||
]}
|
||||
@@ -201,9 +201,9 @@ const ResultPage = () => {
|
||||
</Card>
|
||||
|
||||
{/* 基本信息 */}
|
||||
<Card className="shadow-lg mb-8 rounded-xl">
|
||||
<h3 className="text-lg font-semibold mb-4 text-gray-800 border-l-4 border-mars-500 pl-3">答题信息</h3>
|
||||
<Descriptions bordered column={2}>
|
||||
<Card className="shadow-lg mb-6 rounded-xl">
|
||||
<h3 className="text-base font-semibold mb-3 text-gray-800 border-l-4 border-mars-500 pl-3">答题信息</h3>
|
||||
<Descriptions bordered column={1} size="small">
|
||||
<Item label="姓名">{user?.name}</Item>
|
||||
<Item label="手机号">{user?.phone}</Item>
|
||||
<Item label="答题时间">{formatDateTime(record.createdAt)}</Item>
|
||||
@@ -215,30 +215,30 @@ const ResultPage = () => {
|
||||
|
||||
{/* 答案详情 */}
|
||||
<Card className="shadow-lg rounded-xl">
|
||||
<h3 className="text-lg font-semibold mb-4 text-gray-800 border-l-4 border-mars-500 pl-3">答案详情</h3>
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-base font-semibold mb-3 text-gray-800 border-l-4 border-mars-500 pl-3">答案详情</h3>
|
||||
<div className="space-y-3">
|
||||
{answers.map((answer, index) => (
|
||||
<div
|
||||
key={answer.id}
|
||||
className={`p-4 rounded-lg border ${
|
||||
className={`p-3 rounded-lg border ${
|
||||
answer.isCorrect
|
||||
? 'border-green-200 bg-green-50/50'
|
||||
: 'border-red-200 bg-red-50/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-gray-800">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-medium text-gray-800 text-sm">
|
||||
第 {index + 1} 题
|
||||
</span>
|
||||
<span className={`${getTagColor(answer.questionType || '')} px-2 py-0.5 rounded text-xs`}>
|
||||
<span className={`${getTagColor(answer.questionType || '')} px-1.5 py-0.5 rounded text-xs`}>
|
||||
{answer.questionType === 'single' ? '单选题' :
|
||||
answer.questionType === 'multiple' ? '多选题' :
|
||||
answer.questionType === 'judgment' ? '判断题' : '简答题'}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={`px-2 py-1 rounded text-sm ${
|
||||
className={`px-1.5 py-0.5 rounded text-xs ${
|
||||
answer.isCorrect
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
@@ -247,28 +247,28 @@ const ResultPage = () => {
|
||||
{answer.isCorrect ? '正确' : '错误'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<span className="text-gray-600">题目:</span>
|
||||
<span className="text-gray-800 font-medium">{answer.questionContent || '题目内容加载失败'}</span>
|
||||
<div className="mb-1.5">
|
||||
<span className="text-gray-600 text-xs">题目:</span>
|
||||
<span className="text-gray-800 font-medium text-sm">{answer.questionContent || '题目内容加载失败'}</span>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<span className="text-gray-600">您的答案:</span>
|
||||
<div className="mb-1.5">
|
||||
<span className="text-gray-600 text-xs">您的答案:</span>
|
||||
{renderUserAnswer(answer)}
|
||||
</div>
|
||||
{!answer.isCorrect && (
|
||||
<div className="mb-2">
|
||||
<span className="text-gray-600">正确答案:</span>
|
||||
<div className="mb-1.5">
|
||||
<span className="text-gray-600 text-xs">正确答案:</span>
|
||||
{renderCorrectAnswer(answer)}
|
||||
</div>
|
||||
)}
|
||||
{String(answer.questionAnalysis ?? '').trim() ? (
|
||||
<div className="mb-2">
|
||||
<span className="text-gray-600">解析:</span>
|
||||
<span className="text-gray-800 whitespace-pre-wrap">{answer.questionAnalysis}</span>
|
||||
<div className="mb-1.5">
|
||||
<span className="text-gray-600 text-xs">解析:</span>
|
||||
<span className="text-gray-800 whitespace-pre-wrap text-sm">{answer.questionAnalysis}</span>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mb-2 pt-2 border-t border-gray-100 mt-2">
|
||||
<span className="text-gray-500 text-sm">
|
||||
<div className="mb-1 pt-1.5 border-t border-gray-100 mt-1.5">
|
||||
<span className="text-gray-500 text-xs">
|
||||
本题分值:{answer.questionScore || 0} 分,你的得分:<span className="font-medium text-gray-800">{answer.score}</span> 分
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -136,25 +136,25 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<UserLayout>
|
||||
<div className="container mx-auto max-w-6xl">
|
||||
<div className="mb-8 text-center">
|
||||
<Title level={2} className="!text-mars-600 mb-2">
|
||||
<div className="container mx-auto px-4 max-w-md">
|
||||
<div className="mb-4 text-center">
|
||||
<Title level={3} className="!text-mars-600 mb-1 !text-lg">
|
||||
选择考试科目
|
||||
</Title>
|
||||
<Text type="secondary" className="block text-lg">
|
||||
<Text type="secondary" className="block text-sm">
|
||||
请选择您要参加的考试科目或考试任务
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{/* 考试科目选择 */}
|
||||
<div>
|
||||
<div className="flex items-center mb-6 border-b border-gray-200 pb-2">
|
||||
<BookOutlined className="text-2xl mr-3 text-mars-600" />
|
||||
<Title level={3} className="!mb-0 !text-gray-700">考试科目</Title>
|
||||
<div className="flex items-center mb-3 border-b border-gray-200 pb-1">
|
||||
<BookOutlined className="text-lg mr-2 text-mars-600" />
|
||||
<Title level={4} className="!mb-0 !text-gray-700 !text-base">考试科目</Title>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
{subjects.map((subject) => (
|
||||
<Card
|
||||
key={subject.id}
|
||||
@@ -170,28 +170,28 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="flex-1">
|
||||
<Title level={4} className={`mb-2 ${selectedSubject === subject.id ? 'text-mars-700' : 'text-gray-800'}`}>
|
||||
<Title level={5} className={`mb-1 ${selectedSubject === subject.id ? 'text-mars-700' : 'text-gray-800'} !text-sm`}>
|
||||
{subject.name}
|
||||
</Title>
|
||||
<Space direction="vertical" size="small" className="mb-3">
|
||||
<Space direction="vertical" size="small" className="mb-2">
|
||||
<div className="flex items-center">
|
||||
<ClockCircleOutlined className="mr-2 text-gray-400" />
|
||||
<Text className="text-gray-600">{subject.timeLimitMinutes}分钟</Text>
|
||||
<ClockCircleOutlined className="mr-1 text-gray-400 text-xs" />
|
||||
<Text className="text-gray-600 text-xs">{subject.timeLimitMinutes}分钟</Text>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 text-gray-400">总分:</span>
|
||||
<Text strong className="text-gray-700">{subject.totalScore}分</Text>
|
||||
<span className="mr-1 text-gray-400 text-xs">总分:</span>
|
||||
<Text strong className="text-gray-700 text-xs">{subject.totalScore}分</Text>
|
||||
</div>
|
||||
</Space>
|
||||
<div className="text-sm text-gray-500 bg-gray-50 p-2 rounded">
|
||||
<div className="mb-1 font-medium">题型分布:</div>
|
||||
<div>{formatTypeRatio(subject.typeRatios)}</div>
|
||||
<div className="text-xs text-gray-500 bg-gray-50 p-1.5 rounded">
|
||||
<div className="mb-0.5 font-medium text-xs">题型分布:</div>
|
||||
<div className="text-xs">{formatTypeRatio(subject.typeRatios)}</div>
|
||||
</div>
|
||||
</div>
|
||||
{selectedSubject === subject.id && (
|
||||
<div className="text-mars-600">
|
||||
<div className="w-8 h-8 bg-mars-500 rounded-full flex items-center justify-center shadow-sm">
|
||||
<span className="text-white text-lg font-bold">✓</span>
|
||||
<div className="w-6 h-6 bg-mars-500 rounded-full flex items-center justify-center shadow-sm">
|
||||
<span className="text-white text-sm font-bold">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -203,12 +203,12 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
|
||||
{/* 考试任务选择 */}
|
||||
<div>
|
||||
<div className="flex items-center mb-6 border-b border-gray-200 pb-2">
|
||||
<UserOutlined className="text-2xl mr-3 text-mars-400" />
|
||||
<Title level={3} className="!mb-0 !text-gray-700">考试任务</Title>
|
||||
<div className="flex items-center mb-3 border-b border-gray-200 pb-1">
|
||||
<UserOutlined className="text-lg mr-2 text-mars-400" />
|
||||
<Title level={4} className="!mb-0 !text-gray-700 !text-base">考试任务</Title>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
{tasks.map((task) => {
|
||||
const subject = subjects.find(s => s.id === task.subjectId);
|
||||
const usedAttempts = Number(task.usedAttempts) || 0;
|
||||
@@ -230,41 +230,41 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="flex-1">
|
||||
<Title level={4} className={`mb-2 ${selectedTask === task.id ? 'text-mars-700' : 'text-gray-800'}`}>
|
||||
<Title level={5} className={`mb-1 ${selectedTask === task.id ? 'text-mars-700' : 'text-gray-800'} !text-sm`}>
|
||||
{task.name}
|
||||
</Title>
|
||||
<div className="mb-2">
|
||||
<Tag color={attemptsExhausted ? 'red' : 'blue'}>
|
||||
<Tag color={attemptsExhausted ? 'red' : 'blue'} className="text-xs">
|
||||
{usedAttempts}/{maxAttempts}
|
||||
</Tag>
|
||||
{typeof task.bestScore === 'number' ? (
|
||||
<Tag color="green">最高分 {task.bestScore} 分</Tag>
|
||||
<Tag color="green" className="text-xs">最高分 {task.bestScore} 分</Tag>
|
||||
) : null}
|
||||
{attemptsExhausted ? <Tag color="red">次数用尽</Tag> : null}
|
||||
{attemptsExhausted ? <Tag color="red" className="text-xs">次数用尽</Tag> : null}
|
||||
</div>
|
||||
<Space direction="vertical" size="small" className="mb-3">
|
||||
<Space direction="vertical" size="small" className="mb-2">
|
||||
<div className="flex items-center">
|
||||
<BookOutlined className="mr-2 text-gray-400" />
|
||||
<Text className="text-gray-600">{subject?.name || '未知科目'}</Text>
|
||||
<BookOutlined className="mr-1 text-gray-400 text-xs" />
|
||||
<Text className="text-gray-600 text-xs">{subject?.name || '未知科目'}</Text>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<ClockCircleOutlined className="mr-2 text-gray-400" />
|
||||
<Text className="text-gray-600">
|
||||
<ClockCircleOutlined className="mr-1 text-gray-400 text-xs" />
|
||||
<Text className="text-gray-600 text-xs">
|
||||
{new Date(task.startAt).toLocaleDateString()} - {new Date(task.endAt).toLocaleDateString()}
|
||||
</Text>
|
||||
</div>
|
||||
{subject && (
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 text-gray-400">时长:</span>
|
||||
<Text className="text-gray-600">{subject.timeLimitMinutes}分钟</Text>
|
||||
<span className="mr-1 text-gray-400 text-xs">时长:</span>
|
||||
<Text className="text-gray-600 text-xs">{subject.timeLimitMinutes}分钟</Text>
|
||||
</div>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
{selectedTask === task.id && (
|
||||
<div className="text-mars-400">
|
||||
<div className="w-8 h-8 bg-mars-400 rounded-full flex items-center justify-center shadow-sm">
|
||||
<span className="text-white text-lg font-bold">✓</span>
|
||||
<div className="w-6 h-6 bg-mars-400 rounded-full flex items-center justify-center shadow-sm">
|
||||
<span className="text-white text-sm font-bold">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -275,18 +275,18 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{tasks.length === 0 && (
|
||||
<Card className="text-center py-12 bg-gray-50 border-dashed border-2 border-gray-200">
|
||||
<Text type="secondary" className="text-lg">暂无可用考试任务</Text>
|
||||
<Card className="text-center py-8 bg-gray-50 border-dashed border-2 border-gray-200">
|
||||
<Text type="secondary" className="text-sm">暂无可用考试任务</Text>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center space-x-6">
|
||||
<div className="mt-6 text-center space-x-3">
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="px-12 h-14 text-lg font-medium shadow-lg hover:scale-105 transition-transform bg-mars-500 hover:bg-mars-600 border-none"
|
||||
className="px-6 h-10 text-sm font-medium shadow-lg hover:scale-105 transition-transform bg-mars-500 hover:bg-mars-600 border-none"
|
||||
onClick={startQuiz}
|
||||
disabled={!selectedSubject && !selectedTask}
|
||||
>
|
||||
@@ -295,7 +295,7 @@ export const SubjectSelectionPage: React.FC = () => {
|
||||
<Button
|
||||
type="default"
|
||||
size="large"
|
||||
className="px-8 h-14 text-lg hover:border-mars-500 hover:text-mars-500"
|
||||
className="px-4 h-10 text-sm hover:border-mars-500 hover:text-mars-500"
|
||||
onClick={() => navigate('/tasks')}
|
||||
icon={<UserOutlined />}
|
||||
>
|
||||
|
||||
@@ -204,12 +204,12 @@ export const UserTaskPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<UserLayout>
|
||||
<div className="container mx-auto max-w-6xl">
|
||||
<div className="mb-8 text-center">
|
||||
<Title level={2} className="!text-mars-600 mb-2">
|
||||
<div className="container mx-auto px-4 max-w-md">
|
||||
<div className="mb-4 text-center">
|
||||
<Title level={3} className="!text-mars-600 mb-1 !text-lg">
|
||||
我的考试任务
|
||||
</Title>
|
||||
<Text type="secondary" className="block text-lg">
|
||||
<Text type="secondary" className="block text-sm">
|
||||
查看您被分派的所有考试任务
|
||||
</Text>
|
||||
</div>
|
||||
@@ -220,23 +220,25 @@ export const UserTaskPage: React.FC = () => {
|
||||
dataSource={tasks}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `共 ${total} 条记录`
|
||||
pageSize: 5,
|
||||
showSizeChanger: false,
|
||||
showTotal: (total) => `共 ${total} 条`
|
||||
}}
|
||||
locale={{
|
||||
emptyText: '暂无考试任务'
|
||||
}}
|
||||
size="small"
|
||||
scroll={{ x: 'max-content' }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<div className="mt-8 text-center">
|
||||
<div className="mt-6 text-center">
|
||||
<Button
|
||||
type="default"
|
||||
size="large"
|
||||
onClick={() => navigate('/subjects')}
|
||||
icon={<BookOutlined />}
|
||||
className="px-8 h-12 hover:border-mars-500 hover:text-mars-500"
|
||||
className="px-6 h-10 text-sm hover:border-mars-500 hover:text-mars-500"
|
||||
>
|
||||
返回科目选择
|
||||
</Button>
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Card, Form, Input, Button, message, Select, Layout } from 'antd';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAdmin } from '../../contexts';
|
||||
import { adminAPI } from '../../services/api';
|
||||
import { Logo } from '../../components/common/Logo';
|
||||
import 主要LOGO from '../../assets/主要LOGO.svg';
|
||||
import 纯字母LOGO from '../../assets/纯字母LOGO.svg';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
|
||||
@@ -95,7 +96,7 @@ const AdminLoginPage = () => {
|
||||
return (
|
||||
<Layout className="min-h-screen bg-gray-50">
|
||||
<Header className="bg-white shadow-sm flex items-center px-6 h-16 sticky top-0 z-10">
|
||||
<Logo variant="primary" />
|
||||
<img src={主要LOGO} alt="主要LOGO" style={{ width: '180px', height: '72px' }} />
|
||||
</Header>
|
||||
|
||||
<Content className="flex items-center justify-center p-4 bg-gradient-to-br from-mars-50 to-white">
|
||||
@@ -201,7 +202,7 @@ const AdminLoginPage = () => {
|
||||
<div className="mb-4 md:mb-0">
|
||||
© {new Date().getFullYear()} Boonlive OA System. All Rights Reserved.
|
||||
</div>
|
||||
<Logo variant="secondary" />
|
||||
<img src={纯字母LOGO} alt="纯字母LOGO" style={{ width: '136px', height: '51px' }} />
|
||||
</Footer>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -36,14 +36,14 @@ export const OptionList = ({ type, options, value, onChange, disabled }: OptionL
|
||||
|
||||
if (type === 'text') {
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<div className="mt-3">
|
||||
<TextArea
|
||||
rows={6}
|
||||
rows={5}
|
||||
value={value as string || ''}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder="请输入您的答案..."
|
||||
disabled={disabled}
|
||||
className="rounded-lg border-gray-300 focus:border-[#00897B] focus:ring-[#00897B] text-base p-4"
|
||||
className="rounded-lg border-gray-300 focus:border-[#00897B] focus:ring-[#00897B] text-sm p-3"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -57,7 +57,7 @@ export const OptionList = ({ type, options, value, onChange, disabled }: OptionL
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3 mt-2">
|
||||
<div className="space-y-2.5 mt-2">
|
||||
{renderOptions().map((opt, index) => {
|
||||
const selected = isSelected(opt.value);
|
||||
return (
|
||||
@@ -65,7 +65,7 @@ export const OptionList = ({ type, options, value, onChange, disabled }: OptionL
|
||||
key={opt.key}
|
||||
onClick={() => handleSelect(opt.value)}
|
||||
className={`
|
||||
relative flex items-start p-4 rounded-xl border-2 transition-all duration-200 active:scale-[0.99] cursor-pointer
|
||||
relative flex items-start p-3 rounded-xl border-2 transition-all duration-200 active:scale-[0.99] cursor-pointer
|
||||
${selected
|
||||
? 'border-[#00897B] bg-[#E0F2F1]'
|
||||
: 'border-transparent bg-white shadow-sm hover:border-gray-200'}
|
||||
@@ -73,7 +73,7 @@ export const OptionList = ({ type, options, value, onChange, disabled }: OptionL
|
||||
>
|
||||
{/* 选项圆圈 */}
|
||||
<div className={`
|
||||
flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium border mr-3 mt-0.5 transition-colors
|
||||
flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-xs font-medium border mr-2.5 mt-0.5 transition-colors
|
||||
${selected
|
||||
? 'bg-[#00897B] border-[#00897B] text-white'
|
||||
: 'bg-white border-gray-300 text-gray-500'}
|
||||
@@ -82,7 +82,7 @@ export const OptionList = ({ type, options, value, onChange, disabled }: OptionL
|
||||
</div>
|
||||
|
||||
{/* 选项内容 */}
|
||||
<div className={`text-base leading-snug select-none ${selected ? 'text-[#00695C] font-medium' : 'text-gray-700'}`}>
|
||||
<div className={`text-sm leading-snug select-none ${selected ? 'text-[#00695C] font-medium' : 'text-gray-700'}`}>
|
||||
{opt.label}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,23 +24,23 @@ export const QuizFooter = ({
|
||||
const isLast = current === total - 1;
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 px-4 py-3 safe-area-bottom z-30 shadow-[0_-2px_10px_rgba(0,0,0,0.05)]">
|
||||
<div className="max-w-4xl mx-auto flex items-center justify-between">
|
||||
<div className="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 px-3 py-2.5 safe-area-bottom z-30 shadow-[0_-2px_10px_rgba(0,0,0,0.05)]">
|
||||
<div className="max-w-md mx-auto flex items-center justify-between">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<LeftOutlined />}
|
||||
onClick={onPrev}
|
||||
disabled={isFirst}
|
||||
className={`flex items-center text-gray-600 hover:text-[#00897B] ${isFirst ? 'opacity-30' : ''}`}
|
||||
className={`flex items-center text-gray-600 hover:text-[#00897B] text-sm ${isFirst ? 'opacity-30' : ''}`}
|
||||
>
|
||||
上一题
|
||||
</Button>
|
||||
|
||||
<div
|
||||
onClick={onOpenSheet}
|
||||
className="flex flex-col items-center justify-center -mt-8 bg-white rounded-full h-16 w-16 shadow-lg border border-gray-100 cursor-pointer active:scale-95 transition-transform"
|
||||
className="flex flex-col items-center justify-center -mt-6 bg-white rounded-full h-14 w-14 shadow-lg border border-gray-100 cursor-pointer active:scale-95 transition-transform"
|
||||
>
|
||||
<AppstoreOutlined className="text-xl text-[#00897B] mb-1" />
|
||||
<AppstoreOutlined className="text-lg text-[#00897B] mb-0.5" />
|
||||
<span className="text-[10px] text-gray-500 scale-90">
|
||||
{answeredCount}/{total}
|
||||
</span>
|
||||
@@ -50,7 +50,7 @@ export const QuizFooter = ({
|
||||
<Button
|
||||
type="text"
|
||||
onClick={onSubmit}
|
||||
className="flex items-center text-[#00897B] font-medium hover:bg-teal-50"
|
||||
className="flex items-center text-[#00897B] font-medium hover:bg-teal-50 text-sm"
|
||||
>
|
||||
提交 <RightOutlined />
|
||||
</Button>
|
||||
@@ -58,7 +58,7 @@ export const QuizFooter = ({
|
||||
<Button
|
||||
type="text"
|
||||
onClick={onNext}
|
||||
className="flex items-center text-gray-600 hover:text-[#00897B]"
|
||||
className="flex items-center text-gray-600 hover:text-[#00897B] text-sm"
|
||||
>
|
||||
下一题 <RightOutlined />
|
||||
</Button>
|
||||
|
||||
@@ -19,18 +19,18 @@ export const QuizHeader = ({ current, total, timeLeft, onGiveUp }: QuizHeaderPro
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-[#00897B] text-white px-4 h-14 flex items-center justify-between shadow-md sticky top-0 z-30">
|
||||
<div className="bg-[#00897B] text-white px-3 h-12 flex items-center justify-between shadow-md sticky top-0 z-30">
|
||||
<div className="flex items-center gap-1" onClick={onGiveUp}>
|
||||
<LeftOutlined className="text-lg" />
|
||||
<span className="text-base">返回</span>
|
||||
<LeftOutlined className="text-base" />
|
||||
<span className="text-sm">返回</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 bg-[#00796B] px-3 py-1 rounded-full text-sm">
|
||||
<div className="flex items-center gap-1.5 bg-[#00796B] px-2 py-0.5 rounded-full text-xs">
|
||||
<EyeOutlined />
|
||||
<span>监控中</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 text-base font-medium tabular-nums">
|
||||
<div className="flex items-center gap-1.5 text-sm font-medium tabular-nums">
|
||||
<ClockCircleOutlined />
|
||||
<span>{timeLeft !== null ? formatTime(timeLeft) : '--:--'}</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user