diff --git a/.env.example b/.env.example index d33989a..e8fd832 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,11 @@ LLM_API_BASE=https://api.deepseek.com/v1 # Examples: deepseek-chat, gpt-4o-mini, gemini-1.5-flash LLM_MODEL=deepseek-chat +# Embedding Model Settings (OpenAI-compatible endpoints, falls back to LLM keys if unspecified) +EMBEDDING_API_KEY=your_embedding_api_key_here +EMBEDDING_API_BASE=https://api.openai.com/v1 +EMBEDDING_MODEL=text-embedding-3-small + # Qiniu Cloud Storage Config (For hosting PDF-extracted layout images) QINIU_AK=your_qiniu_access_key_here QINIU_SK=your_qiniu_secret_key_here diff --git a/Cargo.lock b/Cargo.lock index 037ca6f..452fd13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,6 +287,24 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.117", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -363,6 +381,31 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "btls" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5e60b8c8d282c86360cab651ded04ab0335a7b5390c8d34145cbeab8cacf5f" +dependencies = [ + "bitflags", + "btls-sys", + "foreign-types", + "libc", + "openssl-macros", +] + +[[package]] +name = "btls-sys" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1b8638a2e1c38a5ae4efa90ae57e643baec35a30d03fc5b399b893adc4954b" +dependencies = [ + "bindgen 0.72.1", + "cmake", + "fs_extra", + "fslock", +] + [[package]] name = "bumpalo" version = "3.20.3" @@ -484,6 +527,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + [[package]] name = "cmov" version = "0.5.4" @@ -571,26 +623,6 @@ dependencies = [ "url", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1047,19 +1079,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "foreign-types" -version = "0.3.2" +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ + "foreign-types-macros", "foreign-types-shared", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "foreign-types-macros" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" @@ -1070,6 +1120,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fslock" version = "0.2.1" @@ -1271,25 +1327,6 @@ dependencies = [ "crc32fast", ] -[[package]] -name = "h2" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -1306,7 +1343,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1314,6 +1351,11 @@ name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hashlink" @@ -1460,6 +1502,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" +[[package]] +name = "http2" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "569ef7a780e853c4e1768f58a3c8168193b82cdcbab66638a0b1c6583ec5995e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "smallvec", + "tokio", + "tokio-util", +] + [[package]] name = "httparse" version = "1.10.1" @@ -1491,7 +1552,6 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", "http", "http-body", "httparse", @@ -1519,22 +1579,6 @@ dependencies = [ "webpki-roots 1.0.7", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -1553,11 +1597,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", - "system-configuration", "tokio", "tower-service", "tracing", - "windows-registry", ] [[package]] @@ -1910,6 +1952,15 @@ version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" +[[package]] +name = "lru" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +dependencies = [ + "hashbrown 0.17.1", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2073,23 +2124,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -2245,6 +2279,8 @@ dependencies = [ "tokio", "tracing", "url", + "wreq", + "wreq-util", ] [[package]] @@ -2253,20 +2289,6 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" -[[package]] -name = "openssl" -version = "0.10.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "openssl-macros", - "openssl-sys", -] - [[package]] name = "openssl-macros" version = "0.1.1" @@ -2278,24 +2300,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "openssl-sys" -version = "0.9.116" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "outref" version = "0.5.2" @@ -2769,22 +2773,17 @@ dependencies = [ "bytes", "cookie", "cookie_store", - "encoding_rs", "futures-core", "futures-util", - "h2", "http", "http-body", "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", - "mime", "mime_guess", - "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -2795,7 +2794,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -2961,15 +2959,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -2986,29 +2975,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "selectors" version = "0.26.0" @@ -3640,27 +3606,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -3814,6 +3759,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tokio-btls" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1fd638ec35427faf3b8f412e0fdd6fae76591d79dba40f38fa667d22bc44dd" +dependencies = [ + "btls", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.7.0" @@ -3825,16 +3780,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" @@ -3845,6 +3790,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-socks" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e2948f60dbe26b35f2c7fb74ac2854c1fddded0fe9d7548fcc674a246f7615" +dependencies = [ + "either", + "futures-util", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.18" @@ -4039,6 +3996,26 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typed-builder" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "typed-path" version = "0.12.3" @@ -4162,7 +4139,7 @@ version = "137.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33995a1fee055ff743281cde33a41f0d618ee0bdbe8bdf6859e11864499c2595" dependencies = [ - "bindgen", + "bindgen 0.71.1", "bitflags", "fslock", "gzip-header", @@ -4377,6 +4354,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.25.4" @@ -4486,17 +4472,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - [[package]] name = "windows-result" version = "0.4.1" @@ -4763,6 +4738,81 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wreq" +version = "6.0.0-rc.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0eba5f5814a94e5f1a99156f187133464e525b66bdbc69a9627d46530af2e1" +dependencies = [ + "btls", + "btls-sys", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "http2", + "httparse", + "ipnet", + "libc", + "lru", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tokio-btls", + "tokio-socks", + "tower", + "url", + "webpki-root-certs", + "wreq-proto", + "wreq-rt", +] + +[[package]] +name = "wreq-proto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a43942f024bb303f1042c9aa3c87fa1d9149f507c65db6e5220a11ccdb207387" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "http2", + "httparse", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util", + "want", +] + +[[package]] +name = "wreq-rt" +version = "0.2.2-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e9bce67a3fa3dd3f1503f066d86661c9caf399a763d3bd184da7afaf886c8b" +dependencies = [ + "pin-project-lite", + "tokio", + "wreq-proto", +] + +[[package]] +name = "wreq-util" +version = "3.0.0-rc.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa5d2ab72139256916ca352a3d05c53d74e1dd360052eb5ba7691033c417c65" +dependencies = [ + "brotli", + "flate2", + "typed-builder", + "wreq", + "zstd", +] + [[package]] name = "writeable" version = "0.6.3" diff --git a/Cargo.toml b/Cargo.toml index afccf14..01f12bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ tower-http = { version = "0.5", features = ["cors", "fs", "trace"] } sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite", "chrono", "json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -reqwest = { version = "0.12", features = ["json", "stream", "multipart", "cookies"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "multipart", "cookies", "rustls-tls"] } dotenvy = "0.15" quick-xml = { version = "0.31", features = ["serialize"] } anyhow = "1.0" @@ -50,7 +50,7 @@ obscura-net = { path = "libs/obscura/crates/obscura-net", optional = true } [features] default = [] -obscura-inprocess = ["dep:obscura-browser", "dep:obscura-net"] +obscura-inprocess = ["dep:obscura-browser", "dep:obscura-net", "obscura-browser/stealth", "obscura-net/stealth"] [profile.release-min] inherits = "release" diff --git a/bin/obscura b/bin/obscura index 2f53321..2737a0e 100755 Binary files a/bin/obscura and b/bin/obscura differ diff --git a/bin/obscura-worker b/bin/obscura-worker index 0e7a04e..4ec20a4 100755 Binary files a/bin/obscura-worker and b/bin/obscura-worker differ diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 5f244a0..0c0a2e9 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,7 +1,7 @@ // dashboard/src/App.tsx import { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; -import { Loader, Download } from 'lucide-react'; +import { Loader, Download, BookOpen, GitFork, RefreshCw, AlertTriangle } from 'lucide-react'; import { Sidebar } from './components/layout/Sidebar'; import { SearchPanel, getDoctypeBadge } from './features/search/SearchPanel'; import { LibraryPanel } from './features/library/LibraryPanel'; @@ -431,7 +431,9 @@ export default function App() {
{/* 选项卡容器 */}
-
+
{activeTab === 'search' && ( )} - {activeTab === 'reader' && selectedPaper && ( - + {activeTab === 'reader' && ( + selectedPaper ? ( + + ) : ( +
+
+ +
+

未选定阅读文献

+

+ 双语对比阅读功能需要基于已下载的馆藏文献。请前往“馆藏管理”选择或上传一篇文献,然后开启沉浸式双语精读。 +

+ +
+ ) )} {activeTab === 'citation' && ( - + selectedPaper ? ( + + ) : ( +
+
+ +
+

未选定中心文献

+

+ 引用星系拓扑图谱用于展示单篇文献的“引用 - 被引”星系脉络。请前往“馆藏管理”选择一篇文献并生成其引用图谱。 +

+ +
+ ) )} {activeTab === 'sync' && ( @@ -672,49 +710,58 @@ export default function App() {
{/* 详情内容 */} -
+
{/* 作者 */} -
+
作者列表

{detailPaper.authors.join(', ')}

{/* 期刊 & 年份 */} -
-
- 发表期刊 - {detailPaper.pub_journal || '未标注'} +
+
+ 发表期刊 + + {detailPaper.pub_journal || '未标注'} +
-
- 发表年份 - {detailPaper.year} +
+ 发表年份 + {detailPaper.year}
{/* 摘要 */} -
+
摘要 -

+

{detailPaper.abstract_text || '该文献暂无摘要数据。'}

{/* 关键字 */} - {detailPaper.keywords && detailPaper.keywords.length > 0 && ( -
- 关键词 -
+
+ 关键词 + {detailPaper.keywords && detailPaper.keywords.length > 0 ? ( +
{detailPaper.keywords.map(kw => ( {kw} ))}
-
- )} + ) : ( +
+ 暂无关键词 +
+ )} +
{/* 标识符 */} -
+
BIBCODE @@ -765,8 +812,86 @@ export default function App() {
+ {/* 手动上传文件(应对防爬阻断) */} +
+
+ 手动离线上传文献 + 防爬/人机验证备用 +
+

+ 若自动下载受阻,可在浏览器中打开上方链接,手动保存 PDF 或 HTML 后在此处上传覆盖。 +

+
+
+ { + const file = e.target.files?.[0]; + if (file) handleManualUpload(detailPaper.bibcode, 'pdf', file); + }} + className="absolute inset-0 opacity-0 cursor-pointer w-full h-full" + disabled={uploadingBibcode === detailPaper.bibcode} + /> + {detailPaper.has_pdf && ( + + 已下载 + + )} + + {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 PDF 文献'} + + 支持 .pdf 格式 +
+ +
+ { + const file = e.target.files?.[0]; + if (file) handleManualUpload(detailPaper.bibcode, 'html', file); + }} + className="absolute inset-0 opacity-0 cursor-pointer w-full h-full" + disabled={uploadingBibcode === detailPaper.bibcode} + /> + {detailPaper.has_html && ( + + 已下载 + + )} + + {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 HTML 文献'} + + 支持 .html 格式 +
+
+ + {!detailPaper.is_downloaded && ( +
+ {detailPaper.pdf_error === 'no_resource' && detailPaper.html_error === 'no_resource' ? ( + + ) : ( + + )} +
+ )} +
+ {/* 自动下载失败诊断 */} - {(detailPaper.pdf_error || detailPaper.html_error) && ( + {!detailPaper.is_downloaded && (detailPaper.pdf_error || detailPaper.html_error) && (
)} - - {/* 手动上传文件(应对防爬阻断) */} -
-
- 手动离线上传文献 - 防爬/人机验证备用 -
-

- 若自动下载受阻,可在浏览器中打开上方链接,手动保存 PDF 或 HTML 后在此处上传覆盖。 -

-
-
- { - const file = e.target.files?.[0]; - if (file) handleManualUpload(detailPaper.bibcode, 'pdf', file); - }} - className="absolute inset-0 opacity-0 cursor-pointer w-full h-full" - disabled={uploadingBibcode === detailPaper.bibcode} - /> - - {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 PDF 文献'} - - 支持 .pdf 格式 -
- -
- { - const file = e.target.files?.[0]; - if (file) handleManualUpload(detailPaper.bibcode, 'html', file); - }} - className="absolute inset-0 opacity-0 cursor-pointer w-full h-full" - disabled={uploadingBibcode === detailPaper.bibcode} - /> - - {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 HTML 文献'} - - 支持 .html 格式 -
-
- - {!detailPaper.is_downloaded && ( -
- {detailPaper.pdf_error === 'no_resource' && detailPaper.html_error === 'no_resource' ? ( - - ) : ( - - )} -
- )} -
{/* 底部操作:整合所有动作(阅读、图谱、下载) */} diff --git a/dashboard/src/components/layout/Sidebar.tsx b/dashboard/src/components/layout/Sidebar.tsx index 898081b..ce34f06 100644 --- a/dashboard/src/components/layout/Sidebar.tsx +++ b/dashboard/src/components/layout/Sidebar.tsx @@ -1,5 +1,6 @@ // dashboard/src/components/layout/Sidebar.tsx -import { Search, BookOpen, GitFork, Library, RefreshCw } from 'lucide-react'; +import { useState } from 'react'; +import { Search, BookOpen, GitFork, Library, RefreshCw, ChevronLeft } from 'lucide-react'; import type { StandardPaper } from '../../types'; interface SidebarProps { @@ -10,31 +11,81 @@ interface SidebarProps { } export function Sidebar({ activeTab, setActiveTab, selectedPaper, loadCitations }: SidebarProps) { + const [isCollapsed, setIsCollapsed] = useState(false); + + const renderLogo = () => ( + + + + + + + + + + + + + + + ); + return ( -