From 1b7210de4fe543f688a77fc67c19208c8f5a2c07 Mon Sep 17 00:00:00 2001 From: chenwu Date: Tue, 26 May 2026 22:18:36 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=89=8D=E7=AB=AF=EF=BC=9A?= =?UTF-8?q?=E4=B8=B4=E5=BA=8A=E4=BB=AA=E8=A1=A8=E7=9B=98=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=20+=20AI=E6=97=A5=E6=8A=A5=E7=BC=96=E8=BE=91=E7=89=88=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 全面采用临床数据仪表盘风格:IBM Plex Mono/Sans、teal 主色、无阴影设计 - theme.css 完整重写设计 token,支持亮色/暗色/跟随系统三挡切换 - ThemeControls 简化为图标三键切换组件 - NewsCard 临床风格重排:ALL CAPS 分类标签、INSIGHT 观点块 - NewsReader 精选栏:时间轴布局,蓝点 + 垂直轨道线 - AI日报全新排版:左侧 ARCHIVE 侧边栏 + 主区编辑版式 - 报头:中文数字日期、星期、PHARMA INTEL tagline - 分节:52px teal 编号 + 22px 中文分类 + 英文副标题 - 内容卡片:圆角12px,teal 标题,chips 行(来源/时间/评分) - 页脚统计:STORIES / PROCESSED / SOURCES - 全响应式:≤900px 平板、≤640px 移动端自适应 Co-Authored-By: Claude Sonnet 4.6 --- .claude/launch.json | 19 + frontend/index.html | 4 +- frontend/src/App.vue | 48 +- frontend/src/components/NewsCard.vue | 110 ++- frontend/src/components/ThemeControls.vue | 59 ++ frontend/src/styles/theme.css | 161 ++- frontend/src/views/Admin.vue | 32 + frontend/src/views/NewsReader.vue | 1074 ++++++++++++++++----- frontend/vite.config.js | 3 +- 9 files changed, 1191 insertions(+), 319 deletions(-) create mode 100644 .claude/launch.json create mode 100644 frontend/src/components/ThemeControls.vue diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..20fd1d3 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,19 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "Frontend (Vite)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "cwd": "frontend", + "port": 5173 + }, + { + "name": "Backend (FastAPI/uvicorn)", + "runtimeExecutable": "python", + "runtimeArgs": ["-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"], + "cwd": "backend", + "port": 8000 + } + ] +} diff --git a/frontend/index.html b/frontend/index.html index 3c36b0d..554e5fb 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,9 +4,9 @@ 医药情报 - - + +
diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 98240ae..d4dd48f 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,3 +1,49 @@ + + diff --git a/frontend/src/components/NewsCard.vue b/frontend/src/components/NewsCard.vue index 7d262bb..0202be4 100644 --- a/frontend/src/components/NewsCard.vue +++ b/frontend/src/components/NewsCard.vue @@ -9,13 +9,13 @@

{{ news.title_zh }}

{{ news.summary }}

