增加代码评分的前端 #14

Merged
p5i4afnyx merged 1 commits from cxf into main 2 months ago

@ -23,10 +23,268 @@ class OpenRankDashboard {
this.updateLastUpdateTime();
this.setupTabNavigation();
this.setupModeSwitch();
this.setupCodeReviewPage();
// 默认显示开发者分析数据
this.displayDeveloperAnalysis(this.mockData.developers);
this.hydrateFromURL();
}
// 设置代码测评页面功能
setupCodeReviewPage() {
// 运行Pylint测评按钮
document.getElementById('run-lint-btn')?.addEventListener('click', () => {
this.runCodeLinting();
});
// 清空代码按钮
document.getElementById('clear-code-btn')?.addEventListener('click', () => {
const codeInput = document.getElementById('python-code-input');
if (codeInput) {
codeInput.value = '';
this.resetCodeReviewResults();
}
});
// 加载示例按钮
document.getElementById('load-example-btn')?.addEventListener('click', () => {
this.loadExampleCode();
});
}
// 加载示例代码
loadExampleCode() {
const exampleCode = `def calculate_average(numbers):
"""计算数字列表的平均值"""
if not numbers:
return 0
total = sum(numbers)
return total / len(numbers)
def get_user_name():
name = input("请输入您的名字: ")
print(f"你好, {name}!")
return name
# 主程序
if __name__ == "__main__":
user = get_user_name()
scores = [85, 90, 78, 92, 88]
avg = calculate_average(scores)
print(f"平均分数是: {avg}")`;
const codeInput = document.getElementById('python-code-input');
if (codeInput) {
codeInput.value = exampleCode;
this.resetCodeReviewResults();
}
}
// 重置代码测评结果
resetCodeReviewResults() {
document.getElementById('code-score').textContent = '0';
document.getElementById('score-quality').textContent = '待评分';
document.getElementById('score-quality').className = 'score-quality';
document.getElementById('issues-count').textContent = '0';
document.getElementById('issues-list').innerHTML = '<p class="empty-message">请运行测评查看代码中的问题</p>';
document.getElementById('lint-summary').innerHTML = '<p class="empty-message">请运行测评查看代码质量总结</p>';
}
// 运行代码测评
runCodeLinting() {
const codeInput = document.getElementById('python-code-input');
if (!codeInput || !codeInput.value.trim()) {
this.showNotification('请先输入Python代码', 'error');
return;
}
// 模拟Pylint测评过程
this.simulatePylintAnalysis(codeInput.value);
}
// 模拟Pylint分析由于浏览器限制使用模拟数据
simulatePylintAnalysis(code) {
// 这里使用模拟数据实际项目中应该调用后端API
const codeLines = code.split('\n');
// 根据代码内容生成模拟的Pylint问题
const issues = [];
// 检查是否有未使用的导入(模拟)
if (code.includes('import') && !code.includes('from ')) {
issues.push({
type: 'info',
message: '导入了模块但未使用',
line: 1
});
}
// 检查是否有函数缺少文档字符串(模拟)
let inFunction = false;
let functionStartLine = 0;
codeLines.forEach((line, index) => {
if (line.trim().startsWith('def ')) {
inFunction = true;
functionStartLine = index + 1;
} else if (inFunction && line.trim().startsWith('#') || line.trim().startsWith('"""')) {
inFunction = false;
} else if (inFunction && line.trim() && !line.trim().startsWith(' ') && !line.trim().startsWith('#')) {
issues.push({
type: 'warning',
message: '缺少函数文档字符串',
line: functionStartLine
});
inFunction = false;
}
});
// 检查行长度(模拟)
codeLines.forEach((line, index) => {
if (line.length > 79) {
issues.push({
type: 'warning',
message: '行长度超过79个字符',
line: index + 1
});
}
});
// 检查是否有print语句模拟
codeLines.forEach((line, index) => {
if (line.includes('print(') && !line.includes('"""') && !line.includes("''")) {
issues.push({
type: 'info',
message: '考虑使用logging模块替代print语句',
line: index + 1
});
}
});
// 检查是否有input语句模拟
codeLines.forEach((line, index) => {
if (line.includes('input(')) {
issues.push({
type: 'warning',
message: '生产环境中应避免使用input()函数',
line: index + 1
});
}
});
// 生成随机的额外问题(增加模拟真实性)
const randomIssues = [
{ type: 'info', message: '考虑添加类型提示以提高代码可读性', line: Math.floor(Math.random() * codeLines.length) + 1 },
{ type: 'warning', message: '变量名可以更具描述性', line: Math.floor(Math.random() * codeLines.length) + 1 },
{ type: 'info', message: '考虑添加单元测试', line: 1 }
];
// 随机添加1-2个额外问题
const additionalIssues = Math.floor(Math.random() * 2) + 1;
for (let i = 0; i < additionalIssues; i++) {
issues.push(randomIssues[i]);
}
// 计算分数(基于问题数量和严重性)
let score = 10;
issues.forEach(issue => {
if (issue.type === 'error') score -= 3;
else if (issue.type === 'warning') score -= 1;
else if (issue.type === 'info') score -= 0.5;
});
score = Math.max(0, Math.min(10, score));
score = Math.round(score * 10) / 10; // 保留一位小数
// 显示结果
this.displayLintResults(score, issues);
}
// 显示测评结果
displayLintResults(score, issues) {
// 更新分数显示
const scoreElement = document.getElementById('code-score');
const qualityElement = document.getElementById('score-quality');
scoreElement.textContent = score.toString();
// 设置质量等级
let qualityText = '优秀';
let qualityClass = 'excellent';
if (score >= 9) {
qualityText = '优秀';
qualityClass = 'excellent';
} else if (score >= 7) {
qualityText = '良好';
qualityClass = 'good';
} else if (score >= 5) {
qualityText = '一般';
qualityClass = 'average';
} else {
qualityText = '需改进';
qualityClass = 'poor';
}
qualityElement.textContent = qualityText;
qualityElement.className = `score-quality ${qualityClass}`;
// 更新CSS样式以反映不同的质量等级
if (qualityClass === 'excellent') {
qualityElement.style.background = 'rgba(0, 255, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(0, 255, 0, 0.3)';
qualityElement.style.color = '#66ff99';
} else if (qualityClass === 'good') {
qualityElement.style.background = 'rgba(0, 212, 255, 0.2)';
qualityElement.style.border = '1px solid rgba(0, 212, 255, 0.3)';
qualityElement.style.color = '#00d4ff';
} else if (qualityClass === 'average') {
qualityElement.style.background = 'rgba(255, 165, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(255, 165, 0, 0.3)';
qualityElement.style.color = '#ffcc66';
} else {
qualityElement.style.background = 'rgba(255, 0, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(255, 0, 0, 0.3)';
qualityElement.style.color = '#ff6b6b';
}
// 更新问题列表
document.getElementById('issues-count').textContent = issues.length.toString();
const issuesList = document.getElementById('issues-list');
if (issues.length === 0) {
issuesList.innerHTML = '<p class="empty-message">代码质量良好,未发现问题</p>';
} else {
// 按行号排序
issues.sort((a, b) => a.line - b.line);
issuesList.innerHTML = issues.map(issue => `
<div class="issue-item">
<div class="issue-header">
<span class="issue-type ${issue.type}">${issue.type === 'error' ? '错误' : issue.type === 'warning' ? '警告' : '信息'}</span>
<span class="issue-line"> ${issue.line} </span>
</div>
<div class="issue-message">${issue.message}</div>
</div>
`).join('');
}
// 生成总结
const summaryElement = document.getElementById('lint-summary');
const errorCount = issues.filter(i => i.type === 'error').length;
const warningCount = issues.filter(i => i.type === 'warning').length;
const infoCount = issues.filter(i => i.type === 'info').length;
summaryElement.innerHTML = `
<ul>
<li><i class="fas fa-check-circle"></i> : ${score}/10 (${qualityText})</li>
<li><i class="fas fa-exclamation-circle"></i> ${errorCount} </li>
<li><i class="fas fa-exclamation-triangle"></i> ${warningCount} </li>
<li><i class="fas fa-info-circle"></i> ${infoCount} </li>
<li><i class="fas fa-code"></i> : ${document.getElementById('python-code-input').value.split('\n').length}</li>
</ul>
<p style="margin-top: 1rem;">
${score >= 7 ? '代码整体质量良好,继续保持!' : '建议根据提示改进代码质量。'}
</p>
`;
}
// 设置事件监听器
setupEventListeners() {

@ -27,6 +27,7 @@
<button class="nav-btn" data-tab="repositories">仓库分析</button>
<button class="nav-btn" data-tab="developers">开发者分析</button>
<button class="nav-btn" data-tab="network">网络图谱</button>
<button class="nav-btn" data-tab="code-review">代码测评</button>
<button class="nav-btn" data-tab="settings">配置</button>
</nav>
<div class="header-actions">
@ -39,6 +40,61 @@
<!-- 主要内容区域 -->
<main class="main-content" id="global-root">
<!-- 代码测评面板 -->
<div class="tab-content" id="code-review">
<div class="code-review-container">
<h2>Python代码测评</h2>
<div class="code-input-section">
<div class="code-editor-controls">
<button id="run-lint-btn" class="btn-primary">
<i class="fas fa-check-circle"></i>
运行Pylint测评
</button>
<button id="clear-code-btn" class="btn-secondary">
<i class="fas fa-trash"></i>
清空代码
</button>
<button id="load-example-btn" class="btn-secondary">
<i class="fas fa-file-code"></i>
加载示例
</button>
</div>
<div class="code-editor-wrapper">
<textarea id="python-code-input" placeholder="请在此输入Python代码...
例如:
def hello():
print('Hello World')
if __name__ == '__main__':
hello()"></textarea>
</div>
</div>
<div class="results-section">
<div class="score-card">
<h3>代码评分</h3>
<div class="score-display">
<span id="code-score">0</span>
<div class="score-label">/ 10</div>
</div>
<div class="score-quality" id="score-quality">待评分</div>
</div>
<div class="issues-container">
<h3>问题列表 <span id="issues-count">0</span></h3>
<div id="issues-list" class="issues-list">
<p class="empty-message">请运行测评查看代码中的问题</p>
</div>
</div>
</div>
<div class="summary-section">
<h3>测评总结</h3>
<div id="lint-summary" class="summary-content">
<p class="empty-message">请运行测评查看代码质量总结</p>
</div>
</div>
</div>
</div>
<!-- 总览面板 -->
<div class="tab-content active" id="overview">
<div class="stats-grid">

@ -98,6 +98,273 @@ body {
.project-header-inline { display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; flex-wrap:wrap; margin-bottom:1rem; }
.project-header-inline h2 { margin:0; font-size:1.25rem; font-weight:700; }
.badge { display:inline-block; padding:.25rem .6rem; font-size:.65rem; letter-spacing:.5px; background:rgba(0,212,255,.15); border:1px solid rgba(0,212,255,.4); border-radius:6px; color:#00d4ff; font-weight:600; }
/* 代码测评页面样式 */
.code-review-container {
padding: 2rem 0;
}
.code-review-container h2 {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1.5rem;
color: #ffffff;
}
.code-input-section {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.code-editor-controls {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
padding: 0.5rem 1rem;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.15);
border-color: rgba(255, 255, 255, 0.3);
}
.code-editor-wrapper {
position: relative;
}
#python-code-input {
width: 100%;
min-height: 300px;
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
color: #ffffff;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9rem;
line-height: 1.5;
padding: 1rem;
resize: vertical;
outline: none;
}
#python-code-input:focus {
border-color: #00d4ff;
box-shadow: 0 0 0 2px rgba(0, 212, 255, 0.25);
}
.results-section {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.score-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.score-card h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
.score-display {
display: flex;
align-items: baseline;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
#code-score {
font-size: 3rem;
font-weight: 700;
color: #00d4ff;
}
.score-label {
font-size: 1.25rem;
color: rgba(255, 255, 255, 0.6);
}
#score-quality {
font-size: 1rem;
font-weight: 600;
padding: 0.25rem 0.75rem;
border-radius: 6px;
background: rgba(0, 212, 255, 0.2);
border: 1px solid rgba(0, 212, 255, 0.3);
color: #00d4ff;
}
.issues-container {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
}
.issues-container h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: space-between;
}
#issues-count {
font-size: 0.85rem;
padding: 0.2rem 0.5rem;
background: rgba(0, 212, 255, 0.2);
border-radius: 4px;
color: #00d4ff;
}
.issues-list {
max-height: 400px;
overflow-y: auto;
}
.issue-item {
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 6px;
padding: 0.75rem;
margin-bottom: 0.75rem;
}
.issue-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.issue-type {
font-size: 0.75rem;
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-weight: 600;
}
.issue-type.error {
background: rgba(255, 0, 0, 0.2);
color: #ff6b6b;
border: 1px solid rgba(255, 0, 0, 0.3);
}
.issue-type.warning {
background: rgba(255, 165, 0, 0.2);
color: #ffcc66;
border: 1px solid rgba(255, 165, 0, 0.3);
}
.issue-type.info {
background: rgba(0, 128, 0, 0.2);
color: #66ff99;
border: 1px solid rgba(0, 128, 0, 0.3);
}
.issue-line {
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.6);
}
.issue-message {
font-size: 0.85rem;
color: rgba(255, 255, 255, 0.8);
line-height: 1.4;
}
.summary-section {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
}
.summary-section h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
.summary-content {
font-size: 0.9rem;
line-height: 1.6;
color: rgba(255, 255, 255, 0.7);
}
.summary-content ul {
list-style: none;
padding: 0;
}
.summary-content li {
margin-bottom: 0.75rem;
display: flex;
align-items: flex-start;
gap: 0.75rem;
}
.summary-content li i {
color: #00d4ff;
margin-top: 0.25rem;
min-width: 16px;
}
.empty-message {
color: rgba(255, 255, 255, 0.5);
font-style: italic;
text-align: center;
padding: 2rem 0;
}
/* 响应式设计 */
@media (max-width: 768px) {
.results-section {
grid-template-columns: 1fr;
}
.code-editor-controls {
flex-direction: column;
}
.btn-primary, .btn-secondary {
width: 100%;
justify-content: center;
}
}
.badge.approx { background:rgba(255,193,7,.15); border-color:rgba(255,193,7,.4); color:#ffc107; }
.badge.full { background:rgba(0,255,136,.15); border-color:rgba(0,255,136,.4); color:#00ff88; }

Loading…
Cancel
Save