diff --git a/.claude/settings.local.json b/.claude/settings.local.json index cc7d8c1..e072dd9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -5,7 +5,11 @@ "Bash(done)", "Bash(npm run lint)", "Read(//d/App/vue/Miany/**)", - "Bash(find:*)" + "Bash(find:*)", + "mcp__sequential-thinking__sequentialthinking", + "Bash(for dir in src/assets src/components src/config src/router src/stores src/views)", + "Bash(do echo \"=== $dir ===\")", + "Bash(ls:*)" ], "deny": [], "ask": [], diff --git a/CLAUDE.md b/CLAUDE.md index e920ed5..6a6e9d6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -436,6 +436,75 @@ src/assets/styles/theme.css 这次优化在保持视觉效果不变的前提下,大幅简化了颜色变量系统,提升了主题系统的可维护性和扩展性。 +## 📋 用户首页设计与实现记录 + +### 2025年9月16日 - 登录后首页内容设计 + +#### 🎯 功能概述 +为工业CAD模型管理平台设计并实现了专业的登录后首页内容,提供平台功能介绍和使用指导。 + +#### ✅ 完成的设计工作 + +**1. 首页内容设计** +- **项目描述段落**: 详细介绍MianyVue平台的定位、目标用户和核心价值 +- **核心能力展示**: 四大功能模块的专业介绍 + - 多CAD软件统一管理(可扩展设计,避免硬编码数量) + - 智能模型分析(层级分析、几何复杂度等) + - 灵活导出支持(工业标准格式) + - 实时状态监控(系统稳定性保障) +- **技术特色说明**: 平台技术架构和安全性介绍 +- **使用引导**: 简洁的操作提示 + +**2. UI设计特色** +- **文字内容丰富**: 大段专业描述,体现工业软件特色 +- **卡片式布局**: 使用响应式网格展示功能特性 +- **专业配色**: 完全集成现有CSS变量主题系统 +- **交互效果**: hover动画、平滑过渡、视觉层次 + +**3. 技术实现** +- **DashboardView.vue修改**: 替换默认空页面为欢迎内容 +- **样式系统集成**: 使用现有theme.css变量和工业化配色 +- **响应式设计**: 移动端和桌面端的适配 +- **路由配置**: 设置默认显示首页内容 + +#### 📊 设计成果 + +**内容架构** +``` +欢迎页面布局 +├── 标题区域 (平台名称和副标题) +├── 项目描述 (专业介绍段落) +├── 核心能力 (4个功能卡片) +├── 技术特色 (技术架构说明) +└── 使用引导 (操作提示) +``` + +**样式特点** +- **居中布局**: 最大宽度800px,内容居中显示 +- **丰富间距**: 32px间距,良好的视觉层次 +- **图标配色**: 使用主色调蓝色(#2A5CAA)统一图标颜色 +- **卡片交互**: hover效果,轻微上浮动画 +- **文字排版**: 合适的行高(1.6-1.8)和字体大小层级 + +**响应式适配** +- **桌面端**: 2列网格显示功能卡片 +- **移动端**: 单列布局,优化间距和字体大小 +- **灵活布局**: 自适应不同屏幕尺寸 + +#### 🔧 修改的文件 +- `src/views/DashboardView.vue` - 添加欢迎页面内容和样式 +- 路由默认值: currentPage从'connection'改为'home' + +#### 🚀 遵循原则 + +✅ **内容导向**: 提供丰富的文字内容和项目介绍 +✅ **专业定位**: 体现工业CAD软件的专业性和技术特色 +✅ **可扩展设计**: 避免硬编码数量,强调平台的扩展能力 +✅ **设计一致性**: 完全集成现有主题系统和UI风格 +✅ **用户体验**: 清晰的使用指导和操作提示 + +本次首页设计成功为用户提供了专业、信息丰富的平台介绍,建立了良好的第一印象,符合工业软件的专业定位和用户期望。 + ## 📋 CSS变量系统深度优化记录 ### 2025年9月16日 - CSS变量冗余清理 diff --git a/src/assets/styles/theme.css b/src/assets/styles/theme.css index 835dc77..cce4573 100644 --- a/src/assets/styles/theme.css +++ b/src/assets/styles/theme.css @@ -4,86 +4,112 @@ @import './variables.css'; :root { - /* ===== 颜色系统 ===== */ - + /* ===== 基础颜色常量 ===== */ + + /* 核心调色板 - 基础颜色值 */ + --color-primary-base: 42, 92, 170; /* #2A5CAA */ + --color-primary-light-base: 77, 148, 255; /* #4d94ff */ + --color-primary-dark-base: 30, 74, 140; /* #1e4a8c */ + --color-success-base: 76, 175, 80; /* #4CAF50 */ + --color-warning-base: 255, 152, 0; /* #FF9800 */ + --color-error-base: 244, 67, 54; /* #F44336 */ + --color-info-base: 33, 150, 243; /* #2196F3 */ + --color-bg-primary-base: 30, 30, 30; /* #1E1E1E */ + --color-bg-secondary-base: 42, 42, 42; /* #2A2A2A */ + --color-bg-tertiary-base: 26, 26, 26; /* #1A1A1A */ + --color-white-base: 255, 255, 255; /* #ffffff */ + --color-black-base: 0, 0, 0; /* #000000 */ + + /* ===== 语义化颜色系统 ===== */ + /* 主色调 */ - --color-primary: #2A5CAA; - --color-primary-light: #4d94ff; - --color-primary-dark: #1e4a8c; - --color-primary-gradient: linear-gradient(135deg, #2A5CAA 0%, #4d94ff 100%); - --color-primary-gradient-hover: linear-gradient(135deg, #1e4a8c 0%, #2A5CAA 100%); - + --color-primary: rgb(var(--color-primary-base)); + --color-primary-light: rgb(var(--color-primary-light-base)); + --color-primary-dark: rgb(var(--color-primary-dark-base)); + --color-primary-gradient: linear-gradient(135deg, rgb(var(--color-primary-base)) 0%, rgb(var(--color-primary-light-base)) 100%); + --color-primary-gradient-hover: linear-gradient(135deg, rgb(var(--color-primary-dark-base)) 0%, rgb(var(--color-primary-base)) 100%); + /* 状态色 */ - --color-success: #4CAF50; - --color-warning: #FF9800; - --color-error: #F44336; - --color-info: #2196F3; + --color-success: rgb(var(--color-success-base)); + --color-warning: rgb(var(--color-warning-base)); + --color-error: rgb(var(--color-error-base)); + --color-info: rgb(var(--color-info-base)); /* 背景状态色 */ - --color-bg-error: rgba(244, 67, 54, 0.1); - --color-bg-success: rgba(76, 175, 80, 0.1); - --color-bg-warning: rgba(255, 152, 0, 0.1); - --color-bg-info: rgba(33, 150, 243, 0.1); - + --color-bg-error: rgba(var(--color-error-base), 0.1); + --color-bg-success: rgba(var(--color-success-base), 0.1); + --color-bg-warning: rgba(var(--color-warning-base), 0.1); + --color-bg-info: rgba(var(--color-info-base), 0.1); + /* 背景色 */ - --color-bg-primary: #1E1E1E; - --color-bg-secondary: #2A2A2A; - --color-bg-tertiary: #1A1A1A; - --color-bg-quaternary: #252525; - --color-bg-card: rgba(42, 42, 42, 0.8); - --color-bg-hover: rgba(255, 255, 255, 0.05); - --color-bg-active: rgba(42, 92, 170, 0.1); - --color-bg-input: rgba(255, 255, 255, 0.05); - + --color-bg-primary: rgb(var(--color-bg-primary-base)); + --color-bg-secondary: rgb(var(--color-bg-secondary-base)); + --color-bg-tertiary: rgb(var(--color-bg-tertiary-base)); + --color-bg-quaternary: rgb(37, 37, 37); + --color-bg-card: rgba(var(--color-bg-secondary-base), 0.8); + --color-bg-hover: rgba(var(--color-white-base), 0.05); + --color-bg-active: rgba(var(--color-primary-base), 0.1); + --color-bg-input: rgba(var(--color-white-base), 0.05); + /* 渐变背景 */ - --color-bg-gradient-main: linear-gradient(135deg, #1E1E1E 0%, #2A2A2A 100%); - --color-bg-gradient-sidebar: linear-gradient(135deg, #1a1a1a 0%, #252525 100%); - --color-bg-gradient-header: linear-gradient(135deg, #1a1a1a 0%, #252525 100%); - --color-bg-gradient-brand: linear-gradient(135deg, #2A5CAA 0%, #4d94ff 100%); - --color-bg-gradient-brand-hover: linear-gradient(135deg, #1e4a8c 0%, #2A5CAA 100%); - + --color-bg-gradient-main: linear-gradient(135deg, rgb(var(--color-bg-primary-base)) 0%, rgb(var(--color-bg-secondary-base)) 100%); + --color-bg-gradient-sidebar: linear-gradient(135deg, rgb(var(--color-bg-tertiary-base)) 0%, rgb(37, 37, 37) 100%); + --color-bg-gradient-header: linear-gradient(135deg, rgb(var(--color-bg-tertiary-base)) 0%, rgb(37, 37, 37) 100%); + --color-bg-gradient-brand: var(--color-primary-gradient); + --color-bg-gradient-brand-hover: var(--color-primary-gradient-hover); + /* 边框色 */ - --color-border-primary: rgba(255, 255, 255, 0.1); - --color-border-secondary: rgba(255, 255, 255, 0.2); - --color-border-active: #2A5CAA; - --color-border-error: #F44336; + --color-border-primary: rgba(var(--color-white-base), 0.1); + --color-border-secondary: rgba(var(--color-white-base), 0.2); + --color-border-active: var(--color-primary); + --color-border-error: var(--color-error); /* 文字色 */ - --color-text-primary: #ffffff; - --color-text-secondary: #cccccc; - --color-text-tertiary: #888888; - --color-text-quaternary: #666666; - --color-text-disabled: #999999; - --color-text-error: #F44336; + --color-text-primary: rgb(var(--color-white-base)); + --color-text-secondary: rgb(204, 204, 204); + --color-text-tertiary: rgb(136, 136, 136); + --color-text-quaternary: rgb(102, 102, 102); + --color-text-disabled: rgb(153, 153, 153); + --color-text-error: var(--color-error); /* 特殊文字色 */ - --color-text-orange: #ff6b35; - --color-text-red: #ff0000; - --color-text-blue: #0064c8; + --color-text-orange: rgb(255, 107, 53); + --color-text-red: rgb(255, 0, 0); + --color-text-blue: rgb(0, 100, 200); + + /* ===== 优化透明度层级系统 ===== */ + + /* 主色调透明度变体 */ + --color-primary-rgb: rgba(var(--color-primary-base), 0.1); + --color-primary-rgb-3: rgba(var(--color-primary-base), 0.3); + --color-primary-rgb-4: rgba(var(--color-primary-base), 0.4); + + /* 状态色透明度变体 */ + --color-error-rgb-1: rgba(var(--color-error-base), 0.1); + --color-error-rgb-3: rgba(var(--color-error-base), 0.3); + + /* 白色透明度变体(标准5级层级)*/ + --color-white-rgb-05: rgba(var(--color-white-base), 0.05); + --color-white-rgb-1: rgba(var(--color-white-base), 0.1); + --color-white-rgb-15: rgba(var(--color-white-base), 0.15); + --color-white-rgb-2: rgba(var(--color-white-base), 0.2); + --color-white-rgb-3: rgba(var(--color-white-base), 0.3); + + /* 渐变背景 */ + --color-gradient-brand-bg: linear-gradient(135deg, rgba(var(--color-primary-base), 0.1) 0%, rgba(var(--color-primary-light-base), 0.05) 100%); + --color-gradient-brand-bg-2: linear-gradient(135deg, rgba(var(--color-primary-base), 0.2) 0%, rgba(var(--color-primary-light-base), 0.1) 100%); + --color-gradient-success: linear-gradient(135deg, rgba(var(--color-success-base), 0.1) 0%, rgba(var(--color-success-base), 0.05) 100%); + --color-gradient-info: linear-gradient(135deg, rgba(var(--color-info-base), 0.1) 0%, rgba(var(--color-info-base), 0.05) 100%); + --color-gradient-warning: linear-gradient(135deg, rgba(var(--color-warning-base), 0.1) 0%, rgba(var(--color-warning-base), 0.05) 100%); - /* 硬编码颜色变量替换 - 优化版本 */ - --color-primary-rgb: rgba(42, 92, 170, 0.1); - --color-primary-rgb-3: rgba(42, 92, 170, 0.3); - --color-primary-rgb-4: rgba(42, 92, 170, 0.4); - --color-error-rgb-1: rgba(244, 67, 54, 0.1); - --color-error-rgb-3: rgba(244, 67, 54, 0.3); - --color-white-rgb-05: rgba(255, 255, 255, 0.05); - --color-white-rgb-1: rgba(255, 255, 255, 0.1); - --color-white-rgb-15: rgba(255, 255, 255, 0.15); - --color-white-rgb-2: rgba(255, 255, 255, 0.2); - --color-white-rgb-3: rgba(255, 255, 255, 0.3); - --color-bg-dark-95: rgba(42, 42, 42, 0.95); - --color-shadow-black-3: rgba(0, 0, 0, 0.3); - --color-gradient-brand-bg: linear-gradient(135deg, rgba(42, 92, 170, 0.1) 0%, rgba(77, 148, 255, 0.05) 100%); - /* 阴影色 - 指向已有变量避免重复 */ --color-shadow-primary: var(--color-primary-rgb-3); --color-shadow-hover: var(--color-primary-rgb-4); - --color-shadow-card: 0 20px 40px rgba(0, 0, 0, 0.3); - + --color-shadow-card: 0 20px 40px rgba(var(--color-black-base), 0.3); + /* 滚动条 */ - --color-scrollbar-thumb: rgba(255, 255, 255, 0.2); - --color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.3); + --color-scrollbar-thumb: var(--color-white-rgb-2); + --color-scrollbar-thumb-hover: var(--color-white-rgb-3); --color-scrollbar-track: transparent; /* ===== 尺寸系统 ===== */ @@ -141,7 +167,14 @@ --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; - + + /* Z-Index层级 */ + --z-index-header: 1000; + --z-index-sidebar: 1000; + --z-index-modal: 1000; + --z-index-overlay: 999; + --z-index-dropdown: 998; + /* ===== 动画系统 ===== */ --transition-duration: 0.3s; --transition-timing: ease; @@ -149,25 +182,25 @@ /* 亮色主题(可选) */ [data-theme="light"] { - --color-bg-primary: #ffffff; - --color-bg-secondary: #f5f5f5; - --color-bg-tertiary: #fafafa; - --color-bg-quaternary: #eeeeee; - --color-bg-card: rgba(255, 255, 255, 0.9); - --color-bg-hover: rgba(0, 0, 0, 0.05); - --color-bg-active: rgba(42, 92, 170, 0.1); - --color-bg-input: rgba(0, 0, 0, 0.02); - - --color-border-primary: rgba(0, 0, 0, 0.1); - --color-border-secondary: rgba(0, 0, 0, 0.2); - - --color-text-primary: #1a1a1a; - --color-text-secondary: #333333; - --color-text-tertiary: #666666; - --color-text-quaternary: #999999; - --color-text-disabled: #888888; - - --color-shadow-card: 0 20px 40px rgba(0, 0, 0, 0.1); + --color-bg-primary: rgb(var(--color-white-base)); + --color-bg-secondary: rgb(245, 245, 245); + --color-bg-tertiary: rgb(250, 250, 250); + --color-bg-quaternary: rgb(238, 238, 238); + --color-bg-card: rgba(var(--color-white-base), 0.9); + --color-bg-hover: rgba(var(--color-black-base), 0.05); + --color-bg-active: rgba(var(--color-primary-base), 0.1); + --color-bg-input: rgba(var(--color-black-base), 0.02); + + --color-border-primary: rgba(var(--color-black-base), 0.1); + --color-border-secondary: rgba(var(--color-black-base), 0.2); + + --color-text-primary: rgb(26, 26, 26); + --color-text-secondary: rgb(51, 51, 51); + --color-text-tertiary: rgb(102, 102, 102); + --color-text-quaternary: rgb(153, 153, 153); + --color-text-disabled: rgb(136, 136, 136); + + --color-shadow-card: 0 20px 40px rgba(var(--color-black-base), 0.1); } /* 全局基础样式 */ @@ -263,20 +296,20 @@ html, body { } .btn-secondary:hover { - background: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-15); color: var(--color-text-primary); border-color: var(--color-border-primary); } .btn-error { - background: rgba(244, 67, 54, 0.1); - border-color: rgba(244, 67, 54, 0.3); + background: var(--color-error-rgb-1); + border-color: var(--color-error-rgb-3); color: var(--color-error); } .btn-error:hover { - background: rgba(244, 67, 54, 0.2); - border-color: rgba(244, 67, 54, 0.5); + background: var(--color-error-rgb-1); + border-color: var(--color-error-rgb-3); } /* 输入框基础样式 */ @@ -295,8 +328,8 @@ html, body { .form-input:focus { outline: none; border-color: var(--color-border-active); - box-shadow: 0 0 0 var(--input-focus-border-width) rgba(42, 92, 170, 0.1); - background: rgba(255, 255, 255, 0.08); + box-shadow: 0 0 0 var(--input-focus-border-width) var(--color-primary-rgb); + background: var(--color-white-rgb-05); } .form-input::placeholder { @@ -319,7 +352,7 @@ html, body { .card-header { padding: var(--spacing-2xl); border-bottom: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } .card-body { @@ -331,7 +364,7 @@ html, body { .card-footer { padding: var(--spacing-xl) var(--spacing-2xl); border-top: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } /* 布局工具类 */ @@ -393,12 +426,12 @@ html, body { /* 玻璃态效果 */ .glass { - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); + border: 1px solid var(--color-white-rgb-1); } .glass-hover:hover { - background: rgba(255, 255, 255, 0.08); - border-color: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-05); + border-color: var(--color-white-rgb-15); } \ No newline at end of file diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue index 1d6ccfe..ec8f11f 100644 --- a/src/components/layout/AppHeader.vue +++ b/src/components/layout/AppHeader.vue @@ -64,7 +64,7 @@ border-bottom: 1px solid var(--color-border-primary); padding: 0 20px; position: relative; - z-index: 1000; + z-index: var(--z-index-header); } .navbar-left { diff --git a/src/components/layout/CadSidebar.vue b/src/components/layout/CadSidebar.vue index 22036b2..8433441 100644 --- a/src/components/layout/CadSidebar.vue +++ b/src/components/layout/CadSidebar.vue @@ -138,7 +138,7 @@ const testConnection = (software) => { align-items: center; gap: 8px; padding: 12px; - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); border-radius: 6px; font-size: 14px; } @@ -201,14 +201,14 @@ const testConnection = (software) => { align-items: flex-start; gap: 12px; padding: 12px; - background: rgba(255, 255, 255, 0.03); + background: var(--color-white-rgb-05); border-radius: 6px; cursor: pointer; transition: all 0.3s ease; } .option-item:hover { - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); } .option-item input[type="radio"] { @@ -275,11 +275,11 @@ const testConnection = (software) => { } .side-panel::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.2); + background: var(--color-white-rgb-2); border-radius: 3px; } .side-panel::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.3); + background: var(--color-white-rgb-3); } \ No newline at end of file diff --git a/src/components/layout/ContentArea.vue b/src/components/layout/ContentArea.vue index bba95be..ad308c0 100644 --- a/src/components/layout/ContentArea.vue +++ b/src/components/layout/ContentArea.vue @@ -87,8 +87,8 @@ defineProps({ } .content-card { - background: rgba(42, 42, 42, 0.8); - border: 1px solid rgba(255, 255, 255, 0.1); + background: var(--color-bg-dark-8); + border: 1px solid var(--color-white-rgb-1); border-radius: 12px; height: 100%; display: flex; @@ -101,8 +101,8 @@ defineProps({ align-items: center; justify-content: space-between; padding: 20px 24px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.02); + border-bottom: 1px solid var(--color-white-rgb-1); + background: var(--color-white-rgb-05); flex-shrink: 0; } @@ -128,8 +128,8 @@ defineProps({ .card-footer { padding: 16px 24px; - border-top: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.02); + border-top: 1px solid var(--color-white-rgb-1); + background: var(--color-white-rgb-05); flex-shrink: 0; } @@ -172,12 +172,12 @@ defineProps({ } .card-body::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.2); + background: var(--color-white-rgb-2); border-radius: 3px; } .card-body::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.3); + background: var(--color-white-rgb-3); } /* 按钮基础样式 */ @@ -186,9 +186,9 @@ defineProps({ align-items: center; gap: 8px; padding: 8px 16px; - border: 1px solid rgba(255, 255, 255, 0.2); + border: 1px solid var(--color-white-rgb-2); border-radius: 6px; - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); color: var(--color-text-primary); font-size: 14px; cursor: pointer; @@ -197,8 +197,8 @@ defineProps({ } .btn:hover { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.3); + background: var(--color-white-rgb-1); + border-color: var(--color-white-rgb-3); } .btn-primary { @@ -209,17 +209,17 @@ defineProps({ .btn-primary:hover { background: var(--color-primary-gradient-hover); - box-shadow: 0 4px 15px rgba(42, 92, 170, 0.3); + box-shadow: 0 4px 15px var(--color-primary-rgb-3); } .btn-secondary { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.2); + background: var(--color-white-rgb-1); + border-color: var(--color-white-rgb-2); color: var(--color-text-secondary); } .btn-secondary:hover { - background: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-15); color: var(--color-text-primary); } \ No newline at end of file diff --git a/src/components/layout/MainLayout.vue b/src/components/layout/MainLayout.vue index 6d2e5a6..c6eed7d 100644 --- a/src/components/layout/MainLayout.vue +++ b/src/components/layout/MainLayout.vue @@ -70,7 +70,7 @@ import AppHeader from './AppHeader.vue' .app-header { height: 60px; flex-shrink: 0; - z-index: 1000; + z-index: var(--z-index-sidebar); } .app-body { @@ -123,7 +123,7 @@ import AppHeader from './AppHeader.vue' display: flex; align-items: center; justify-content: center; - background: rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-1); border: none; border-radius: 6px; color: var(--color-text-secondary); @@ -132,7 +132,7 @@ import AppHeader from './AppHeader.vue' } .tool-btn:hover { - background: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-15); color: var(--color-text-primary); } @@ -219,12 +219,12 @@ import AppHeader from './AppHeader.vue' .app-sidebar::-webkit-scrollbar-thumb, .work-content::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.2); + background: var(--color-white-rgb-2); border-radius: 3px; } .app-sidebar::-webkit-scrollbar-thumb:hover, .work-content::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.3); + background: var(--color-white-rgb-3); } \ No newline at end of file diff --git a/src/components/layout/ModelManagement.vue b/src/components/layout/ModelManagement.vue index affc19f..e600dde 100644 --- a/src/components/layout/ModelManagement.vue +++ b/src/components/layout/ModelManagement.vue @@ -389,16 +389,16 @@ const openSelectedFile = async () => { } .action-card:hover .action-card-inner { - background: rgba(255, 255, 255, 0.08); - border-color: rgba(255, 255, 255, 0.2); + background: var(--color-white-rgb-05); + border-color: var(--color-white-rgb-2); transform: translateY(-4px); - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2); + box-shadow: 0 12px 30px var(--color-black-rgb-2); } .action-card.active .action-card-inner { - background: rgba(42, 92, 170, 0.1); + background: var(--color-primary-rgb); border-color: var(--color-primary); - box-shadow: 0 0 20px rgba(42, 92, 170, 0.2); + box-shadow: 0 0 20px var(--color-primary-rgb-2); } .action-card.active::before { @@ -430,7 +430,7 @@ const openSelectedFile = async () => { justify-content: center; width: 80px; height: 80px; - background: linear-gradient(135deg, rgba(42, 92, 170, 0.1) 0%, rgba(77, 148, 255, 0.05) 100%); + background: linear-gradient(135deg, var(--color-primary-rgb) 0%, var(--color-primary-light-rgb-05) 100%); border-radius: var(--size-border-radius); font-size: 32px; color: var(--color-primary); @@ -446,7 +446,7 @@ const openSelectedFile = async () => { left: -50%; width: 200%; height: 200%; - background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent); + background: linear-gradient(45deg, transparent, var(--color-white-rgb-1), transparent); transform: rotate(45deg); transition: all 0.6s ease; } @@ -465,9 +465,9 @@ const openSelectedFile = async () => { } .action-card.active .action-icon { - background: linear-gradient(135deg, rgba(42, 92, 170, 0.2) 0%, rgba(77, 148, 255, 0.1) 100%); + background: linear-gradient(135deg, var(--color-primary-rgb-2) 0%, var(--color-primary-light-rgb-1) 100%); color: var(--color-primary); - box-shadow: 0 0 20px rgba(42, 92, 170, 0.3); + box-shadow: 0 0 20px var(--color-primary-rgb-3); } .action-badge { @@ -484,7 +484,7 @@ const openSelectedFile = async () => { justify-content: center; font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); - box-shadow: 0 2px 8px rgba(42, 92, 170, 0.3); + box-shadow: 0 2px 8px var(--color-primary-rgb-3); z-index: 2; } @@ -513,15 +513,15 @@ const openSelectedFile = async () => { color: var(--color-error); font-weight: var(--font-weight-medium); padding: var(--spacing-xs) var(--spacing-sm); - background: rgba(244, 67, 54, 0.1); + background: var(--color-error-rgb-1); border-radius: var(--size-border-radius); - border: 1px solid rgba(244, 67, 54, 0.2); + border: 1px solid var(--color-error-rgb-1); } .action-preview { padding: var(--spacing-md) var(--spacing-lg); - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-05); + border: 1px solid var(--color-white-rgb-1); border-radius: var(--size-border-radius); display: flex; align-items: center; @@ -563,11 +563,11 @@ const openSelectedFile = async () => { left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.6); + background: var(--color-black-rgb-6); display: flex; align-items: center; justify-content: center; - z-index: 1000; + z-index: var(--z-index-modal); backdrop-filter: blur(4px); } @@ -580,7 +580,7 @@ const openSelectedFile = async () => { max-height: 70vh; display: flex; flex-direction: column; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4); + box-shadow: 0 20px 40px var(--color-black-rgb-4); overflow: hidden; transform: scale(1); transition: all var(--transition-duration) var(--transition-timing); @@ -592,7 +592,7 @@ const openSelectedFile = async () => { justify-content: space-between; padding: var(--spacing-xl); border-bottom: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } .dialog-title-section { @@ -647,7 +647,7 @@ const openSelectedFile = async () => { gap: var(--spacing-sm); margin-bottom: var(--spacing-lg); padding: var(--spacing-sm) var(--spacing-md); - background: rgba(255, 255, 255, 0.03); + background: var(--color-white-rgb-05); border-radius: var(--size-border-radius); font-size: var(--font-size-sm); color: var(--color-text-secondary); @@ -685,14 +685,14 @@ const openSelectedFile = async () => { } .file-item:hover { - background: rgba(255, 255, 255, 0.05); - border-color: rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-05); + border-color: var(--color-white-rgb-1); } .file-item.selected { - background: rgba(42, 92, 170, 0.1); + background: var(--color-primary-rgb); border-color: var(--color-primary); - box-shadow: 0 0 15px rgba(42, 92, 170, 0.2); + box-shadow: 0 0 15px var(--color-primary-rgb-2); } .file-item.recent { @@ -705,7 +705,7 @@ const openSelectedFile = async () => { justify-content: center; width: 40px; height: 40px; - background: rgba(42, 92, 170, 0.1); + background: var(--color-primary-rgb); border-radius: var(--size-border-radius); color: var(--color-primary); font-size: var(--font-size-lg); @@ -766,7 +766,7 @@ const openSelectedFile = async () => { justify-content: space-between; padding: var(--spacing-xl); border-top: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } .dialog-info { diff --git a/src/components/layout/OpenedModelsTable.vue b/src/components/layout/OpenedModelsTable.vue index 7fc3184..b41f43d 100644 --- a/src/components/layout/OpenedModelsTable.vue +++ b/src/components/layout/OpenedModelsTable.vue @@ -188,16 +188,20 @@ import { useCADStore } from '@/stores/cad' // 时间常量配置 const TIME_CONSTANTS = { + // 基础时间单位 MILLISECONDS_PER_SECOND: 1000, SECONDS_PER_MINUTE: 60, MINUTES_PER_HOUR: 60, - HOURS_PER_DAY: 24, - // 计算常量 - MILLISECONDS_PER_MINUTE: 1000 * 60, - MILLISECONDS_PER_HOUR: 1000 * 60 * 60, - MILLISECONDS_PER_DAY: 1000 * 60 * 60 * 24, + HOURS_PER_DAY: 24 +} + +// 计算常量 - 使用基础常量计算避免魔术数字 +const DERIVED_TIME_CONSTANTS = { + MILLISECONDS_PER_MINUTE: TIME_CONSTANTS.MILLISECONDS_PER_SECOND * TIME_CONSTANTS.SECONDS_PER_MINUTE, + MILLISECONDS_PER_HOUR: TIME_CONSTANTS.MILLISECONDS_PER_SECOND * TIME_CONSTANTS.SECONDS_PER_MINUTE * TIME_CONSTANTS.MINUTES_PER_HOUR, + MILLISECONDS_PER_DAY: TIME_CONSTANTS.MILLISECONDS_PER_SECOND * TIME_CONSTANTS.SECONDS_PER_MINUTE * TIME_CONSTANTS.MINUTES_PER_HOUR * TIME_CONSTANTS.HOURS_PER_DAY, // 业务常量 - RECENT_MODEL_THRESHOLD: 1000 * 60 * 60 // 1小时内算最近 + RECENT_MODEL_THRESHOLD: TIME_CONSTANTS.MILLISECONDS_PER_SECOND * TIME_CONSTANTS.SECONDS_PER_MINUTE * TIME_CONSTANTS.MINUTES_PER_HOUR // 1小时内算最近 } const emit = defineEmits(['select', 'view', 'export', 'close', 'refresh', 'add']) @@ -255,7 +259,7 @@ const refreshModels = async () => { const isRecentModel = (model) => { const now = new Date() const diff = now - model.openTime - return diff < TIME_CONSTANTS.RECENT_MODEL_THRESHOLD + return diff < DERIVED_TIME_CONSTANTS.RECENT_MODEL_THRESHOLD } const getModelIconClass = (model) => { @@ -294,9 +298,9 @@ const getSourceIcon = (source) => { const formatTime = (time) => { const now = new Date() const diff = now - time - const minutes = Math.floor(diff / TIME_CONSTANTS.MILLISECONDS_PER_MINUTE) - const hours = Math.floor(diff / TIME_CONSTANTS.MILLISECONDS_PER_HOUR) - const days = Math.floor(diff / TIME_CONSTANTS.MILLISECONDS_PER_DAY) + const minutes = Math.floor(diff / DERIVED_TIME_CONSTANTS.MILLISECONDS_PER_MINUTE) + const hours = Math.floor(diff / DERIVED_TIME_CONSTANTS.MILLISECONDS_PER_HOUR) + const days = Math.floor(diff / DERIVED_TIME_CONSTANTS.MILLISECONDS_PER_DAY) if (minutes < TIME_CONSTANTS.MINUTES_PER_HOUR) { return `${minutes}分钟前` @@ -334,8 +338,8 @@ const formatTimeDetail = (time) => { align-items: center; justify-content: space-between; padding: var(--spacing-lg); - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-05); + border: 1px solid var(--color-white-rgb-1); border-radius: var(--size-border-radius-card); backdrop-filter: blur(10px); } @@ -390,7 +394,7 @@ const formatTimeDetail = (time) => { } .models-table-container:hover { - box-shadow: 0 25px 50px rgba(0, 0, 0, 0.35); + box-shadow: 0 25px 50px var(--color-black-rgb-35); } .table-wrapper { @@ -401,11 +405,11 @@ const formatTimeDetail = (time) => { width: 100%; border-collapse: collapse; font-size: 16px; - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } .models-table th { - background: rgba(255, 255, 255, 0.03); + background: var(--color-white-rgb-05); border-bottom: 2px solid var(--color-border-primary); padding: var(--spacing-xl) var(--spacing-lg); text-align: left; @@ -468,7 +472,7 @@ const formatTimeDetail = (time) => { } .model-row:hover { - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); transform: translateX(4px); } @@ -477,7 +481,7 @@ const formatTimeDetail = (time) => { } .model-row.active { - background: rgba(42, 92, 170, 0.1); + background: var(--color-primary-rgb); } .model-row.active::before { @@ -486,7 +490,7 @@ const formatTimeDetail = (time) => { } .model-row.recent { - background: rgba(255, 152, 0, 0.05); + background: var(--color-warning-rgb-05); } .model-row:last-child td { @@ -527,7 +531,7 @@ const formatTimeDetail = (time) => { justify-content: center; width: 48px; height: 48px; - background: linear-gradient(135deg, rgba(42, 92, 170, 0.1) 0%, rgba(77, 148, 255, 0.05) 100%); + background: linear-gradient(135deg, var(--color-primary-rgb) 0%, var(--color-primary-light-rgb-05) 100%); border-radius: var(--size-border-radius); color: var(--color-primary); font-size: 20px; @@ -535,17 +539,17 @@ const formatTimeDetail = (time) => { } .model-icon.assembly { - background: linear-gradient(135deg, rgba(76, 175, 80, 0.1) 0%, rgba(76, 175, 80, 0.05) 100%); + background: var(--color-gradient-success); color: var(--color-success); } .model-icon.part { - background: linear-gradient(135deg, rgba(33, 150, 243, 0.1) 0%, rgba(33, 150, 243, 0.05) 100%); + background: var(--color-gradient-info); color: var(--color-info); } .model-icon.drawing { - background: linear-gradient(135deg, rgba(255, 152, 0, 0.1) 0%, rgba(255, 152, 0, 0.05) 100%); + background: linear-gradient(135deg, var(--color-warning-rgb-1) 0%, var(--color-warning-rgb-05) 100%); color: var(--color-warning); } @@ -590,7 +594,7 @@ const formatTimeDetail = (time) => { } .model-version { - background: rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-1); padding: 2px 6px; border-radius: 4px; font-weight: var(--font-weight-medium); @@ -612,7 +616,7 @@ const formatTimeDetail = (time) => { justify-content: center; width: 32px; height: 32px; - background: rgba(255, 255, 255, 0.1); + background: var(--color-white-rgb-1); border-radius: var(--size-border-radius); color: var(--color-text-secondary); font-size: var(--font-size-base); @@ -620,17 +624,17 @@ const formatTimeDetail = (time) => { } .source-icon.solidworks { - background: rgba(255, 107, 53, 0.1); + background: var(--color-orange-rgb-1); color: var(--color-text-orange); } .source-icon.autocad { - background: rgba(255, 0, 0, 0.1); + background: var(--color-red-rgb-1); color: var(--color-text-red); } .source-icon.creo { - background: rgba(0, 100, 200, 0.1); + background: var(--color-blue-rgb-1); color: var(--color-text-blue); } @@ -699,17 +703,17 @@ const formatTimeDetail = (time) => { .action-btn.view-btn:hover { color: var(--color-info); - background: rgba(33, 150, 243, 0.1); + background: var(--color-info-rgb-1); } .action-btn.export-btn:hover { color: var(--color-success); - background: rgba(76, 175, 80, 0.1); + background: var(--color-success-rgb-1); } .action-btn.close-btn:hover { color: var(--color-error); - background: rgba(244, 67, 54, 0.1); + background: var(--color-error-rgb-1); } /* 空状态 */ @@ -721,13 +725,13 @@ const formatTimeDetail = (time) => { padding: var(--spacing-4xl); color: var(--color-text-tertiary); text-align: center; - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } .empty-icon { width: 80px; height: 80px; - background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%); + background: linear-gradient(135deg, var(--color-white-rgb-05) 0%, var(--color-white-rgb-05) 100%); border-radius: 50%; display: flex; align-items: center; diff --git a/src/components/ui/BaseButton.vue b/src/components/ui/BaseButton.vue index 20a57d1..cc1266d 100644 --- a/src/components/ui/BaseButton.vue +++ b/src/components/ui/BaseButton.vue @@ -139,7 +139,7 @@ const handleClick = (event) => { } .btn-secondary:hover:not(:disabled) { - background: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-15); color: var(--color-text-primary); border-color: var(--color-border-primary); transform: translateY(-1px); @@ -156,8 +156,8 @@ const handleClick = (event) => { } .btn-error:hover:not(:disabled) { - background: rgba(244, 67, 54, 0.2); - border-color: rgba(244, 67, 54, 0.5); + background: var(--color-error-rgb-1); + border-color: var(--color-error-rgb-3); transform: translateY(-1px); } diff --git a/src/components/ui/BaseCard.vue b/src/components/ui/BaseCard.vue index 56510ba..83f5304 100644 --- a/src/components/ui/BaseCard.vue +++ b/src/components/ui/BaseCard.vue @@ -71,27 +71,27 @@ const cardClasses = computed(() => { } .card-hover:hover { - background: rgba(42, 42, 42, 0.9); + background: var(--color-bg-dark-95); border-color: var(--color-primary); transform: translateY(-2px); box-shadow: var(--color-shadow-hover); } .card-glass { - background: rgba(255, 255, 255, 0.05); + background: var(--color-white-rgb-05); backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); + border: 1px solid var(--color-white-rgb-1); } .card-glass:hover { - background: rgba(255, 255, 255, 0.08); - border-color: rgba(255, 255, 255, 0.15); + background: var(--color-white-rgb-05); + border-color: var(--color-white-rgb-15); } .card-header { padding: var(--spacing-2xl); border-bottom: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); display: flex; align-items: center; justify-content: space-between; @@ -112,7 +112,7 @@ const cardClasses = computed(() => { .card-footer { padding: var(--spacing-xl) var(--spacing-2xl); border-top: 1px solid var(--color-border-primary); - background: rgba(255, 255, 255, 0.02); + background: var(--color-white-rgb-05); } /* 内边距变体 */ diff --git a/src/components/ui/BaseInput.vue b/src/components/ui/BaseInput.vue index 963ce3f..76f442c 100644 --- a/src/components/ui/BaseInput.vue +++ b/src/components/ui/BaseInput.vue @@ -178,8 +178,8 @@ const clearInput = () => { .form-input:focus { outline: none; border-color: var(--color-border-active); - box-shadow: 0 0 0 var(--input-focus-border-width) rgba(42, 92, 170, 0.1); - background: rgba(255, 255, 255, 0.08); + box-shadow: 0 0 0 var(--input-focus-border-width) var(--color-primary-rgb); + background: var(--color-white-rgb-05); } .form-input::placeholder { @@ -205,7 +205,7 @@ const clearInput = () => { .form-input-error:focus { border-color: var(--color-border-error); - box-shadow: 0 0 0 var(--input-focus-border-width) rgba(244, 67, 54, 0.1); + box-shadow: 0 0 0 var(--input-focus-border-width) var(--color-error-rgb-1); } /* 图标样式 */ diff --git a/src/components/ui/CadSoftwareGrid.vue b/src/components/ui/CadSoftwareGrid.vue index 965589f..589945c 100644 --- a/src/components/ui/CadSoftwareGrid.vue +++ b/src/components/ui/CadSoftwareGrid.vue @@ -107,12 +107,12 @@ const testConnection = (software) => { .software-item:hover { border-color: var(--color-border-active); transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(42,92,170,0.2); + box-shadow: 0 4px 12px var(--color-primary-rgb-2); } .software-item.active { border-color: var(--color-secondary); - background-color: rgba(255,107,53,0.1); + background-color: var(--color-orange-rgb-1); } .software-item.connected { @@ -170,17 +170,17 @@ const testConnection = (software) => { width: var(--size-connection-dot); height: var(--size-connection-dot); border-radius: 50%; - border: 1px solid rgba(255,255,255,0.3); + border: 1px solid var(--color-white-rgb-3); } .connection-dot.connected { background-color: var(--color-success); - box-shadow: 0 0 6px rgba(76,175,80,0.5); + box-shadow: 0 0 6px var(--color-success-rgb-5); } .connection-dot.disconnected { background-color: var(--color-error); - box-shadow: 0 0 6px rgba(244,67,54,0.5); + box-shadow: 0 0 6px var(--color-error-rgb-3); } .connection-test-btn { diff --git a/src/config/auth.js b/src/config/auth.js index 43625ab..ebb8d34 100644 --- a/src/config/auth.js +++ b/src/config/auth.js @@ -41,6 +41,12 @@ const AUTH_CONFIG = { TIMEOUTS: { login: 5000, // 登录超时 validate: 3000 // 验证超时 + }, + + // 验证规则 + VALIDATION_RULES: { + MIN_USERNAME_LENGTH: 2, // 用户名最小长度 + MIN_PASSWORD_LENGTH: 6 // 密码最小长度 } } @@ -78,6 +84,11 @@ export const getAuthTimeouts = () => { return AUTH_CONFIG.TIMEOUTS } +// 获取验证规则 +export const getValidationRules = () => { + return AUTH_CONFIG.VALIDATION_RULES +} + // 验证用户凭据(模拟验证) export const validateCredentials = (username, password) => { const mockCreds = getMockCredentials() diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue index d9b1b89..3399fc7 100644 --- a/src/views/DashboardView.vue +++ b/src/views/DashboardView.vue @@ -94,14 +94,79 @@ - +
- + @@ -120,7 +185,7 @@ import ContentArea from '@/components/layout/ContentArea.vue' import BaseButton from '@/components/ui/BaseButton.vue' // 当前页面状态 -const currentPage = ref('connection') +const currentPage = ref('home') // 导航点击处理 const handleNavClick = (navItem) => { @@ -386,4 +451,148 @@ const openSettings = () => { background: var(--color-white-rgb-15); color: var(--color-text-primary); } + +/* 欢迎页面样式 */ +.welcome-page { + display: flex; + flex-direction: column; + gap: 32px; + padding: 20px 0; + max-width: 800px; + margin: 0 auto; + line-height: 1.6; +} + +.project-description { + text-align: center; + margin-bottom: 20px; +} + +.project-description p { + font-size: 16px; + color: var(--color-text-secondary); + line-height: 1.8; + margin: 0; + padding: 0 20px; +} + +.section-title { + display: flex; + align-items: center; + gap: 12px; + font-size: 18px; + font-weight: 600; + color: var(--color-text-primary); + margin: 0 0 20px 0; + border-bottom: 2px solid var(--color-primary-rgb); + padding-bottom: 8px; +} + +.section-title i { + color: var(--color-primary); + font-size: 20px; +} + +.feature-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 20px; +} + +.feature-item { + background: var(--color-white-rgb-05); + border: 1px solid var(--color-white-rgb-1); + border-radius: 8px; + padding: 20px; + transition: all 0.3s ease; +} + +.feature-item:hover { + background: var(--color-white-rgb-1); + border-color: var(--color-white-rgb-2); + transform: translateY(-2px); +} + +.feature-item h4 { + display: flex; + align-items: center; + gap: 10px; + font-size: 16px; + font-weight: 600; + color: var(--color-text-primary); + margin: 0 0 12px 0; +} + +.feature-item h4 i { + color: var(--color-primary); + font-size: 18px; + width: 20px; + text-align: center; +} + +.feature-item p { + font-size: 14px; + color: var(--color-text-secondary); + line-height: 1.6; + margin: 0; +} + +.tech-description p { + font-size: 15px; + color: var(--color-text-secondary); + line-height: 1.7; + margin: 0; + padding: 0 10px; + text-align: justify; +} + +.guide-section { + text-align: center; + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid var(--color-white-rgb-1); +} + +.guide-text { + display: inline-flex; + align-items: center; + gap: 10px; + font-size: 16px; + color: var(--color-text-tertiary); + background: var(--color-white-rgb-05); + padding: 12px 20px; + border-radius: 6px; + border: 1px solid var(--color-white-rgb-1); +} + +.guide-text i { + color: var(--color-primary); + font-size: 18px; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .welcome-page { + padding: 15px; + gap: 24px; + } + + .feature-list { + grid-template-columns: 1fr; + gap: 16px; + } + + .project-description p { + font-size: 15px; + padding: 0 10px; + } + + .section-title { + font-size: 16px; + } + + .feature-item { + padding: 16px; + } +} \ No newline at end of file diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 22c925e..d627560 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -128,10 +128,14 @@ import { ref, computed, onMounted } from 'vue' import { useRouter } from 'vue-router' import { useAuthStore } from '@/stores/auth' +import { getValidationRules } from '@/config/auth' const router = useRouter() const authStore = useAuthStore() +// 获取验证规则配置 +const validationRules = getValidationRules() + // 表单数据 const formData = ref({ username: '', @@ -169,8 +173,8 @@ const validateField = (field) => { case 'username': if (!formData.value.username.trim()) { errors.value.username = '请输入用户名' - } else if (formData.value.username.length < 2) { - errors.value.username = '用户名至少2个字符' + } else if (formData.value.username.length < validationRules.MIN_USERNAME_LENGTH) { + errors.value.username = `用户名至少${validationRules.MIN_USERNAME_LENGTH}个字符` } else { errors.value.username = '' } @@ -179,8 +183,8 @@ const validateField = (field) => { case 'password': if (!formData.value.password.trim()) { errors.value.password = '请输入密码' - } else if (formData.value.password.length < 6) { - errors.value.password = '密码至少6个字符' + } else if (formData.value.password.length < validationRules.MIN_PASSWORD_LENGTH) { + errors.value.password = `密码至少${validationRules.MIN_PASSWORD_LENGTH}个字符` } else { errors.value.password = '' }