- 核心观点{{ news.opinion }} + INSIGHT{{ news.opinion }}
@@ -39,56 +39,76 @@ const timeAgo = computed(() => { const diff = Date.now() - new Date(props.news.published_at).getTime() const h = Math.floor(diff / 3600000) if (h < 1) return '刚刚' - if (h < 24) return `${h}小时前` - return `${Math.floor(h / 24)}天前` + if (h < 24) return `${h}h前` + return `${Math.floor(h / 24)}d前` }) diff --git a/frontend/src/components/ThemeControls.vue b/frontend/src/components/ThemeControls.vue new file mode 100644 index 0000000..e4bfe0c --- /dev/null +++ b/frontend/src/components/ThemeControls.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/frontend/src/styles/theme.css b/frontend/src/styles/theme.css index 6edcca6..9840b33 100644 --- a/frontend/src/styles/theme.css +++ b/frontend/src/styles/theme.css @@ -1,64 +1,147 @@ -/* Light theme design tokens */ +/* ───────────────────────────────────────────────────────────────── + Clinical design-system — IBM Plex Mono + IBM Plex Sans + Light = clinical white | Dark = deep navy #050D12 +───────────────────────────────────────────────────────────────── */ + +/* ── Light ────────────────────────────────────────────────────── */ :root { - --bg: #f0f2f5; - --bg-card: #ffffff; - --bg-hover: #f0f4ff; - --bg-1: #ffffff; - --bg-2: #f8f9fc; - --bg-hi: #f3f4f6; + --bg: #F0F6FA; + --bg-card: #FFFFFF; + --bg-hover: rgba(13,155,142,0.05); + --bg-1: #FFFFFF; + --bg-2: #F5F9FC; + --bg-hi: rgba(13,155,142,0.06); - --blue: #2563eb; - --blue-2: #3b82f6; - --blue-gl: rgba(37, 99, 235, 0.06); - --blue-bd: rgba(37, 99, 235, 0.2); + /* primary accent — clinical teal */ + --blue: #0D9B8E; + --blue-2: #13B5A7; + --blue-gl: rgba(13,155,142,0.06); + --blue-bd: rgba(13,155,142,0.22); - --violet: #7c3aed; - --cyan: #0ea5e9; - --mint: #10b981; - --amber: #f59e0b; - --red: #ef4444; + --violet: #7C3AED; + --cyan: #06B6D4; + --mint: #0D9B8E; + --amber: #B07A0A; + --red: #CC3333; + --link-hover:#0A7D72; - --t1: #111827; - --t2: #374151; - --t3: #6b7280; - --t4: #9ca3af; + --ok-bg: rgba(13,155,142,0.08); + --ok-bd: rgba(13,155,142,0.22); + --ok-text: #0D9B8E; + --soft-blue: rgba(13,155,142,0.07); + --soft-green: rgba(22,163,74,0.07); - --rule: #f3f4f6; - --rule2: #e5e7eb; + --badge-red-bg: rgba(204,51,51,0.10); + --badge-red-text: #CC3333; + --badge-amber-bg: rgba(176,122,10,0.10); + --badge-amber-text:#B07A0A; + --badge-blue-bg: rgba(13,155,142,0.10); + --badge-blue-text: #0D9B8E; + --badge-gray-bg: rgba(5,13,18,0.06); + --badge-gray-text: rgba(5,13,18,0.46); - --sans: 'Noto Sans SC', system-ui, sans-serif; - --mono: 'JetBrains Mono', 'Courier New', monospace; + --t1: #050D12; + --t2: rgba(5,13,18,0.76); + --t3: rgba(5,13,18,0.52); + --t4: rgba(5,13,18,0.36); - --r: 12px; - --r-sm: 8px; + --rule: rgba(13,155,142,0.10); + --rule2: rgba(13,155,142,0.20); + + --sans: 'IBM Plex Sans', system-ui, sans-serif; + --mono: 'IBM Plex Mono', 'Courier New', monospace; + + --r: 8px; + --r-sm: 5px; --r-pill: 9999px; - --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04); - --shadow: 0 4px 12px rgba(0,0,0,0.08); - --shadow-lg: 0 8px 24px rgba(37,99,235,0.12); + /* clinical: no decorative shadows */ + --shadow-sm: none; + --shadow: none; + --shadow-lg: none; } +/* ── Dark ─────────────────────────────────────────────────────── */ +:root[data-theme="dark"] { + --bg: #050D12; + --bg-card: #0B1820; + --bg-hover: rgba(61,217,198,0.06); + --bg-1: #0B1820; + --bg-2: #071018; + --bg-hi: rgba(61,217,198,0.06); + + --blue: #3DD9C6; + --blue-2: #3DD9C6; + --blue-gl: rgba(61,217,198,0.06); + --blue-bd: rgba(61,217,198,0.20); + + --violet: #A78BFA; + --cyan: #22D3EE; + --mint: #3DD9C6; + --amber: #F5C97A; + --red: #FF6B6B; + --link-hover:#5DE8D5; + + --ok-bg: rgba(61,217,198,0.10); + --ok-bd: rgba(61,217,198,0.20); + --ok-text: #3DD9C6; + --soft-blue: rgba(61,217,198,0.06); + --soft-green: rgba(61,217,198,0.06); + + --badge-red-bg: rgba(255,107,107,0.15); + --badge-red-text: #FF6B6B; + --badge-amber-bg: rgba(245,201,122,0.15); + --badge-amber-text:#F5C97A; + --badge-blue-bg: rgba(61,217,198,0.12); + --badge-blue-text: #3DD9C6; + --badge-gray-bg: rgba(255,255,255,0.08); + --badge-gray-text: rgba(255,255,255,0.40); + + --t1: #FFFFFF; + --t2: rgba(255,255,255,0.76); + --t3: rgba(255,255,255,0.50); + --t4: rgba(255,255,255,0.30); + + --rule: rgba(61,217,198,0.08); + --rule2: rgba(61,217,198,0.15); +} + +/* ── Global base ──────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } -html, body { - height: 100%; +html { font-size: 16px; } + +body { + font-family: var(--sans); background: var(--bg); color: var(--t1); - font-family: var(--sans); - font-size: 14px; line-height: 1.5; + font-size: 14px; -webkit-font-smoothing: antialiased; + transition: background 0.25s, color 0.25s; } a { color: inherit; text-decoration: none; } -button { cursor: pointer; font-family: inherit; border: none; background: none; } -input, select, textarea { font-family: inherit; } +button { background: none; border: none; cursor: pointer; font: inherit; } +input, select, textarea { font: inherit; } -/* Element Plus light theme */ -.el-input__wrapper { background: #fff !important; box-shadow: 0 0 0 1px var(--rule2) !important; } +/* Element Plus overrides */ +.el-input__wrapper { background: var(--bg-card) !important; box-shadow: 0 0 0 1px var(--rule2) !important; } .el-input__inner { color: var(--t1) !important; } -.el-select-dropdown { background: #fff; border-color: var(--rule2); } +.el-select-dropdown { background: var(--bg-card); border-color: var(--rule2); } .el-select-dropdown__item { color: var(--t2); } .el-select-dropdown__item.hover, .el-select-dropdown__item:hover { background: var(--bg-hover); } -.el-table { --el-table-bg-color: #fff; --el-table-header-bg-color: var(--bg-2); } +.el-table { + --el-table-bg-color: var(--bg-card); + --el-table-tr-bg-color: var(--bg-card); + --el-table-header-bg-color: var(--bg-2); + --el-table-text-color: var(--t2); + --el-table-header-text-color: var(--t1); + --el-table-border-color: var(--rule); + --el-table-row-hover-bg-color: var(--bg-hover); +} +:root[data-theme="dark"] .el-popper, +:root[data-theme="dark"] .el-select__popper.el-popper { + background: var(--bg-card); border-color: var(--rule2); color: var(--t2); +} diff --git a/frontend/src/views/Admin.vue b/frontend/src/views/Admin.vue index 29a0636..5732e39 100644 --- a/frontend/src/views/Admin.vue +++ b/frontend/src/views/Admin.vue @@ -2,6 +2,13 @@