// detail.js - 开发者详情页渲染器 let currentDevId = null; // 显示详情页 function showDetailPage(devId) { currentDevId = devId; const overview = document.getElementById('overview-container'); const detail = document.getElementById('detail-container'); if (!overview || !detail) { console.error('找不到容器元素'); return; } // 淡出总览页 overview.classList.add('fade-out'); setTimeout(() => { overview.style.display = 'none'; overview.classList.remove('fade-out'); // 渲染详情页数据 renderDetailPage(devId); detail.style.display = 'block'; detail.classList.add('fade-in'); // 滚动到顶部 window.scrollTo(0, 0); }, 300); } // 返回总览页 function hideDetailPage() { const overview = document.getElementById('overview-container'); const detail = document.getElementById('detail-container'); detail.classList.add('fade-out'); setTimeout(() => { detail.style.display = 'none'; detail.classList.remove('fade-out'); overview.style.display = 'block'; overview.classList.add('fade-in'); // 刷新总览页数据 refreshDashboard(); }, 300); } // 渲染详情页 function renderDetailPage(devId) { const dev = getDeveloperById(devId); if (!dev) return; const container = document.getElementById('detail-container'); // 生成五维进度条 const progressBars = renderPCAProgressBars(dev.pca); // 获取模块历史 const modules = getModuleHistory(devId); const moduleList = renderModuleHistory(modules); // 获取连胜趋势数据 const trendData = getWinTrendData(devId); container.innerHTML = `
${dev.id} 🏆 ${dev.wins}
${dev.name}
${dev.el} ${dev.module}
${Object.entries(dev.pca).map(([key, val]) => `${key}:${val}` ).join('')}

📊 完整PCA雷达图

${renderRadarChart(dev.pca, 'large')}
${Object.entries(dev.pca).map(([dim, score]) => `${dim}: ${score}` ).join('')}

📈 五维进度条

${progressBars}

📋 模块历史

${moduleList}

🏆 连胜趋势

