feat: 全面UI优化 — 5套主题系统 + 设计体系 + 菜单重组 + 页面优化
1. 主题系统扩展 (5套主题) - ocean-deep(深海蓝) / light-professional(明亮白) / midnight-purple(午夜紫) - pine-green(松林绿) / orange-vitality(活力橙) - useTheme hook 重写支持5主题 + 向后兼容 - AppearanceSettings 5主题预览卡片 2. 设计体系 (index.css) - 按钮系统: dg-btn-primary/secondary/ghost/danger + 尺寸变体 - 徽章系统: dg-badge-* (8色) - 卡片/表格: dg-card-section, dg-table-row, dg-table-header - 状态点: dg-status-dot-* (4色) - 动效关键帧: slideInLeft, scaleIn 3. 菜单重组 (menu.ts) - 5分组: 概览/数据源/工单/权限/系统 - 6个图标更新: Code2/FileEdit/ShieldCheck/FolderLock/ScrollText/Timer - 新增 permission 权限码字段 4. Layout 侧边栏增强 - 左侧渐变指示条 + 发光效果 - hover 微动画 + 图标变色 - 面包屑导航头部 - 主题切换循环5主题 5. 核心页面优化 - TicketsPage: 设计系统类 + 颜色对齐 - QueriesPage: 去Card依赖 + dg-table/dg-btn统一 - Breadcrumb组件 + useBreadcrumb hook
This commit is contained in:
1 parent
4e2df4d3d7
commit
746a000e8a
25 files changed
+7718
-178
No files matched your search
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
import { useTheme, THEME_OPTIONS, type Theme } from '@/hooks/useTheme';
|
||||
import { LOGIN_STYLE_OPTIONS, type LoginStyle } from '@/pages/LoginPage';
|
||||
import { Sun, Moon, Check, Save, Loader2 } from 'lucide-react';
|
||||
import { Check, Save, Loader2 } from 'lucide-react';
|
||||
import api from '@/api/request';
|
||||
import { toast } from '@/hooks/useToast';
|
||||
|
||||
@@ -16,7 +16,15 @@ export default function AppearanceSettings() {
|
||||
useEffect(() => {
|
||||
api.get<{ theme?: string; login_style?: string }>('/user/preferences')
|
||||
.then(prefs => {
|
||||
if (prefs?.theme) setTheme(prefs.theme as 'dark' | 'light');
|
||||
if (prefs?.theme) {
|
||||
// Backward compat: map old values
|
||||
const t = prefs.theme;
|
||||
if (t === 'dark' || t === 'light') {
|
||||
setTheme(t === 'dark' ? 'ocean-deep' : 'light-professional');
|
||||
} else if (THEME_OPTIONS.some(o => o.id === t)) {
|
||||
setTheme(t as Theme);
|
||||
}
|
||||
}
|
||||
if (prefs?.login_style) setLoginStyle(prefs.login_style as LoginStyle);
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -27,7 +35,7 @@ export default function AppearanceSettings() {
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const handleThemeChange = (t: 'dark' | 'light') => {
|
||||
const handleThemeChange = (t: Theme) => {
|
||||
setTheme(t);
|
||||
setDirty(true);
|
||||
};
|
||||
@@ -66,24 +74,36 @@ export default function AppearanceSettings() {
|
||||
<div className="space-y-8">
|
||||
{/* Theme Mode */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold mb-3">主题模式</h3>
|
||||
<div className="flex gap-3">
|
||||
{([
|
||||
{ id: 'dark' as const, icon: Moon, label: '深色模式' },
|
||||
{ id: 'light' as const, icon: Sun, label: '浅色模式' },
|
||||
]).map(opt => (
|
||||
<h3 className="text-sm font-semibold mb-1">主题模式</h3>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] mb-4">选择界面配色方案,即时预览效果</p>
|
||||
<div className="grid grid-cols-5 gap-3">
|
||||
{THEME_OPTIONS.map(opt => (
|
||||
<button
|
||||
key={opt.id}
|
||||
onClick={() => handleThemeChange(opt.id)}
|
||||
className={`flex items-center gap-2 px-5 py-3 rounded-xl text-sm font-medium transition-all ${
|
||||
theme === opt.id
|
||||
? 'bg-blue-500/15 text-blue-400 ring-1 ring-blue-500/30'
|
||||
: 'bg-[var(--dg-bg-tertiary)] text-[var(--dg-text-secondary)] hover:bg-[var(--dg-bg-hover)]'
|
||||
className={`group relative rounded-xl p-4 text-left transition-all bg-[var(--dg-bg-tertiary)] hover:bg-[var(--dg-bg-hover)] ${
|
||||
theme === opt.id ? 'ring-2 ring-blue-500/50' : ''
|
||||
}`}
|
||||
>
|
||||
<opt.icon className="w-4 h-4" />
|
||||
{opt.label}
|
||||
{theme === opt.id && <Check className="w-3.5 h-3.5 ml-1" />}
|
||||
{/* Color preview swatch */}
|
||||
<div
|
||||
className="w-full h-6 rounded-md mb-3"
|
||||
style={{
|
||||
background: opt.isDark
|
||||
? `linear-gradient(135deg, ${opt.primaryColor} 0%, color-mix(in srgb, ${opt.primaryColor} 40%, #1a1a2e) 50%, #0d1117 100%)`
|
||||
: `linear-gradient(135deg, ${opt.primaryColor} 0%, color-mix(in srgb, ${opt.primaryColor} 60%, #ffffff) 50%, #f8fafc 100%)`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Active check mark */}
|
||||
{theme === opt.id && (
|
||||
<div className="absolute top-2 right-2 w-5 h-5 rounded-full bg-blue-500 flex items-center justify-center">
|
||||
<Check className="w-3 h-3 text-white" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h4 className="text-sm font-medium mb-0.5">{opt.name}</h4>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] leading-snug">{opt.description}</p>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user