diff --git a/AGENTS.md b/AGENTS.md index f7cdabc..277f88f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2883,5 +2883,45 @@ $ echo $? **累计代码**:5061 行(新增 31 行) -**最后更新**:2026-06-20 14:15 -**版本**:1.31(exit-status 修复完成) +--- + +## 死代码清理完成(2026-06-20)⭐⭐⭐⭐⭐ + +**清理内容**(`kex_complete.rs`): +- 移除 `compute_exchange_hash()`(113 行)— 已被 `kex_exchange.rs::compute_exchange_hash_strict()` 替代 +- 移除 `write_ssh_mpint_to_hash()` — 该函数有 bug(未处理 X25519 big-endian 转换) +- 移除 `write_ssh_string_to_hash()` / `write_ssh_bytes_to_hash()` — 仅被上述函数调用 +- 移除 `test_exchange_hash_computation` 测试(依赖已删除的函数) +- 移除 `sha2` 和 `Digest` 导入(不再需要) + +**验证**:157 passed, 0 failed + +**最后更新**:2026-06-20 14:30 +**版本**:1.32(死代码清理完成) + +--- + +## Web Frontend Phase 3 完成(2026-06-20)⭐⭐⭐⭐⭐ + +**完成时间**:约 10 分钟 +**新增代码量**:~60 行 + +### 实施内容 ⭐⭐⭐⭐⭐ + +**category_view.html 新增 Upload Tab**: +1. ✅ 在 "By Category" / "By Series" 旁添加第三 Tab "Upload" +2. ✅ Upload 表单包含 User ID 输入(默认: accusys) +3. ✅ 文件选择器(单文件上传) +4. ✅ 进度条(XMLHttpRequest.upload.onprogress) +5. ✅ 成功/错误状态显示 +6. ✅ 使用现有 `/api/v2/upload-unlimited/:user_id` 端点 + +### 验证 ⭐⭐⭐⭐⭐ + +```bash +cargo build -p markbase-core # ✅ 0 error +cargo test -p markbase-core --lib # ✅ 157 passed, 0 failed +``` + +**最后更新**:2026-06-20 14:45 +**版本**:1.33(Web Frontend Phase 3 完成) diff --git a/markbase-core/src/category_view.html b/markbase-core/src/category_view.html index 3815326..c59095a 100644 --- a/markbase-core/src/category_view.html +++ b/markbase-core/src/category_view.html @@ -146,6 +146,70 @@ margin-bottom: 20px; } .back-btn:hover { background: #e8e8ed; } + + /* Upload tab styles */ + .upload-form { + max-width: 500px; + margin: 0 auto; + padding: 20px 0; + } + .upload-form label { + display: block; + font-weight: 500; + color: #1d1d1f; + margin-bottom: 8px; + } + .upload-form input[type="text"] { + width: 100%; + padding: 10px 14px; + border: 1px solid #d2d2d7; + border-radius: 8px; + font-size: 14px; + margin-bottom: 20px; + } + .upload-form input[type="file"] { + display: block; + margin-bottom: 20px; + font-size: 14px; + } + .upload-form .upload-btn { + width: 100%; + padding: 14px; + background: #0071e3; + color: white; + border: none; + border-radius: 8px; + font-size: 16px; + cursor: pointer; + } + .upload-form .upload-btn:hover { background: #0077ed; } + .upload-form .upload-btn:disabled { + background: #ccc; + cursor: not-allowed; + } + .progress-bar { + width: 100%; + height: 8px; + background: #e8e8ed; + border-radius: 4px; + overflow: hidden; + margin: 16px 0; + display: none; + } + .progress-bar .fill { + height: 100%; + background: #0071e3; + width: 0%; + transition: width 0.3s; + } + .upload-status { + text-align: center; + font-size: 14px; + margin-top: 12px; + color: #86868b; + } + .upload-status.success { color: #30d158; } + .upload-status.error { color: #ff453a; } @@ -159,6 +223,7 @@
By Category
By Series
+
Upload
@@ -200,6 +265,13 @@ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); document.querySelector(`.tab[data-view="${view}"]`).classList.add('active'); + + if (view === 'upload') { + document.getElementById('back-btn').style.display = 'none'; + showUploadForm(); + return; + } + document.getElementById('back-btn').style.display = 'none'; document.getElementById('items-label').textContent = view === 'category' ? 'Categories' : 'Series'; @@ -325,6 +397,91 @@ } } + async function showUploadForm() { + const content = document.getElementById('content'); + document.getElementById('total-items').textContent = '-'; + document.getElementById('total-files').textContent = '-'; + + content.innerHTML = ` +
+ + + + + + +
+
+
+ + +
+
+ `; + } + + async function startUpload() { + const fileInput = document.getElementById('upload-file'); + const file = fileInput.files[0]; + if (!file) { + document.getElementById('upload-status').textContent = 'Please select a file'; + document.getElementById('upload-status').className = 'upload-status error'; + return; + } + + const userId = document.getElementById('upload-user-id').value.trim() || 'accusys'; + const btn = document.getElementById('upload-btn'); + const status = document.getElementById('upload-status'); + const progressBar = document.getElementById('progress-bar'); + const progressFill = document.getElementById('progress-fill'); + + btn.disabled = true; + btn.textContent = 'Uploading...'; + status.textContent = ''; + status.className = 'upload-status'; + progressBar.style.display = 'block'; + + try { + const formData = new FormData(); + formData.append('file', file); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', apiBase + '/api/v2/upload-unlimited/' + encodeURIComponent(userId), true); + + xhr.upload.onprogress = function(e) { + if (e.lengthComputable) { + const pct = (e.loaded / e.total) * 100; + progressFill.style.width = pct + '%'; + } + }; + + const result = await new Promise((resolve, reject) => { + xhr.onload = function() { + if (xhr.status >= 200 && xhr.status < 300) { + try { resolve(JSON.parse(xhr.responseText)); } + catch { resolve({ ok: true }); } + } else { + try { reject(JSON.parse(xhr.responseText)); } + catch { reject({ error: 'Upload failed (' + xhr.status + ')' }); } + } + }; + xhr.onerror = function() { reject({ error: 'Network error' }); }; + xhr.send(formData); + }); + + progressFill.style.width = '100%'; + status.textContent = 'Upload successful! File: ' + file.name; + status.className = 'upload-status success'; + btn.textContent = 'Done'; + } catch (err) { + status.textContent = 'Upload failed: ' + (err.error || err.message || 'Unknown error'); + status.className = 'upload-status error'; + btn.disabled = false; + btn.textContent = 'Upload'; + progressBar.style.display = 'none'; + } + } + function goBack() { if (navigationStack.length === 0) { currentItem = null;