diff --git a/design-qa.md b/design-qa.md
index 46cdf43..381eee6 100644
--- a/design-qa.md
+++ b/design-qa.md
@@ -325,3 +325,105 @@ Verification evidence:
Design-QA final result: blocked
final result: blocked
+
+---
+
+# Dataset Version Actions Design QA
+
+## Evidence
+
+- Source visual truth: `/Users/caoxiaozhu/.codex/generated_images/019f5e2e-3bee-77f0-b285-89ef139db56c/exec-48a163b6-d4c9-4646-9199-135957c6e72e.png`
+- Historical-version implementation: `/Users/caoxiaozhu/.codex/visualizations/2026/07/14/019f5e2e-3bee-77f0-b285-89ef139db56c/dataset-version-build/implementation-historical-version-final.png`
+- Delete-confirm implementation: `/Users/caoxiaozhu/.codex/visualizations/2026/07/14/019f5e2e-3bee-77f0-b285-89ef139db56c/dataset-version-build/implementation-delete-confirm.png`
+- Full-view comparison: `/Users/caoxiaozhu/.codex/visualizations/2026/07/14/019f5e2e-3bee-77f0-b285-89ef139db56c/dataset-version-build/comparison-full.png`
+- Focused version-control comparison: `/Users/caoxiaozhu/.codex/visualizations/2026/07/14/019f5e2e-3bee-77f0-b285-89ef139db56c/dataset-version-build/comparison-version-controls-final.png`
+- Viewport: 1316 × 768 browser window; source crop normalized for the focused comparison.
+- State: authenticated dataset detail, V3 current, V2 selected as a read-only historical version.
+
+## Full-view comparison
+
+The existing product shell, dataset summary, version selector, read-only alert, file toolbar, and sample table remain unchanged. The former standalone primary action has been replaced by one compact rounded-square overflow button at the far right of the version-control row, matching the selected hierarchy.
+
+## Focused comparison and required fidelity surfaces
+
+- Fonts and typography: existing system/PingFang stack, 13px labels, 12px metadata, and Element Plus menu text are preserved.
+- Spacing and layout rhythm: the 40px overflow trigger aligns with the version selector and leaves the central status copy flexible; the 168px menu provides 40px action rows.
+- Colors and visual tokens: the existing indigo primary token is used for the activate icon; the delete item and confirmation action use the danger token.
+- Image and icon fidelity: no new raster assets are needed. Existing Font Awesome ellipsis, check-circle, and trash icons match the repository's icon system.
+- Copy and content: the menu contains exactly “设为当前版本” and “删除版本”, separated visually; the confirmation names V2 and explains that current V3 is unaffected.
+
+## Interaction checks
+
+- Created V2 and V3 through the real edit-and-save flow, then switched from current V3 to historical V2.
+- Historical records became read-only and the overflow trigger appeared; current V3 showed no history-operation trigger.
+- Opening the trigger exposed exactly two accessible menu items: “设为当前版本” and “删除版本”.
+- Choosing “删除版本” opened the danger confirmation dialog; cancelling returned focus without deleting data.
+- Actual deletion behavior, protected-version rejection, optimistic-lock handling, and non-reused version numbers are covered by `test:dataset-preview`.
+
+## Comparison history
+
+### Iteration 1 — blocked
+
+- [P2] The overflow trigger was circular while the selected mock used a small rounded square.
+- [P2] The menu did not explicitly lock its target width or primary-action icon color.
+
+Fixes:
+
+- Replaced the circular trigger with a 40px square and 10px radius.
+- Set the menu minimum width to 168px, action height to 40px, and the activate icon to the product primary color.
+
+### Iteration 2 — passed
+
+No actionable P0/P1/P2 differences remain. The desktop capture API does not retain the transient popup layer in screenshots, so the open-menu labels were additionally verified through the accessibility tree; exact popup shadow rendering remains a non-blocking P3 capture gap.
+
+final result: passed
+
+---
+
+# Login Page Responsive Design QA
+
+## Evidence
+
+- Source visual truth: `/Users/caoxiaozhu/.codex/generated_images/019f5f3f-f7e1-7e41-9605-ea307d9f09e6/exec-d376c603-0c47-45ad-86fd-3e99c1a95ec7.png`
+- Implementation route: `http://localhost:6801/login`
+- Implementation screenshot: unavailable because the in-app browser runtime could not initialize in this session.
+- Intended desktop viewport: 1536 × 1024.
+- Intended laptop viewports: 1366 × 768 and 1280 × 720.
+- State: unauthenticated login page, default username and password populated.
+
+## Static and automated evidence
+
+- Added a 1440px width breakpoint that shifts the split from 58/42 to 55/45 and caps the form at 440px.
+- Added a short-screen breakpoint for heights up to 820px that reduces title, form, input, footer, and panel spacing without hiding the left visual.
+- Kept the single-column fallback at 900px and below.
+- `regression-login-layout.mjs`: passed.
+- `regression-default-dashboard.mjs`: passed.
+- `vue-tsc -b --noEmit`: passed.
+- Vite dev transform for `LoginView.vue`: HTTP 200.
+- Production build: blocked by the pre-existing missing route component `UserPermissionView.vue`, outside the login-page change.
+
+## Required fidelity surfaces
+
+- Fonts and typography: code uses the existing product font stack with laptop-specific display-size reductions; visual comparison remains unavailable.
+- Spacing and layout rhythm: dedicated width and height media queries are present; rendered measurements remain unavailable.
+- Colors and visual tokens: existing indigo tokens and the selected dark-purple visual asset are preserved.
+- Image quality and asset fidelity: the generated `login-hero-flow.png` is used directly; the official `logo.png` is reused for the brand lockup.
+- Copy and content: platform title, supporting copy, form labels, actions, and footer match the selected design.
+
+## Findings
+
+- [P2] Browser-rendered laptop comparison unavailable
+ Location: login page at 1366 × 768 and 1280 × 720.
+ Evidence: the in-app browser runtime failed during initialization, so no implementation screenshot or side-by-side comparison could be captured.
+ Impact: static checks cannot prove that all visible spacing and crop details match the selected design at laptop sizes.
+ Fix: capture both laptop viewports in a working in-app browser session, compare them with the source, and resolve any remaining P0/P1/P2 differences.
+
+## Comparison history
+
+### Iteration 1 — blocked
+
+- User reported that the initial implementation was optimized for large displays and did not compose well on laptop screens.
+- Added explicit laptop-width and short-screen layout rules and passed targeted regression/type checks.
+- Post-fix visual evidence remains unavailable because browser capture is blocked.
+
+final result: blocked
diff --git a/frontend/package.json b/frontend/package.json
index fb2b390..dc2037e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -9,6 +9,7 @@
"preview": "vite preview",
"type-check": "vue-tsc -b --noEmit",
"test": "node scripts/run-regressions.mjs",
+ "test:login-layout": "node scripts/regression-login-layout.mjs",
"test:default-dashboard": "node scripts/regression-default-dashboard.mjs",
"test:dashboard": "node scripts/regression-dashboard.mjs",
"test:data-process-list": "node scripts/regression-data-process-list.mjs",
@@ -21,6 +22,7 @@
"test:eval-detail": "node scripts/regression-eval-detail.mjs",
"test:model-manage": "node scripts/regression-model-manage.mjs",
"test:hardware": "node scripts/regression-hardware-dashboard.mjs",
+ "test:user-settings": "node scripts/regression-user-settings.mjs",
"test:training-log-layout": "node scripts/regression-training-log-layout.mjs",
"test:fine-tune-create": "node scripts/regression-fine-tune-create-ui.mjs",
"test:page-surface": "node scripts/regression-page-surface.mjs"
diff --git a/frontend/scripts/regression-dashboard.mjs b/frontend/scripts/regression-dashboard.mjs
index 1c43f08..759be26 100644
--- a/frontend/scripts/regression-dashboard.mjs
+++ b/frontend/scripts/regression-dashboard.mjs
@@ -19,6 +19,8 @@ assert.match(
assert.match(echartsSource, /import\s*\{[^}]*BarChart[^}]*\}\s*from\s*['"]echarts\/charts['"]/, 'ECharts 未注册 BarChart')
assert.match(echartsSource, /use\(\[[\s\S]*?BarChart[\s\S]*?\]\)/, 'BarChart 未加入 ECharts 按需注册列表')
+assert.match(echartsSource, /import\s*\{[^}]*PieChart[^}]*\}\s*from\s*['"]echarts\/charts['"]/, 'ECharts 未注册 PieChart')
+assert.match(echartsSource, /use\(\[[\s\S]*?PieChart[\s\S]*?\]\)/, 'PieChart 未加入 ECharts 按需注册列表')
for (const copy of [
'平台运行状态',
@@ -39,16 +41,24 @@ assert.match(dashboardSource, /router\.push\(['"]\/fine-tune['"]\)/, '查看全
assert.match(dashboardSource, /router\.push\(`\/training-log\/\$\{task\.id\}`\)/, '训练任务详情应进入训练日志页')
assert.doesNotMatch(dashboardSource, /class=["']dashboard-heading["']/, '服务看板不应重复展示页面标题栏')
assert.doesNotMatch(dashboardSource, /查看告警/, '服务看板不应保留冗余的顶部告警按钮')
-assert.match(dashboardSource, /\.dashboard-view\s*\{[\s\S]*?gap:\s*10px;/, '服务看板应使用紧凑的区块间距')
-assert.match(dashboardSource, /\.dashboard-middle\s*\{[\s\S]*?flex:\s*1 1 auto;[\s\S]*?min-height:\s*0;/, '中间区域应弹性占满剩余高度')
+assert.match(dashboardSource, /\.dashboard-view\s*\{[\s\S]*?gap:\s*16px;/, '服务看板区块间距应保持舒展')
+assert.match(dashboardSource, /\.dashboard-view\s*\{[\s\S]*?min-height:\s*100%;/, '服务看板应至少填满页面可用高度')
+assert.match(dashboardSource, /\.dashboard-middle\s*\{[\s\S]*?flex:\s*0 0 auto;[\s\S]*?min-height:\s*0;/, '中间区域不应因新增统计卡片被压缩')
assert.match(dashboardSource, /grid-template-columns:\s*minmax\(0,\s*1\.9fr\)\s*minmax\(300px,\s*0\.82fr\);/, '服务状态列应收窄,为训练图表释放更多宽度')
-assert.match(dashboardSource, /\.training-chart\s*\{[\s\S]*?flex:\s*1 1 auto;[\s\S]*?height:\s*auto;[\s\S]*?min-height:\s*230px;/, '训练统计图应随可用空间自动拉伸')
-assert.match(dashboardSource, /@media\s*\(max-height:\s*900px\)[\s\S]*?\.training-chart\s*\{[\s\S]*?min-height:\s*200px;/, '较矮桌面视口应保留图表最小可读高度')
+assert.match(dashboardSource, /\.training-chart\s*\{[\s\S]*?height:\s*300px;[\s\S]*?min-height:\s*300px;/, '训练统计图应保持舒展、稳定的展示高度')
assert.match(dashboardSource, /\.service-table\s*\{[\s\S]*?grid-template-rows:[^;]*repeat\(4,\s*minmax\(48px,\s*1fr\)\)/, '服务状态行应随中间区域同步拉伸')
assert.match(dashboardSource, /\.tasks-heading\s*\{[\s\S]*?min-height:\s*32px;[\s\S]*?padding:\s*0 14px 10px;/, '训练任务标题区应适当加高')
assert.match(dashboardSource, /\.tasks-table\s*\{[\s\S]*?th,\s*td\s*\{[\s\S]*?height:\s*42px;[\s\S]*?th\s*\{[\s\S]*?height:\s*36px;/, '训练任务表格行应适当加高')
assert.match(dashboardSource, /@media\s*\(max-height:\s*900px\)[\s\S]*?\.tasks-heading\s*\{[\s\S]*?min-height:\s*28px;[\s\S]*?padding:\s*0 12px 8px;[\s\S]*?\.tasks-table\s*\{[\s\S]*?height:\s*36px;[\s\S]*?th\s*\{[\s\S]*?height:\s*32px;/, '低高度桌面视口也应提高训练任务占比')
-assert.match(mainLayoutSource, /\.layout-content:has\(\.dashboard-view\)[\s\S]*?overflow-y:\s*hidden;/, '服务看板容器应避免产生页面纵向滚动条')
-assert.match(mainLayoutSource, /\.page-canvas\s*\{[\s\S]*?flex:\s*1 1 auto;[\s\S]*?overflow:\s*hidden;/, '服务看板页面画布应约束在可用视口内')
+assert.match(dashboardSource, /class=["']user-stats-row["'][\s\S]*?用户操作分布[\s\S]*?登录时长排行[\s\S]*?最近登录用户/, '服务看板应展示三块用户统计卡片')
+assert.match(dashboardSource, /class=["']duration-chart["'][\s\S]*?loginDurationChartOption/, '登录时长应使用 ECharts 图表展示')
+assert.match(dashboardSource, /const loginDurationChartOption[\s\S]*?type:\s*['"]bar['"][\s\S]*?formatter:\s*['"]\{c\} 小时['"]/, '登录时长应以横向柱状图展示具体小时数')
+assert.match(dashboardSource, /const operationChartOption[\s\S]*?position:\s*['"]outside['"][\s\S]*?labelLine:\s*\{[\s\S]*?show:\s*true/, '饼图应以外侧引导线标注操作名称')
+assert.match(dashboardSource, /const loginDurationChartOption[\s\S]*?grid:\s*\{\s*top:\s*8,\s*right:\s*12,\s*bottom:\s*6,\s*left:\s*8,[\s\S]*?max:\s*Math\.ceil\(Math\.max[\s\S]*?position:\s*['"]insideRight['"]/, '登录时长图应收紧左右边距、按数据范围拉伸,并将数值置于柱内')
+assert.match(dashboardSource, /\.user-stats-row\s*\{[\s\S]*?repeat\(3,\s*minmax\(0,\s*1fr\)\)/, '宽屏用户统计卡片应保持三列')
+assert.match(dashboardSource, /@media\s*\(max-width:\s*1180px\)[\s\S]*?\.user-stats-row\s*\{[\s\S]*?repeat\(2,\s*minmax\(0,\s*1fr\)\)/, '中等宽度应将用户统计卡片降为两列')
+assert.match(dashboardSource, /@media\s*\(max-width:\s*720px\)[\s\S]*?\.user-stats-row\s*\{[\s\S]*?grid-template-columns:\s*1fr;/, '窄屏应将用户统计卡片降为单列')
+assert.match(mainLayoutSource, /\.layout-content:has\(\.dashboard-view\)[\s\S]*?overflow-y:\s*auto;/, '服务看板应允许在内容超出视口时纵向滚动')
+assert.match(mainLayoutSource, /\.page-canvas\s*\{[\s\S]*?flex:\s*1 0 auto;[\s\S]*?overflow:\s*visible;/, '服务看板画布应允许新增卡片完整显示')
console.log('服务看板回归检查通过')
diff --git a/frontend/scripts/regression-dataset-preview.mjs b/frontend/scripts/regression-dataset-preview.mjs
index 28b7a78..8a339ac 100644
--- a/frontend/scripts/regression-dataset-preview.mjs
+++ b/frontend/scripts/regression-dataset-preview.mjs
@@ -17,6 +17,7 @@ const mockPath = path.join(root, 'src/mock/data.ts')
const recordsPath = path.join(root, 'src/views/dataset/datasetRecords.ts')
const versionsPath = path.join(root, 'src/mock/datasetVersions.ts')
const source = fs.readFileSync(previewPath, 'utf8')
+const previewLogicSource = source.slice(0, source.indexOf('
diff --git a/frontend/src/views/login/LoginView.vue b/frontend/src/views/login/LoginView.vue
index bef2528..aa89d4b 100644
--- a/frontend/src/views/login/LoginView.vue
+++ b/frontend/src/views/login/LoginView.vue
@@ -40,225 +40,308 @@ async function handleLogin() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
记住密码
-
忘记密码?
+
+
+
-
+ 数据准备
+ ·
+ 模型训练
+ ·
+ 效果评测
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 记住密码
+ 忘记密码?
+
+
+
+ 登录
+
+
+
+
+
+