后台基本功能完成,待完善:普通用户前端页面
This commit is contained in:
@@ -85,3 +85,80 @@
|
||||
.bg-mars {
|
||||
background-color: #008C8C;
|
||||
}
|
||||
|
||||
.qt-text-import-th-content,
|
||||
.qt-text-import-td-content {
|
||||
width: 850px !important;
|
||||
min-width: 850px !important;
|
||||
max-width: 850px !important;
|
||||
}
|
||||
|
||||
.qt-text-import-th-analysis,
|
||||
.qt-text-import-td-analysis {
|
||||
width: 320px !important;
|
||||
min-width: 320px !important;
|
||||
max-width: 320px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.qt-text-import-th-content,
|
||||
.qt-text-import-td-content {
|
||||
width: 600px !important;
|
||||
min-width: 600px !important;
|
||||
max-width: 600px !important;
|
||||
}
|
||||
|
||||
.qt-text-import-th-analysis,
|
||||
.qt-text-import-td-analysis {
|
||||
width: 260px !important;
|
||||
min-width: 260px !important;
|
||||
max-width: 260px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.qt-text-import-th-content,
|
||||
.qt-text-import-td-content {
|
||||
width: 360px !important;
|
||||
min-width: 360px !important;
|
||||
max-width: 360px !important;
|
||||
}
|
||||
|
||||
.qt-text-import-th-analysis,
|
||||
.qt-text-import-td-analysis {
|
||||
width: 220px !important;
|
||||
min-width: 220px !important;
|
||||
max-width: 220px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.qt-text-import-th-content,
|
||||
.qt-text-import-td-content {
|
||||
width: 260px !important;
|
||||
min-width: 260px !important;
|
||||
max-width: 260px !important;
|
||||
}
|
||||
|
||||
.qt-text-import-th-analysis,
|
||||
.qt-text-import-td-analysis {
|
||||
width: 180px !important;
|
||||
min-width: 180px !important;
|
||||
max-width: 180px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-question-count-td {
|
||||
text-align: center !important;
|
||||
vertical-align: middle;
|
||||
padding: 8px 12px !important;
|
||||
}
|
||||
|
||||
.qc-question-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 90px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Button, Input, Space, message, Popconfirm, Modal, Form, Tag } from 'antd';
|
||||
import { Table, Button, Input, Space, message, Popconfirm, Modal, Form, Tag, Tooltip } from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import api from '../../services/api';
|
||||
@@ -9,6 +9,7 @@ interface QuestionCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
questionCount?: number;
|
||||
}
|
||||
|
||||
const QuestionCategoryPage = () => {
|
||||
@@ -93,6 +94,22 @@ const QuestionCategoryPage = () => {
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<Tooltip title="该类别下题目数量(按题目表 category 统计)">
|
||||
<span>题库数量</span>
|
||||
</Tooltip>
|
||||
),
|
||||
dataIndex: 'questionCount',
|
||||
key: 'questionCount',
|
||||
align: 'center' as const,
|
||||
width: 120,
|
||||
className: 'qc-question-count-td',
|
||||
sorter: (a: QuestionCategory, b: QuestionCategory) => (a.questionCount ?? 0) - (b.questionCount ?? 0),
|
||||
render: (count: number | undefined) => (
|
||||
<div className="qc-question-count">{count ?? 0}</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
@@ -172,4 +189,4 @@ const QuestionCategoryPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default QuestionCategoryPage;
|
||||
export default QuestionCategoryPage;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { Alert, Button, Card, Input, Modal, Radio, Space, Table, Tag, Typography, message } from 'antd';
|
||||
import { Alert, Button, Card, Input, Modal, Radio, Space, Statistic, Table, Tag, Typography, message } from 'antd';
|
||||
import { ArrowLeftOutlined, DeleteOutlined, FileTextOutlined, ImportOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { questionAPI } from '../../services/api';
|
||||
@@ -16,6 +16,7 @@ const QuestionTextImportPage = () => {
|
||||
const [parseErrors, setParseErrors] = useState<string[]>([]);
|
||||
const [questions, setQuestions] = useState<ImportQuestion[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [tablePagination, setTablePagination] = useState({ current: 1, pageSize: 10 });
|
||||
|
||||
const exampleText = [
|
||||
'题型|题目类别|分值|题目内容|选项|答案|解析',
|
||||
@@ -29,6 +30,7 @@ const QuestionTextImportPage = () => {
|
||||
const result = parseTextQuestions(rawText);
|
||||
setParseErrors(result.errors);
|
||||
setQuestions(result.questions);
|
||||
setTablePagination((prev) => ({ ...prev, current: 1 }));
|
||||
if (result.questions.length === 0) {
|
||||
message.error(result.errors.length ? '解析失败,请检查格式' : '未解析到任何题目');
|
||||
return;
|
||||
@@ -44,6 +46,11 @@ const QuestionTextImportPage = () => {
|
||||
setQuestions((prev) => prev.filter((_, i) => i !== idx));
|
||||
};
|
||||
|
||||
const indexBase = (tablePagination.current - 1) * tablePagination.pageSize;
|
||||
const totalCount = questions.length + parseErrors.length;
|
||||
const validCount = questions.length;
|
||||
const invalidCount = parseErrors.length;
|
||||
|
||||
const handleImport = async () => {
|
||||
if (questions.length === 0) return;
|
||||
Modal.confirm({
|
||||
@@ -72,13 +79,16 @@ const QuestionTextImportPage = () => {
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
render: (_: any, __: any, index: number) => index + 1,
|
||||
render: (_: any, __: any, index: number) => indexBase + index + 1,
|
||||
},
|
||||
{
|
||||
title: '题目内容',
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
width: 850,
|
||||
ellipsis: true,
|
||||
onHeaderCell: () => ({ className: 'qt-text-import-th-content' }),
|
||||
onCell: () => ({ className: 'qt-text-import-td-content' }),
|
||||
},
|
||||
{
|
||||
title: '题型',
|
||||
@@ -116,8 +126,10 @@ const QuestionTextImportPage = () => {
|
||||
title: '解析',
|
||||
dataIndex: 'analysis',
|
||||
key: 'analysis',
|
||||
width: 220,
|
||||
width: 320,
|
||||
ellipsis: true,
|
||||
onHeaderCell: () => ({ className: 'qt-text-import-th-analysis' }),
|
||||
onCell: () => ({ className: 'qt-text-import-td-analysis' }),
|
||||
render: (analysis: ImportQuestion['analysis']) => (
|
||||
<span>
|
||||
<Tag color="blue">解析</Tag>
|
||||
@@ -130,7 +142,7 @@ const QuestionTextImportPage = () => {
|
||||
key: 'action',
|
||||
width: 80,
|
||||
render: (_: any, __: any, index: number) => (
|
||||
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleRemove(index)} />
|
||||
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleRemove(indexBase + index)} />
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -166,14 +178,25 @@ const QuestionTextImportPage = () => {
|
||||
|
||||
<Card className="shadow-sm mb-4">
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<Space>
|
||||
<Button icon={<FileTextOutlined />} onClick={() => setRawText(exampleText)}>
|
||||
填充示例
|
||||
</Button>
|
||||
<Button type="primary" onClick={handleParse} disabled={!rawText.trim()}>
|
||||
解析文本
|
||||
</Button>
|
||||
</Space>
|
||||
<div className="flex items-center justify-between">
|
||||
<Space>
|
||||
<Button icon={<FileTextOutlined />} onClick={() => setRawText(exampleText)}>
|
||||
填充示例
|
||||
</Button>
|
||||
<Button type="primary" onClick={handleParse} disabled={!rawText.trim()}>
|
||||
解析文本
|
||||
</Button>
|
||||
</Space>
|
||||
<Space size="large">
|
||||
<Statistic title="本次导入题目总数" value={totalCount} valueStyle={{ color: '#1677ff', fontWeight: 700 }} />
|
||||
<Statistic title="有效题目数量" value={validCount} valueStyle={{ color: '#52c41a', fontWeight: 700 }} />
|
||||
<Statistic
|
||||
title="无效题目数量"
|
||||
value={invalidCount}
|
||||
valueStyle={{ color: invalidCount > 0 ? '#ff4d4f' : '#8c8c8c', fontWeight: 700 }}
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<TextArea
|
||||
value={rawText}
|
||||
@@ -203,7 +226,15 @@ const QuestionTextImportPage = () => {
|
||||
<Table
|
||||
columns={columns as any}
|
||||
dataSource={questions.map((q, idx) => ({ ...q, key: `${q.content}-${idx}` }))}
|
||||
pagination={{ pageSize: 10, showSizeChanger: true }}
|
||||
pagination={{ ...tablePagination, showSizeChanger: true }}
|
||||
tableLayout="fixed"
|
||||
scroll={{ x: 1800 }}
|
||||
onChange={(pagination) =>
|
||||
setTablePagination({
|
||||
current: pagination.current ?? 1,
|
||||
pageSize: pagination.pageSize ?? 10,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user