- 新增 _calculate_lane_conflicts_v2() 分開返回標籤重疊和線穿框分數 - 修改泳道選擇算法,優先選擇無標籤重疊的泳道 - 兩階段搜尋:優先側別無可用泳道則嘗試另一側 - 增強日誌輸出,顯示標籤範圍和詳細衝突分數 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
143 lines
4.5 KiB
HTML
143 lines
4.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-TW">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>經典時間軸測試</title>
|
|
<script src="https://cdn.plot.ly/plotly-2.26.0.min.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
}
|
|
.status {
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
}
|
|
.success { background: #d4edda; color: #155724; }
|
|
.error { background: #f8d7da; color: #721c24; }
|
|
button {
|
|
background: #667EEA;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
font-size: 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
button:hover {
|
|
background: #5568d3;
|
|
}
|
|
#timeline {
|
|
margin-top: 20px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>經典時間軸渲染器測試</h1>
|
|
|
|
<div>
|
|
<button onclick="loadDemo('project')">載入專案時間軸</button>
|
|
<button onclick="loadDemo('life')">載入個人履歷</button>
|
|
<button onclick="loadDemo('roadmap')">載入產品路線圖</button>
|
|
<button onclick="clearTimeline()">清空</button>
|
|
</div>
|
|
|
|
<div id="status"></div>
|
|
<div id="timeline"></div>
|
|
|
|
<script>
|
|
const API_BASE = 'http://localhost:8000/api';
|
|
|
|
async function showStatus(message, isError = false) {
|
|
const statusDiv = document.getElementById('status');
|
|
statusDiv.className = 'status ' + (isError ? 'error' : 'success');
|
|
statusDiv.textContent = message;
|
|
}
|
|
|
|
async function loadDemo(type) {
|
|
try {
|
|
showStatus('載入中...');
|
|
|
|
// 清空現有事件
|
|
await fetch(`${API_BASE}/events`, { method: 'DELETE' });
|
|
|
|
// 選擇檔案
|
|
const files = {
|
|
'project': 'demo_project_timeline.csv',
|
|
'life': 'demo_life_events.csv',
|
|
'roadmap': 'demo_product_roadmap.csv'
|
|
};
|
|
const filename = files[type];
|
|
|
|
// 讀取檔案
|
|
const fileResponse = await fetch(`/examples/${filename}`);
|
|
const blob = await fileResponse.blob();
|
|
|
|
// 上傳檔案
|
|
const formData = new FormData();
|
|
formData.append('file', blob, filename);
|
|
|
|
const importResponse = await fetch(`${API_BASE}/import`, {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const importResult = await importResponse.json();
|
|
showStatus(`匯入成功:${importResult.data.count} 筆事件`);
|
|
|
|
// 渲染時間軸
|
|
const renderResponse = await fetch(`${API_BASE}/render`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
direction: 'horizontal',
|
|
theme: 'modern',
|
|
show_grid: true,
|
|
enable_zoom: true,
|
|
enable_drag: true
|
|
})
|
|
});
|
|
|
|
const renderResult = await renderResponse.json();
|
|
|
|
if (renderResult.success) {
|
|
// 顯示 Plotly 圖表
|
|
Plotly.newPlot('timeline',
|
|
renderResult.data.data,
|
|
renderResult.layout,
|
|
renderResult.config
|
|
);
|
|
showStatus(`成功渲染 ${filename}`);
|
|
} else {
|
|
showStatus(`渲染失敗: ${renderResult.message}`, true);
|
|
}
|
|
|
|
} catch (error) {
|
|
showStatus(`錯誤: ${error.message}`, true);
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async function clearTimeline() {
|
|
try {
|
|
await fetch(`${API_BASE}/events`, { method: 'DELETE' });
|
|
document.getElementById('timeline').innerHTML = '';
|
|
showStatus('已清空');
|
|
} catch (error) {
|
|
showStatus(`錯誤: ${error.message}`, true);
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|