`; // 绘制趋势图 setTimeout(() => drawTrendChart('trend-canvas', trendData), 100); } // 渲染PCA五维进度条 function renderPCAProgressBars(pca) { const dimensions = [ { key: 'EXE', label: '执行力', color: '#4CAF50' }, { key: 'TEC', label: '技术深度', color: '#2196F3' }, { key: 'SYS', label: '系统思维', color: '#9C27B0' }, { key: 'COL', label: '协作力', color: '#FF9800' }, { key: 'INI', label: '主动性', color: '#f44336' } ]; return dimensions.map(dim => { const score = pca[dim.key] || 0; return `
${dim.label} ${score}
${dim.key}
`; }).join(''); } // 渲染模块历史列表 function renderModuleHistory(modules) { if (!modules || modules.length === 0) { return '

暂无模块历史

'; } return ` `; } // 获取模块历史(模拟数据) function getModuleHistory(devId) { const histories = { 'DEV-001': [ { code: 'M-DEVBOARD-001', name: '开发者看板·环节0~2', status: '已完成', completedDate: '2026-03-10' }, { code: 'M-FRONTEND-003', name: '前端基础组件', status: '已完成', completedDate: '2026-03-08' }, { code: 'M-API-002', name: 'API对接练习', status: '进行中', completedDate: null } ], 'DEV-002': [ { code: 'M-FRONTEND-001', name: '前端架构设计', status: '已完成', completedDate: '2026-03-09' }, { code: 'M-UI-005', name: '组件库开发', status: '已完成', completedDate: '2026-03-07' }, { code: 'M-TEST-003', name: '单元测试编写', status: '待开始', completedDate: null } ], 'DEV-003': [ { code: 'M-BACKEND-002', name: 'API服务搭建', status: '已完成', completedDate: '2026-03-11' }, { code: 'M-DB-001', name: '数据库设计', status: '已完成', completedDate: '2026-03-09' }, { code: 'M-DEPLOY-002', name: '容器化部署', status: '进行中', completedDate: null } ], 'DEV-004': [ { code: 'M-DEVBOARD-001', name: '开发者看板·环节0~2', status: '已完成', completedDate: '2026-03-11' }, { code: 'M-CANVAS-005', name: 'Canvas雷达图绘制', status: '已完成', completedDate: '2026-03-09' }, { code: 'M-COMPONENTS-003', name: '组件化思维训练', status: '已完成', completedDate: '2026-03-07' }, { code: 'M-DEPLOY-001', name: '静态部署练习', status: '待开始', completedDate: null } ] }; return histories[devId] || histories['DEV-001']; } // 获取连胜趋势数据 function getWinTrendData(devId) { const trends = { 'DEV-001': [ { date: '03-06', value: 3 }, { date: '03-07', value: 3 }, { date: '03-08', value: 4 }, { date: '03-09', value: 4 }, { date: '03-10', value: 5 }, { date: '03-11', value: 5 }, { date: '03-12', value: 5 } ], 'DEV-002': [ { date: '03-06', value: 5 }, { date: '03-07', value: 6 }, { date: '03-08', value: 6 }, { date: '03-09', value: 7 }, { date: '03-10', value: 7 }, { date: '03-11', value: 8 }, { date: '03-12', value: 8 } ], 'DEV-003': [ { date: '03-06', value: 1 }, { date: '03-07', value: 1 }, { date: '03-08', value: 2 }, { date: '03-09', value: 2 }, { date: '03-10', value: 3 }, { date: '03-11', value: 3 }, { date: '03-12', value: 3 } ], 'DEV-004': [ { date: '03-06', value: 8 }, { date: '03-07', value: 9 }, { date: '03-08', value: 9 }, { date: '03-09', value: 10 }, { date: '03-10', value: 11 }, { date: '03-11', value: 12 }, { date: '03-12', value: 13 } ] }; return trends[devId] || trends['DEV-001']; } // 绘制趋势图 function drawTrendChart(canvasId, data) { const canvas = document.getElementById(canvasId); if (!canvas) return; const ctx = canvas.getContext('2d'); const width = canvas.width; const height = canvas.height; const padding = 40; ctx.clearRect(0, 0, width, height); if (!data || data.length < 2) { ctx.fillStyle = '#888'; ctx.font = '14px monospace'; ctx.fillText('暂无连胜数据', padding, height/2); return; } // 计算坐标范围 const values = data.map(d => d.value); const maxValue = Math.max(...values) + 1; const minValue = Math.max(0, Math.min(...values) - 1); const xStep = (width - 2 * padding) / (data.length - 1); // 绘制网格线 ctx.strokeStyle = '#333'; ctx.lineWidth = 1; ctx.beginPath(); for (let i = 0; i <= 5; i++) { const y = padding + (i * (height - 2 * padding) / 5); ctx.moveTo(padding, y); ctx.lineTo(width - padding, y); } ctx.strokeStyle = '#444'; ctx.stroke(); // 绘制轴线 ctx.beginPath(); ctx.strokeStyle = '#666'; ctx.lineWidth = 2; ctx.moveTo(padding, padding); ctx.lineTo(padding, height - padding); ctx.lineTo(width - padding, height - padding); ctx.stroke(); // 绘制折线 ctx.beginPath(); ctx.strokeStyle = '#4CAF50'; ctx.lineWidth = 3; data.forEach((point, i) => { const x = padding + i * xStep; const y = padding + (height - 2 * padding) * (1 - (point.value - minValue) / (maxValue - minValue)); if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); // 绘制数据点 data.forEach((point, i) => { const x = padding + i * xStep; const y = padding + (height - 2 * padding) * (1 - (point.value - minValue) / (maxValue - minValue)); ctx.beginPath(); ctx.arc(x, y, 6, 0, Math.PI * 2); ctx.fillStyle = '#FFD700'; ctx.fill(); ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.stroke(); // 显示数值 ctx.fillStyle = '#fff'; ctx.font = 'bold 12px monospace'; ctx.textAlign = 'center'; ctx.fillText(point.value, x, y - 15); // 显示日期 ctx.fillStyle = '#aaa'; ctx.font = '10px monospace'; ctx.fillText(point.date, x, height - padding + 20); }); } // 导出函数 window.showDetailPage = showDetailPage; window.hideDetailPage = hideDetailPage; window.getModuleHistory = getModuleHistory; window.getWinTrendData = getWinTrendData;