Skip to content

Commit 5a5a3d5

Browse files
author
CodeJudge
committed
feat: 提交状态分布图 + README徽章
1 parent 3de51ca commit 5a5a3d5

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
<div align="center">
2+
13
# CodeJudge - 在线评测系统
24

5+
[![GitHub stars](https://img.shields.io/github/stars/anyncfunction/codejudge?style=flat-square&logo=github)](https://github.com/anyncfunction/codejudge)
6+
[![GitHub license](https://img.shields.io/github/license/anyncfunction/codejudge?style=flat-square)](https://github.com/anyncfunction/codejudge/blob/main/LICENSE)
7+
[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
8+
[![React](https://img.shields.io/badge/React-18-61DAFB?style=flat-square&logo=react)](https://reactjs.org/)
9+
[![Express](https://img.shields.io/badge/Express-4.x-000000?style=flat-square&logo=express)](https://expressjs.com/)
10+
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
11+
312
一个现代化在线评测平台,支持**编程题****选择题****填空题**三种题型,对标 LeetCode 式体验。
413

14+
</div>
15+
516
## 特性
617

718
- **三种题型** — 编程题(在线编写代码运行判题)、选择题(选项匹配评分)、填空题(文本匹配判题)

frontend/src/pages/Profile.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState, useEffect } from 'react';
22
import { Link } from 'react-router-dom';
3-
import { User, Mail, Shield, Award, TrendingUp, Loader2, AlertTriangle, CheckCircle2, XCircle, Clock, Zap, Lock, Key, CalendarDays, Code } from 'lucide-react';
3+
import { User, Mail, Shield, Award, TrendingUp, Loader2, AlertTriangle, CheckCircle2, XCircle, Clock, Zap, Lock, Key, CalendarDays, Code, PieChart } from 'lucide-react';
44
import { useAuth } from '../context/AuthContext';
55
import api from '../services/api';
66
import type { Submission } from '../types';
@@ -51,6 +51,7 @@ export default function Profile() {
5151
const [passwordError, setPasswordError] = useState<string | null>(null);
5252
const [calendarDates, setCalendarDates] = useState<Set<string>>(new Set());
5353
const [languageStats, setLanguageStats] = useState<{language: string; count: number}[]>([]);
54+
const [submissionStatus, setSubmissionStatus] = useState<any[]>([]);
5455

5556
useEffect(() => {
5657
const token = localStorage.getItem('oj_token');
@@ -67,6 +68,15 @@ export default function Profile() {
6768
setLanguageStats(data.languages || []);
6869
})
6970
.catch(() => {});
71+
fetch('/api/submissions?page=1&limit=1000', { headers: { Authorization: `Bearer ${token}` } })
72+
.then(r => r.json())
73+
.then(data => {
74+
const submissions = data.submissions || [];
75+
const statusCount: Record<string, number> = {};
76+
submissions.forEach((s: any) => { statusCount[s.status] = (statusCount[s.status] || 0) + 1; });
77+
setSubmissionStatus(Object.entries(statusCount).map(([status, count]) => ({ status, count })));
78+
})
79+
.catch(() => {});
7080
}, []);
7181

7282
useEffect(() => {
@@ -239,6 +249,41 @@ export default function Profile() {
239249
</div>
240250
)}
241251

252+
{/* Status distribution */}
253+
{submissionStatus.length > 0 && (
254+
<div className="card p-6">
255+
<h3 className="text-sm font-semibold text-dark-200 mb-3 flex items-center gap-2">
256+
<PieChart className="w-4 h-4 text-purple-400" /> 提交状态分布
257+
</h3>
258+
<div className="grid grid-cols-2 gap-3">
259+
{submissionStatus.map((item: {status: string; count: number}) => {
260+
const maxCount = Math.max(...submissionStatus.map((s: any) => s.count));
261+
const colorMap: Record<string, string> = {
262+
accepted: 'bg-emerald-500', wrong_answer: 'bg-red-500',
263+
compile_error: 'bg-yellow-500', time_limit: 'bg-purple-500',
264+
runtime_error: 'bg-orange-500',
265+
};
266+
const labelMap: Record<string, string> = {
267+
accepted: '通过', wrong_answer: '答案错误',
268+
compile_error: '编译错误', time_limit: '超时',
269+
runtime_error: '运行错误',
270+
};
271+
return (
272+
<div key={item.status} className="flex items-center gap-3">
273+
<div className={`w-2.5 h-2.5 rounded-full ${colorMap[item.status] || 'bg-dark-500'}`} />
274+
<span className="flex-1 text-xs text-dark-400">{labelMap[item.status] || item.status}</span>
275+
<div className="flex-1 h-2 bg-dark-700 rounded-full overflow-hidden">
276+
<div className={`h-full ${colorMap[item.status] || 'bg-dark-500'} rounded-full`}
277+
style={{ width: `${(item.count / maxCount) * 100}%` }} />
278+
</div>
279+
<span className="text-xs text-dark-400 w-6 text-right">{item.count}</span>
280+
</div>
281+
);
282+
})}
283+
</div>
284+
</div>
285+
)}
286+
242287
<GamificationSection />
243288

244289
{/* Solved calendar */}

0 commit comments

Comments
 (0)