加载仓库数据...
+diff --git a/handlers/repos.go b/handlers/repos.go index a67b168..208e53d 100644 --- a/handlers/repos.go +++ b/handlers/repos.go @@ -110,6 +110,7 @@ func (h *ReposHandler) CloneRepo(c *gin.Context) { c.Header("Cache-Control", "no-cache") c.Header("Connection", "keep-alive") c.Header("X-Accel-Buffering", "no") + c.Status(http.StatusOK) flusher, ok := c.Writer.(http.Flusher) if !ok { diff --git a/templates/pages/index.html b/templates/pages/index.html index 37a0998..372592a 100644 --- a/templates/pages/index.html +++ b/templates/pages/index.html @@ -78,41 +78,80 @@ document.getElementById('clone-form').addEventListener('submit', async function( const bar = document.getElementById('clone-bar'); const errorEl = document.getElementById('clone-error'); btn.disabled = true; + btn.textContent = '克隆中...'; progress.classList.remove('hidden'); errorEl.classList.add('hidden'); bar.style.width = '0%'; + status.textContent = '正在连接...'; + try { const resp = await fetch('/api/repos', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({url: url}) }); - if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || 'clone failed'); } + + if (!resp.ok) { + const data = await resp.json(); + throw new Error(data.error || 'clone failed'); + } + const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; + let currentEvent = ''; + while (true) { const {done, value} = await reader.read(); if (done) break; + buffer += decoder.decode(value, {stream: true}); const lines = buffer.split('\n'); buffer = lines.pop() || ''; + for (const line of lines) { - if (line.startsWith('data: ')) { + if (line.startsWith('event: ')) { + currentEvent = line.slice(7).trim(); + } else if (line.startsWith('data: ')) { try { const data = JSON.parse(line.slice(6)); - if (data.progress !== undefined) bar.style.width = data.progress + '%'; - if (data.message) status.textContent = data.message; - if (data.done) { window.location.href = '/repo/' + data.repo_id; return; } - } catch {} + + if (currentEvent === 'start') { + status.textContent = '开始克隆...'; + bar.style.width = '10%'; + } else if (currentEvent === 'progress') { + status.textContent = data.step || '处理中...'; + if (data.current !== undefined && data.total > 0) { + bar.style.width = Math.round((data.current / data.total) * 80 + 10) + '%'; + } else { + bar.style.width = '50%'; + } + } else if (currentEvent === 'complete') { + bar.style.width = '100%'; + status.textContent = '克隆完成!'; + // Redirect to repo page + setTimeout(() => { + window.location.href = '/repo/' + data.repo_id; + }, 500); + return; + } else if (currentEvent === 'error') { + throw new Error(data.message || '克隆失败'); + } + } catch (parseErr) { + if (parseErr.message && !parseErr.message.includes('JSON')) { + throw parseErr; + } + } } } } } catch (err) { errorEl.textContent = err.message; errorEl.classList.remove('hidden'); + progress.classList.add('hidden'); } finally { btn.disabled = false; + btn.textContent = '克隆'; } }); diff --git a/templates/pages/repo.html b/templates/pages/repo.html index 3dd5d96..0171851 100644 --- a/templates/pages/repo.html +++ b/templates/pages/repo.html @@ -18,12 +18,6 @@ .graph-container svg { display: block; } - .ref-tag { - cursor: pointer; - } - .ref-tag:hover { - opacity: 0.8; - }
@@ -31,9 +25,10 @@加载仓库数据...
+