Jelajahi Sumber

feat: 新增主题样式/并可切换主题

Mickey Mike 4 jam lalu
induk
melakukan
a99500bdd8

+ 6 - 0
apps/web/src/assets/icons/branch.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+  <line x1="6" y1="3" x2="6" y2="15"></line>
+  <circle cx="18" cy="6" r="3"></circle>
+  <circle cx="18" cy="18" r="3"></circle>
+  <path d="M18 9v2a4 4 0 0 1-4 4H7"></path>
+</svg>

+ 4 - 0
apps/web/src/assets/icons/chain.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+  <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
+  <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
+</svg>

+ 3 - 0
apps/web/src/assets/icons/moon.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+  <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
+</svg>

+ 4 - 0
apps/web/src/assets/icons/settings-gear.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+  <circle cx="12" cy="12" r="3"></circle>
+  <path d="M12 1v6m0 6v6M4.22 4.22l4.24 4.24m5.08 5.08l4.24 4.24M1 12h6m6 0h6M4.22 19.78l4.24-4.24m5.08-5.08l4.24-4.24"></path>
+</svg>

+ 11 - 0
apps/web/src/assets/icons/sun.svg

@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+  <circle cx="12" cy="12" r="5"></circle>
+  <line x1="12" y1="1" x2="12" y2="3"></line>
+  <line x1="12" y1="21" x2="12" y2="23"></line>
+  <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
+  <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
+  <line x1="1" y1="12" x2="3" y2="12"></line>
+  <line x1="21" y1="12" x2="23" y2="12"></line>
+  <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
+  <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
+</svg>

+ 8 - 8
apps/web/src/components/SearchDialog/index.vue

@@ -184,7 +184,7 @@ onUnmounted(() => {
 .search-dialog-container {
 	width: 600px;
 	max-height: 70vh;
-	background: #fff;
+	background: var(--bg-base);
 	border-radius: 12px;
 	box-shadow:
 		0 3px 12px rgba(0, 0, 0, 0.15),
@@ -208,11 +208,11 @@ onUnmounted(() => {
 
 .search-header {
 	padding: 16px 20px;
-	border-bottom: 1px solid #f0f0f0;
+	border-bottom: 1px solid var(--border-light);
 	display: flex;
 	gap: 12px;
 	align-items: center;
-	background: #fafafa;
+	background: var(--bg-container);
 
 	:deep(.el-input) {
 		input {
@@ -220,7 +220,7 @@ onUnmounted(() => {
 			font-size: 14px;
 
 			&::placeholder {
-				color: #d0d0d0;
+				color: var(--text-placeholder);
 			}
 		}
 	}
@@ -255,7 +255,7 @@ onUnmounted(() => {
 
 .section-title {
 	font-size: 12px;
-	color: #999;
+	color: var(--text-tertiary);
 	padding: 8px 20px;
 	font-weight: 500;
 	text-transform: uppercase;
@@ -279,11 +279,11 @@ onUnmounted(() => {
 	align-items: center;
 	gap: 12px;
 	transition: all 0.2s ease;
-	color: #333;
+	color: var(--text-primary);
 	font-size: 13px;
 
 	&:hover {
-		background: #f5f5f5;
+		background: var(--bg-container);
 		color: #ff6b6b;
 
 		.item-icon {
@@ -292,7 +292,7 @@ onUnmounted(() => {
 	}
 
 	&.action-item {
-		color: #999;
+		color: var(--text-tertiary);
 
 		&:hover {
 			color: #ff6b6b;

+ 6 - 6
apps/web/src/components/SetterCommon/Code/CodeEditor.vue

@@ -20,7 +20,7 @@ interface CodeEditorType {
     appendTo?: string | HTMLElement
     // 内容
     modelValue?: any
-    // 语法  
+    // 语法
     language?: string
     // 主题
     theme?: 'vs-light' | 'vs-dark'
@@ -86,7 +86,7 @@ const languageSource = [
 
 /**
  * @description: formatValue为json 格式,需要转换处理
- * @return 
+ * @return
  */
 const formatValue = (value: any) => {
     if (props.formatValue === 'json') {
@@ -337,12 +337,12 @@ defineExpose({
 
 // light
 .editor-tooltip--light {
-    background-color: #ffffff !important;
+    background-color: var(--bg-base) !important;
     color: #1e1e1e !important;
     border: 1px solid #e5e7eb;
 
     .el-popper__arrow::before {
-        background: #ffffff !important;
+        background: var(--bg-base) !important;
         border: 1px solid #e5e7eb;
     }
 }
@@ -350,7 +350,7 @@ defineExpose({
 // dark
 .editor-tooltip--dark {
     background-color: #1e1e1e !important;
-    color: #ffffff !important;
+    color: var(--bg-base) !important;
 
     .el-popper__arrow::before {
         background: #1e1e1e !important;
@@ -377,7 +377,7 @@ defineExpose({
         ::v-deep(.el-select .el-select__wrapper) {
             border: none;
             box-shadow: none;
-            background-color: #ffff;
+            background-color: var(--bg-base);
         }
 
         ::v-deep(.el-select .el-select__placeholder) {

+ 63 - 52
apps/web/src/components/Sidebar/index.vue

@@ -46,6 +46,14 @@
 						<SvgIcon name="Fold" />
 					</span>
 				</el-tooltip>
+				<el-tooltip placement="bottom">
+					<template #content>
+						<span>{{ isDarkMode ? '浅色模式' : '暗黑模式' }}</span>
+					</template>
+					<span style="cursor: pointer" @click="toggleTheme">
+					<SvgIcon :name="isDarkMode ? 'sun' : 'moon'" />
+					</span>
+				</el-tooltip>
 			</div>
 		</div>
 
@@ -160,6 +168,7 @@ import { ElMessage } from 'element-plus'
 import SearchDialog from '../SearchDialog/index.vue'
 import { v4 } from 'uuid'
 import TemplateModal from '../TemplateModal/index.vue'
+import { applyTheme } from '@/theme'
 
 import logo from '@/assets/logo.svg'
 
@@ -171,6 +180,7 @@ const router = useRouter()
 const collapsed = ref(false)
 const showSearchDialog = ref(false)
 const showTemplateModal = ref(false)
+const isDarkMode = ref(false)
 
 // 计算当前活跃的菜单项
 const activeMenu = computed(() => router.currentRoute.value.path)
@@ -212,6 +222,9 @@ const handleKeyDown = (e: KeyboardEvent) => {
 
 onMounted(() => {
 	window.addEventListener('keydown', handleKeyDown)
+	// 初始化主题
+	const savedMode = localStorage.getItem('app-theme-mode') || 'light'
+	isDarkMode.value = savedMode === 'dark'
 })
 
 onUnmounted(() => {
@@ -235,17 +248,22 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 		name
 	)
 }
+
+const toggleTheme = () => {
+	isDarkMode.value = !isDarkMode.value
+	applyTheme(isDarkMode.value ? 'dark' : 'light')
+}
 </script>
 
 <style lang="less" scoped>
 * {
-	color: hsl(0, 0%, 46%);
+	color: var(--text-secondary);
 }
 .sidebar {
 	width: 200px;
 	height: 100%;
-	background: #fff;
-	border-right: 1px solid #f0f0f0;
+	background: var(--bg-base);
+	border-right: 1px solid var(--border-light);
 	box-sizing: border-box;
 	display: flex;
 	flex-direction: column;
@@ -260,7 +278,7 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 	align-items: center;
 	justify-content: space-between;
 	padding: 8px 10px;
-	border-bottom: 1px solid #f2f2f2;
+	border-bottom: 1px solid var(--border-light);
 }
 .brand-logo {
 	font-weight: 700;
@@ -281,7 +299,7 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 }
 .top-icons svg:hover {
 	color: #ff6b6b;
-	background-color: #f0f0f0;
+	background-color: var(--bg-container);
 }
 .top-icons > span {
 	display: flex;
@@ -296,7 +314,7 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 }
 .top-icons > span:hover svg {
 	color: #ff6b6b;
-	background-color: #f0f0f0;
+	background-color: var(--bg-container);
 }
 
 .main-menu {
@@ -311,10 +329,12 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 	height: 32px;
 }
 .el-menu-vertical-demo .el-menu-item:hover {
-	background: #f0f0f0;
+	background: var(--bg-container);
 }
 .el-menu-vertical-demo .el-menu-item.is-active {
-	background: #f0f0f0 !important;
+	background: var(--bg-container) !important;
+	color: var(--el-color-primary) !important;
+	border-right: 3px solid var(--el-color-primary);
 }
 .label {
 	font-size: 13px;
@@ -322,7 +342,7 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 }
 .beta {
 	font-size: 10px;
-	color: #999;
+	color: var(--text-tertiary);
 	margin-left: 6px;
 }
 .spacer {
@@ -330,7 +350,7 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 }
 .bottom-menu {
 	padding-bottom: 8px;
-	border-top: 1px solid #f2f2f2;
+	border-top: 1px solid var(--border-light);
 	display: flex;
 	flex-direction: column;
 	gap: 6px;
@@ -342,17 +362,17 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 	gap: 10px;
 	padding: 8px 18px;
 	padding-right: 10px;
-	color: #333;
+	color: var(--text-primary);
 	cursor: pointer;
 	border-radius: 4px;
 	transition: all 0.2s ease;
 }
 .bottom-item:hover {
-	background: #fafafa;
+	background: var(--bg-container);
 	color: #ff6b6b;
 }
 .bottom-item.active {
-	background: #fafafa;
+	background: var(--bg-container);
 	color: #ff6b6b;
 }
 
@@ -360,46 +380,37 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 	position: absolute;
 	left: 100%;
 	width: 240px;
-	background: #fff;
-	border: 1px solid #f0f0f0;
+	background: var(--bg-container);
+	border: 1px solid var(--border-light);
 	border-radius: 4px;
-	box-shadow: 2px 4px 12px rgba(0, 0, 0, 0.12);
-	z-index: 999;
-	margin-left: 8px;
-	animation: slideInRight 0.2s ease;
-
-	.settings-menu-list {
-		padding: 8px 0;
-		max-height: 500px;
-		overflow-y: auto;
-
-		.settings-menu-item {
-			padding: 10px 16px;
-			color: #666;
-			cursor: pointer;
-			transition: all 0.2s;
-			font-size: 13px;
-			white-space: nowrap;
-
-			&:hover {
-				background: #f5f5f5;
-				color: #333;
-			}
+	box-shadow: var(--shadow-lg);
+	overflow-y: auto;
+
+	.settings-menu-item {
+		padding: 10px 16px;
+		color: var(--text-secondary);
+		cursor: pointer;
+		transition: all 0.2s;
+		font-size: 13px;
+		white-space: nowrap;
+
+		&:hover {
+			background: var(--bg-base);
+			color: var(--text-primary);
+		}
 
-			&.logout {
-				color: #ff6b6b;
-				border-top: 1px solid #f0f0f0;
-				margin-top: 4px;
-				padding-top: 12px;
+		&.logout {
+			color: #ff6b6b;
+			border-top: 1px solid var(--border-light);
+			margin-top: 4px;
+			padding-top: 12px;
 
-				&:hover {
-					background: #fff5f5;
-				}
+			&:hover {
+				background: rgba(255, 107, 107, 0.1);
 			}
 		}
 	}
 }
-
 .sidebar.collapsed .label {
 	display: none;
 }
@@ -434,24 +445,24 @@ const handleSettingsClick = (event: MouseEvent, name: string) => {
 		padding: 1px 4px;
 		min-width: 18px;
 		height: 18px;
-		background: #f0f0f0;
-		color: #333;
-		border: 1px solid #d9d9d9;
+		background: var(--bg-container);
+		color: var(--text-primary);
+		border: 1px solid var(--border-base);
 		border-radius: 2px;
 		font-family: 'Monaco', 'Courier New', monospace;
 		font-weight: 500;
 		font-size: 10px;
-		box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+		box-shadow: var(--shadow-sm);
 	}
 
 	.plus {
-		color: #999;
+		color: var(--text-tertiary);
 		margin: 0 1px;
 		font-size: 10px;
 	}
 
 	.desc {
-		color: #ccc;
+		color: var(--text-placeholder);
 		margin-left: 2px;
 		font-size: 11px;
 	}

+ 0 - 1
apps/web/src/components/SvgIcon/index.vue

@@ -51,6 +51,5 @@ const getStyle = computed((): CSSProperties => {
 .svg-icon {
 	overflow: hidden;
 	vertical-align: -0.15em;
-	fill: currentColor;
 }
 </style>

+ 8 - 4
apps/web/src/components/TemplateModal/index.vue

@@ -158,6 +158,10 @@ const selectTemplate = (template: Template) => {
 </script>
 
 <style lang="less" scoped>
+:deep(.el-dialog__body) {
+	background: var(--bg-base);
+}
+
 .template-modal {
 	:deep(.el-col:nth-child(n + 4)) {
 		.template-card {
@@ -167,7 +171,7 @@ const selectTemplate = (template: Template) => {
 
 	.template-card {
 		padding: 20px;
-		border: 1px solid #e5e5e5;
+		border: 1px solid var(--border-light);
 		border-radius: 8px;
 		display: flex;
 		flex-direction: column;
@@ -179,7 +183,7 @@ const selectTemplate = (template: Template) => {
 
 		&:hover {
 			border-color: var(--el-color-primary);
-			box-shadow: 0 4px 12px var(--el-color-primary-light-7);
+			box-shadow: var(--shadow-md);
 			transform: translateY(-2px);
 
 			.template-title {
@@ -195,14 +199,14 @@ const selectTemplate = (template: Template) => {
 		.template-title {
 			font-size: 14px;
 			font-weight: 600;
-			color: #2c2c2c;
+			color: var(--text-primary);
 			margin-bottom: 8px;
 			transition: color 0.2s;
 		}
 
 		.template-description {
 			font-size: 12px;
-			color: #666;
+			color: var(--text-secondary);
 			margin-bottom: 12px;
 			min-height: 36px;
 			display: flex;

+ 3 - 3
apps/web/src/features/selectTableModal/index.vue

@@ -31,11 +31,11 @@
 					>
 						<div class="left flex items-center gap-24px">
 							<div class="icon w-40px h-40px bg-#ffb800 rounded-md grid place-items-center">
-								<Icon icon="iconoir:database-solid" color="#fff" height="24" width="24" />
+								<Icon icon="iconoir:database-solid" color="var(--bg-base)" height="24" width="24" />
 							</div>
 							<div>
-								<div class="text-#333 text-xs">{{ table.name }}</div>
-								<div class="text-#666 text-xs">{{ table.desc }}</div>
+						<div class="text-[var(--text-primary)] text-xs">{{ table.name }}</div>
+						<div class="text-[var(--text-secondary)] text-xs">{{ table.desc }}</div>
 							</div>
 						</div>
 						<el-button type="primary" @click="onAdd(table)">添加</el-button>

+ 8 - 8
apps/web/src/layouts/MainLayout.vue

@@ -193,10 +193,10 @@ onUnmounted(() => {
 	left: 0;
 	top: 0;
 	width: 240px;
-	background: #fff;
-	border: 1px solid #f0f0f0;
+	background: var(--bg-base);
+	border: 1px solid var(--border-light);
 	border-radius: 4px;
-	box-shadow: 2px 4px 12px rgba(0, 0, 0, 0.12);
+	box-shadow: var(--shadow-lg);
 	z-index: 999;
 	max-height: calc(100vh - 60px);
 	overflow-y: auto;
@@ -204,7 +204,7 @@ onUnmounted(() => {
 	.settings-menu-list {
 		.settings-menu-item {
 			padding: 10px 8px;
-			color: #666;
+			color: var(--text-secondary);
 			cursor: pointer;
 			transition: all 0.2s;
 			font-size: 13px;
@@ -223,18 +223,18 @@ onUnmounted(() => {
 			}
 
 			&:hover {
-				background: #f5f5f5;
-				color: #333;
+				background: var(--bg-base);
+				color: var(--text-primary);
 			}
 
 			&.logout {
 				color: #ff6b6b;
-				border-top: 1px solid #f0f0f0;
+				border-top: 1px solid var(--border-light);
 				margin-top: 4px;
 				padding-top: 12px;
 
 				&:hover {
-					background: #fff5f5;
+					background: rgba(255, 107, 107, 0.1);
 				}
 			}
 		}

+ 6 - 51
apps/web/src/main.ts

@@ -5,64 +5,19 @@ import store from './store'
 import router from './router'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
+// 导入 Element Plus 暗黑模式样式
+import 'element-plus/theme-chalk/dark/css-vars.css'
 import zhCn from 'element-plus/es/locale/lang/zh-cn'
 import i18n from './i18n'
 import 'virtual:svg-icons-register'
+import { initTheme } from '@/theme'
+import { lightTheme } from '@/theme/light'
+import { darkTheme } from '@/theme/dark'
 // import 'monaco-editor/esm/vs/editor/editor.main.css';
-
+initTheme(lightTheme, darkTheme)
 import 'normalize.css'
 import 'virtual:uno.css'
 
-// Theme colors configuration
-const themeColors = {
-	primary: '#ff6b6b',
-	'primary-light-3': '#ff8a8a',
-	'primary-light-5': '#ffa3a3',
-	'primary-light-7': '#ffbcbc',
-	'primary-light-8': '#ffd0d0',
-	'primary-light-9': '#ffe3e3',
-	'primary-dark-2': '#e55555',
-	success: '#67c23a',
-	'success-light-3': '#85ce61',
-	'success-light-5': '#a6e4a1',
-	'success-light-7': '#c6f6d5',
-	'success-light-8': '#d4edda',
-	'success-light-9': '#e1f5e3',
-	'success-dark-2': '#55b82d',
-	warning: '#e6a23c',
-	'warning-light-3': '#edb563',
-	'warning-light-5': '#f3d19e',
-	'warning-light-7': '#f9e4ba',
-	'warning-light-8': '#fce9cc',
-	'warning-light-9': '#fef0d9',
-	'warning-dark-2': '#d68830',
-	danger: '#f56c6c',
-	'danger-light-3': '#f78989',
-	'danger-light-5': '#f9a8a8',
-	'danger-light-7': '#fcc7c7',
-	'danger-light-8': '#fdd9d9',
-	'danger-light-9': '#feebeb',
-	'danger-dark-2': '#dd5960',
-	error: '#f56c6c',
-	'error-light-3': '#f78989',
-	'error-light-5': '#f9a8a8',
-	'error-light-7': '#fcc7c7',
-	'error-light-8': '#fdd9d9',
-	'error-light-9': '#feebeb',
-	info: '#909399',
-	'info-light-3': '#a6a9ad',
-	'info-light-5': '#b1b3b9',
-	'info-light-7': '#d3d4d6',
-	'info-light-8': '#e4e4e7',
-	'info-light-9': '#f2f2f5',
-	'info-dark-2': '#7a7d82'
-}
-
-const root = document.documentElement
-Object.entries(themeColors).forEach(([key, value]) => {
-	root.style.setProperty(`--el-color-${key}`, value)
-})
-
 const app = createApp(App)
 app.use(store)
 app.use(router)

+ 349 - 10
apps/web/src/style.css

@@ -4,18 +4,89 @@
 	font-weight: 400;
 
 	color-scheme: light dark;
-	color: rgba(255, 255, 255, 0.87);
-	background-color: #242424;
 
 	font-synthesis: none;
 	text-rendering: optimizeLegibility;
 	-webkit-font-smoothing: antialiased;
 	-moz-osx-font-smoothing: grayscale;
 
-	/* Element Plus theme color */
 	--el-color-primary: #ff6b6b;
 }
 
+/* 浅色主题(默认) */
+:root {
+	--bg-page: #ffffff;
+	--bg-base: #ffffff;
+	--bg-container: #f5f7fa;
+	--bg-overlay: #ffffff;
+	--text-primary: #303133;
+	--text-secondary: #606266;
+	--text-tertiary: #909399;
+	--text-placeholder: #adb3b8;
+	--text-disabled: #c0c4c8;
+	--text-strong: #000000;
+	--card-bg-selected: linear-gradient(135deg, #ffe6e6 0%, #ffd6d6 100%);
+	--card-bg-unselected: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
+	--border-light: #ebeef5;
+	--border-base: #dcdfe6;
+	--border-dark: #ccc;
+
+	/* Element Plus 全局背景和文字 */
+	--el-bg-color: #ffffff;
+	--el-text-color-primary: #303133;
+	--el-text-color-regular: #606266;
+	--el-text-color-secondary: #909399;
+	--el-text-color-placeholder: #adb3b8;
+	--el-text-color-disabled: #c0c4c8;
+	--el-border-color: #dcdfe6;
+	--el-border-color-light: #ebeef5;
+	--el-border-color-lighter: #f5f7fa;
+	--el-border-color-extra-light: #fafafa;
+	--el-fill-color-blank: #ffffff;
+	--el-fill-color-white: #ffffff;
+	--el-fill-color: #f0f2f5;
+	--el-fill-color-light: #f5f7fa;
+	--el-fill-color-lighter: #fafafa;
+	--el-fill-color-extra-light: #fafbfc;
+}
+
+/* 暗黑主题 */
+:root.dark {
+	--bg-page: #0a0a0a;
+	--bg-base: #141414;
+	--bg-container: #1f1f1f;
+	--bg-overlay: #262626;
+	--text-primary: #efefef;
+	--text-secondary: #b3b3b3;
+	--text-tertiary: #909399;
+	--text-placeholder: #757575;
+	--text-disabled: #6c6c6c;
+	--text-strong: #ffffff;
+	--card-bg-selected: linear-gradient(135deg, #4a2a2a 0%, #3a1f1f 100%);
+	--card-bg-unselected: linear-gradient(135deg, #2a2a2a 0%, #141414 100%);
+	--border-light: #414141;
+	--border-base: #434343;
+	--border-dark: #595959;
+
+	/* Element Plus 暗黑背景和文字 */
+	--el-bg-color: #141414;
+	--el-text-color-primary: #efefef;
+	--el-text-color-regular: #b3b3b3;
+	--el-text-color-secondary: #909399;
+	--el-text-color-placeholder: #757575;
+	--el-text-color-disabled: #6c6c6c;
+	--el-border-color: #434343;
+	--el-border-color-light: #414141;
+	--el-border-color-lighter: #373737;
+	--el-border-color-extra-light: #262626;
+	--el-fill-color-blank: #1f1f1f;
+	--el-fill-color-white: #1f1f1f;
+	--el-fill-color: #262626;
+	--el-fill-color-light: #2a2a2a;
+	--el-fill-color-lighter: #2e2e2e;
+	--el-fill-color-extra-light: #323232;
+}
+
 a {
 	font-weight: 500;
 	color: var(--el-color-primary);
@@ -30,6 +101,11 @@ body {
 	padding: 0;
 	min-width: 320px;
 	height: 100%;
+	background-color: var(--bg-page);
+	color: var(--text-primary);
+	transition:
+		background-color 0.3s,
+		color 0.3s;
 }
 
 h1 {
@@ -44,12 +120,14 @@ button {
 	font-size: 1em;
 	font-weight: 500;
 	font-family: inherit;
-	background-color: #1a1a1a;
+	background-color: var(--bg-container);
+	color: var(--text-primary);
 	cursor: pointer;
-	transition: border-color 0.25s;
+	transition: all 0.25s;
 }
 button:hover {
 	border-color: var(--el-color-primary);
+	background-color: var(--bg-base);
 }
 button:focus,
 button:focus-visible {
@@ -89,20 +167,22 @@ button:focus-visible {
 }
 .el-dialog__body {
 	padding: calc(var(--el-dialog-padding-primary)) var(--el-dialog-padding-primary);
+	background-color: var(--bg-base);
+	color: var(--text-primary);
 }
 
 .el-dialog__header {
-	border-bottom: 1px solid #e2e2e2 !important;
+	border-bottom: 1px solid var(--border-base) !important;
 	margin-right: 0 !important;
 	border-top-left-radius: 4px;
 	border-top-right-radius: 4px;
 	padding: 0px 13px !important;
 	line-height: 53px;
 	height: 50px;
-	color: var(--el-button-text-color) !important;
+	color: var(--text-primary) !important;
 	font-weight: bold;
 	font-size: 14px;
-	background-color: #fff !important;
+	background-color: var(--bg-base) !important;
 }
 
 .el-dialog__headerbtn {
@@ -116,12 +196,271 @@ button:focus-visible {
 	padding-top: 0 !important;
 	text-align: right;
 	box-sizing: border-box;
+	background-color: var(--bg-base);
+	border-top: 1px solid var(--border-light);
 }
 
 .el-dialog__headerbtn .el-dialog__close {
-	color: var(--el-button-text-color) !important;
+	color: var(--text-primary) !important;
 }
 
 .el-dialog__title {
-	color: var(--el-button-text-color);
+	color: var(--text-primary);
+}
+
+/* Element Plus 所有组件的全局样式覆盖 */
+.el-input,
+.el-input__wrapper,
+.el-input__inner {
+	background-color: var(--bg-base);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-input__inner::placeholder {
+	color: var(--text-placeholder);
+}
+
+.el-textarea__inner {
+	background-color: var(--bg-base);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-select-dropdown {
+	background-color: var(--bg-container);
+	border-color: var(--border-base);
+}
+
+.el-option {
+	color: var(--text-primary);
+}
+
+.el-option:hover {
+	background-color: var(--bg-base);
+}
+
+.el-option.selected {
+	background-color: var(--bg-base);
+	color: var(--el-color-primary);
+}
+
+.el-popper {
+	background-color: var(--bg-container);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-table {
+	background-color: var(--bg-base);
+	color: var(--text-primary);
+}
+
+.el-table__header th {
+	background-color: var(--bg-container);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-table__body tr {
+	background-color: var(--bg-base);
+	border-color: var(--border-base);
+}
+
+.el-table__body tr:hover > td {
+	background-color: var(--bg-overlay);
+}
+
+.el-card {
+	background-color: var(--bg-base);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-card__header {
+	background-color: var(--bg-base);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-container {
+	background-color: var(--bg-page);
+}
+
+.el-main {
+	background-color: var(--bg-page);
+	color: var(--text-primary);
+}
+
+.el-aside {
+	background-color: var(--bg-base);
+}
+
+.el-header {
+	background-color: var(--bg-base);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-footer {
+	background-color: var(--bg-base);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-menu {
+	background-color: var(--bg-base);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-menu-item,
+.el-sub-menu__title {
+	color: var(--text-secondary);
+}
+
+.el-menu-item:hover,
+.el-sub-menu__title:hover {
+	color: var(--text-primary);
+	background-color: var(--bg-container) !important;
+}
+
+.el-menu-item.is-active {
+	background-color: var(--bg-container) !important;
+	color: var(--el-color-primary) !important;
+	border-right-color: var(--el-color-primary);
+}
+
+.el-button {
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-button:hover {
+	background-color: var(--bg-container);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-tag {
+	background-color: var(--bg-container);
+	border-color: var(--border-light);
+	color: var(--text-primary);
+}
+
+.el-pagination .btn {
+	background-color: var(--bg-base);
+	color: var(--text-primary);
+	border-color: var(--border-light);
+}
+
+.el-pagination .btn:hover {
+	color: var(--el-color-primary);
+}
+
+.el-tooltip__popper {
+	background-color: var(--bg-container);
+	border-color: var(--border-base);
+	color: var(--text-primary);
+}
+
+.el-drawer {
+	background-color: var(--bg-base);
+	color: var(--text-primary);
+}
+
+/* 全局通用样式类 - 供所有组件使用 */
+/* 白色/基础背景的元素 */
+[style*='background: #fff'],
+[style*='background:#fff'],
+[style*='background-color: #fff'],
+[style*='background-color:#fff'],
+[style*='background: white'],
+.panel,
+.card-container,
+.content-wrapper {
+	background-color: var(--bg-base) !important;
+}
+
+/* 浅灰背景的元素 */
+[style*='background: #f'],
+[style*='background:#f'],
+.container-light,
+.section-light {
+	background-color: var(--bg-container) !important;
+}
+
+/* 深色文字 */
+[style*='color: #333'],
+[style*='color:#333'],
+[style*='color: #222'],
+[style*='color: #1f2937'],
+[style*='color: #111827'],
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.title,
+.heading,
+.text-primary {
+	color: var(--text-primary) !important;
+}
+
+/* 次要文字 */
+[style*='color: #666'],
+[style*='color:#666'],
+[style*='color: #6b7280'],
+.description,
+.subtitle,
+.text-secondary {
+	color: var(--text-secondary) !important;
+}
+
+/* 三级文字 */
+[style*='color: #999'],
+[style*='color:#999'],
+[style*='color: #888'],
+.text-muted,
+.text-tertiary {
+	color: var(--text-tertiary) !important;
+}
+
+/* 边框 */
+[style*='border: 1px solid #f0'],
+[style*='border-bottom: 1px solid #f'],
+[style*='border-top: 1px solid #f'] {
+	border-color: var(--border-light) !important;
+}
+
+/* 卡片和面板通用样式 */
+.stat-card,
+.action-card,
+.content-panel,
+.workflow-card,
+.panel-header,
+.welcome-banner {
+	background-color: var(--bg-base) !important;
+	border-color: var(--border-light) !important;
+	color: var(--text-primary) !important;
+}
+
+.stat-card:hover,
+.action-card:hover,
+.workflow-card:hover {
+	background-color: var(--bg-container) !important;
+}
+
+/* 阴影效果 - 根据主题调整透明度 */
+:root {
+	--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.12);
+	--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.15);
+	--shadow-lg: 2px 4px 12px rgba(0, 0, 0, 0.18);
+}
+
+:root.dark {
+	--shadow-sm: 0 2px 8px rgba(255, 255, 255, 0.25);
+	--shadow-md: 0 4px 16px rgba(255, 255, 255, 0.35);
+	--shadow-lg: 2px 4px 12px rgba(255, 255, 255, 0.4);
 }

+ 70 - 0
apps/web/src/theme/dark.ts

@@ -0,0 +1,70 @@
+import type { ThemeColors } from './index'
+
+// 暗黑主题:黑色背景 + 深色UI元素,保持与浅色相同的基础色系
+export const darkTheme: ThemeColors = {
+	// 基础色系(与浅色主题保持一致)
+	primary: '#ff6b6b',
+	'primary-light-3': '#ff8a8a',
+	'primary-light-5': '#ffa3a3',
+	'primary-light-7': '#ffbcbc',
+	'primary-light-8': '#ffd0d0',
+	'primary-light-9': '#ffe3e3',
+	'primary-dark-2': '#e55555',
+
+	success: '#67c23a',
+	'success-light-3': '#85ce61',
+	'success-light-5': '#a6e4a1',
+	'success-light-7': '#c6f6d5',
+	'success-light-8': '#d4edda',
+	'success-light-9': '#e1f5e3',
+	'success-dark-2': '#55b82d',
+
+	warning: '#e6a23c',
+	'warning-light-3': '#edb563',
+	'warning-light-5': '#f3d19e',
+	'warning-light-7': '#f9e4ba',
+	'warning-light-8': '#fce9cc',
+	'warning-light-9': '#fef0d9',
+	'warning-dark-2': '#d68830',
+
+	danger: '#f56c6c',
+	'danger-light-3': '#f78989',
+	'danger-light-5': '#f9a8a8',
+	'danger-light-7': '#fcc7c7',
+	'danger-light-8': '#fdd9d9',
+	'danger-light-9': '#feebeb',
+	'danger-dark-2': '#dd5960',
+
+	error: '#f56c6c',
+	'error-light-3': '#f78989',
+	'error-light-5': '#f9a8a8',
+	'error-light-7': '#fcc7c7',
+	'error-light-8': '#fdd9d9',
+	'error-light-9': '#feebeb',
+
+	info: '#909399',
+	'info-light-3': '#a6a9ad',
+	'info-light-5': '#b1b3b9',
+	'info-light-7': '#d3d4d6',
+	'info-light-8': '#e4e4e7',
+	'info-light-9': '#f2f2f5',
+	'info-dark-2': '#7a7d82',
+
+	// 背景色 - 黑色系
+	'bg-page': '#0a0a0a',
+	'bg-base': '#141414',
+	'bg-container': '#1f1f1f',
+	'bg-overlay': '#262626',
+
+	// 文字色 - 浅色系
+	'text-primary': '#efefef',
+	'text-secondary': '#b3b3b3',
+	'text-tertiary': '#909399',
+	'text-placeholder': '#757575',
+	'text-disabled': '#6c6c6c',
+
+	// 边框色 - 深灰色
+	'border-light': '#414141',
+	'border-base': '#434343',
+	'border-dark': '#595959',
+}

+ 40 - 0
apps/web/src/theme/index.ts

@@ -0,0 +1,40 @@
+import { lightTheme } from './light'
+import { darkTheme } from './dark'
+
+export type ThemeMode = 'light' | 'dark'
+
+export type ThemeColors = Record<string, string>
+
+export { lightTheme, darkTheme }
+
+const THEME_MODE_KEY = 'app-theme-mode'
+
+function setCssVars(colors: ThemeColors) {
+	const root = document.documentElement
+	Object.entries(colors).forEach(([key, value]) => {
+		// 设置 Element Plus 颜色变量
+		root.style.setProperty(`--el-color-${key}`, value)
+		// 同时设置通用变量(去掉 el-color- 前缀)
+		root.style.setProperty(`--${key}`, value)
+	})
+}
+
+export function applyTheme(mode: ThemeMode, colors?: ThemeColors) {
+	const colorMap = !colors ? (mode === 'dark' ? darkTheme : lightTheme) : colors
+	setCssVars(colorMap)
+
+	const html = document.documentElement
+	html.classList.toggle('dark', mode === 'dark')
+
+	localStorage.setItem(THEME_MODE_KEY, mode)
+}
+
+export function initTheme(customLight?: ThemeColors, customDark?: ThemeColors) {
+	const mode = (localStorage.getItem(THEME_MODE_KEY) as ThemeMode) || 'light'
+	const lightColors = customLight || lightTheme
+	const darkColors = customDark || darkTheme
+
+	applyTheme(mode, mode === 'dark' ? darkColors : lightColors)
+
+	return mode
+}

+ 63 - 0
apps/web/src/theme/light.ts

@@ -0,0 +1,63 @@
+import type { ThemeColors } from './index'
+
+export const lightTheme: ThemeColors = {
+	primary: '#ff6b6b',
+	'primary-light-3': '#ff8a8a',
+	'primary-light-5': '#ffa3a3',
+	'primary-light-7': '#ffbcbc',
+	'primary-light-8': '#ffd0d0',
+	'primary-light-9': '#ffe3e3',
+	'primary-dark-2': '#e55555',
+	success: '#67c23a',
+	'success-light-3': '#85ce61',
+	'success-light-5': '#a6e4a1',
+	'success-light-7': '#c6f6d5',
+	'success-light-8': '#d4edda',
+	'success-light-9': '#e1f5e3',
+	'success-dark-2': '#55b82d',
+	warning: '#e6a23c',
+	'warning-light-3': '#edb563',
+	'warning-light-5': '#f3d19e',
+	'warning-light-7': '#f9e4ba',
+	'warning-light-8': '#fce9cc',
+	'warning-light-9': '#fef0d9',
+	'warning-dark-2': '#d68830',
+	danger: '#f56c6c',
+	'danger-light-3': '#f78989',
+	'danger-light-5': '#f9a8a8',
+	'danger-light-7': '#fcc7c7',
+	'danger-light-8': '#fdd9d9',
+	'danger-light-9': '#feebeb',
+	'danger-dark-2': '#dd5960',
+	error: '#f56c6c',
+	'error-light-3': '#f78989',
+	'error-light-5': '#f9a8a8',
+	'error-light-7': '#fcc7c7',
+	'error-light-8': '#fdd9d9',
+	'error-light-9': '#feebeb',
+	info: '#909399',
+	'info-light-3': '#a6a9ad',
+	'info-light-5': '#b1b3b9',
+	'info-light-7': '#d3d4d6',
+	'info-light-8': '#e4e4e7',
+	'info-light-9': '#f2f2f5',
+	'info-dark-2': '#7a7d82',
+
+	// 背景色
+	'bg-page': '#ffffff',
+	'bg-base': '#ffffff',
+	'bg-container': '#f5f7fa',
+	'bg-overlay': '#ffffff',
+
+	// 文字色
+	'text-primary': '#303133',
+	'text-secondary': '#606266',
+	'text-tertiary': '#909399',
+	'text-placeholder': '#adb3b8',
+	'text-disabled': '#c0c4c8',
+
+	// 边框色
+	'border-light': '#ebeef5',
+	'border-base': '#dcdfe6',
+	'border-dark': '#ccc',
+}

+ 10 - 10
apps/web/src/views/About.vue

@@ -102,22 +102,22 @@
 
 	.content-section {
 		.info-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 32px;
 			margin-bottom: 24px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+			box-shadow: var(--shadow-sm);
 
 			h2 {
 				font-size: 24px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 				margin-bottom: 16px;
 			}
 
 			p {
 				font-size: 15px;
-				color: #666;
+				color: var(--text-secondary);
 				line-height: 1.8;
 			}
 		}
@@ -129,16 +129,16 @@
 			margin-bottom: 24px;
 
 			.feature-card {
-				background: #fff;
+				background: var(--bg-base);
 				border-radius: 12px;
 				padding: 28px;
 				text-align: center;
-				box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+				box-shadow: var(--shadow-sm);
 				transition: all 0.3s;
 
 				&:hover {
 					transform: translateY(-4px);
-					box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
+					box-shadow: var(--shadow-lg);
 				}
 
 				.feature-icon {
@@ -146,13 +146,13 @@
 				color: var(--el-color-primary);
 					font-size: 18px;
 					font-weight: 600;
-					color: #333;
+					color: var(--text-primary);
 					margin-bottom: 8px;
 				}
 
 				p {
 					font-size: 14px;
-					color: #666;
+					color: var(--text-secondary);
 					line-height: 1.6;
 				}
 			}
@@ -164,7 +164,7 @@
 
 			p {
 				font-size: 14px;
-				color: #999;
+				color: var(--text-tertiary);
 			}
 		}
 	}

+ 25 - 25
apps/web/src/views/Chat.vue

@@ -29,7 +29,7 @@
 							<template #dropdown>
 								<el-dropdown-menu>
 									<el-dropdown-item command="rename">重命名</el-dropdown-item>
-									<el-dropdown-item command="delete" style="color: #ff6b6b">
+									<el-dropdown-item command="delete" style="color: var(--el-color-danger)">
 										删除
 									</el-dropdown-item>
 								</el-dropdown-menu>
@@ -386,18 +386,18 @@ const formatTime = (timestamp: number) => {
 .chat-container {
 	display: flex;
 	height: 100vh;
-	background: #fff;
+	background: var(--bg-page);
 
 	.chat-sidebar {
 		width: 200px;
-		border-right: 1px solid #e8e8e8;
+		border-right: 1px solid var(--border-light);
 		display: flex;
 		flex-direction: column;
-		background: #fafafa;
+		background: var(--bg-base);
 
 		.sidebar-header {
 			padding: 13px;
-			border-bottom: 1px solid #e8e8e8;
+				border-bottom: 1px solid var(--border-light);
 
 			.new-chat-btn {
 				width: 100%;
@@ -413,7 +413,7 @@ const formatTime = (timestamp: number) => {
 				.list-title {
 					padding: 8px 12px;
 					font-size: 12px;
-					color: #999;
+					color: var(--text-tertiary);
 					font-weight: 600;
 					text-transform: uppercase;
 				}
@@ -426,10 +426,10 @@ const formatTime = (timestamp: number) => {
 					transition: all 0.2s;
 					border: 1px solid transparent;
 					position: relative;
-					background-color: rgba(0, 0, 0, 0.06);
+					background-color: var(--bg-container);
 
 					&:hover {
-						background: #f0f0f0;
+						background: var(--bg-overlay);
 
 						.conv-menu {
 							opacity: 1;
@@ -447,7 +447,7 @@ const formatTime = (timestamp: number) => {
 
 					.conv-title {
 						font-size: 14px;
-						color: #333;
+						color: var(--text-primary);
 						overflow: hidden;
 						text-overflow: ellipsis;
 						white-space: nowrap;
@@ -456,7 +456,7 @@ const formatTime = (timestamp: number) => {
 
 					.conv-time {
 						font-size: 12px;
-						color: #999;
+						color: var(--text-tertiary);
 					}
 
 					.conv-menu {
@@ -466,10 +466,10 @@ const formatTime = (timestamp: number) => {
 						cursor: pointer;
 						opacity: 0;
 						transition: opacity 0.2s;
-						color: #999;
+						color: var(--text-tertiary);
 
 						&:hover {
-							color: #333;
+							color: var(--text-primary);
 						}
 					}
 				}
@@ -481,17 +481,17 @@ const formatTime = (timestamp: number) => {
 		flex: 1;
 		display: flex;
 		flex-direction: column;
-		background: #fff;
+		background: var(--bg-page);
 
 		.chat-header {
 			padding: 16px 24px;
-			border-bottom: 1px solid #f0f0f0;
-			background: #fff;
+			border-bottom: 1px solid var(--border-light);
+			background: var(--bg-base);
 
 			.chat-title {
 				font-size: 18px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 			}
 		}
 
@@ -505,10 +505,10 @@ const formatTime = (timestamp: number) => {
 			.bubble-items {
 				.think {
 					padding-left: 20px;
-					border-left: solid 4px #c5b7b7;
+					border-left: solid 4px var(--border-light);
 					&-title {
 						font-size: 14px;
-						color: #333;
+						color: var(--text-primary);
 						display: flex;
 						align-items: center;
 					}
@@ -521,7 +521,7 @@ const formatTime = (timestamp: number) => {
 				flex-direction: column;
 				align-items: center;
 				justify-content: center;
-				color: #999;
+				color: var(--text-tertiary);
 
 				.empty-icon {
 					font-size: 48px;
@@ -532,7 +532,7 @@ const formatTime = (timestamp: number) => {
 					font-size: 16px;
 					font-weight: 600;
 					margin-bottom: 4px;
-					color: #333;
+					color: var(--text-primary);
 				}
 
 				.empty-subtext {
@@ -554,23 +554,23 @@ const formatTime = (timestamp: number) => {
 }
 
 ::-webkit-scrollbar-thumb {
-	background: #d0d0d0;
+	background: var(--border-light);
 	border-radius: 3px;
 
 	&:hover {
-		background: #999;
+		background: var(--border-base);
 	}
 }
 :deep(.el-bubble-end .el-bubble-content) {
 	background-color: var(--el-color-primary-light-9);
 	border-radius: 8px 0px 8px 8px;
-	color: #333;
+	color: var(--text-primary);
 	border: none;
 }
 
 :deep(.el-bubble-start .el-bubble-content) {
-	background-color: rgba(0, 0, 0, 0.06);
+	background-color: var(--bg-container);
 	border: none;
-	color: #111;
+	color: var(--text-primary);
 }
 </style>

+ 31 - 34
apps/web/src/views/Dashboard.vue

@@ -3,8 +3,8 @@
 		<!-- 欢迎横幅 -->
 		<div class="welcome-banner">
 			<div class="welcome-content">
-				<h1>欢迎回来!</h1>
-				<p>今天是 {{ currentDate }},开始构建你的自动化流程吧</p>
+				<h1 style="color: #fff !important">欢迎回来!</h1>
+				<p style="color: #fff !important">今天是 {{ currentDate }},开始构建你的自动化流程吧</p>
 			</div>
 			<el-button type="primary" size="large" @click="createWorkflow">
 				<SvgIcon name="workflow" size="16" />
@@ -137,7 +137,7 @@
 
 		<!-- 推荐模板 -->
 		<div class="templates-section">
-			<div class="panel-header">
+			<div class="panel-header" style="padding: 10px">
 				<h2>推荐模板</h2>
 				<el-button text @click="templateModalVisible = true">查看更多 →</el-button>
 			</div>
@@ -329,7 +329,6 @@ const templates = ref([
 <style lang="less" scoped>
 .dashboard-container {
 	height: calc(100vh - 48px);
-	background: #f5f7fa;
 	padding: 24px;
 	display: flex;
 	flex-direction: column;
@@ -369,7 +368,7 @@ const templates = ref([
 }
 
 .stat-card {
-	background: white;
+	background: var(--bg-base);
 	border-radius: 12px;
 	padding: 20px;
 	display: flex;
@@ -377,10 +376,10 @@ const templates = ref([
 	gap: 16px;
 	cursor: pointer;
 	transition: all 0.3s;
-	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+	box-shadow: var(--shadow-sm);
 
 	&:hover {
-		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+		box-shadow: var(--shadow-md);
 		transform: translateY(-2px);
 	}
 
@@ -419,13 +418,13 @@ const templates = ref([
 		.stat-value {
 			font-size: 24px;
 			font-weight: 700;
-			color: #1f2937;
+			color: var(--text-primary);
 			margin-bottom: 4px;
 		}
 
 		.stat-label {
 			font-size: 13px;
-			color: #6b7280;
+			color: var(--text-secondary);
 		}
 	}
 
@@ -450,7 +449,7 @@ const templates = ref([
 		font-size: 18px;
 		font-weight: 600;
 		margin: 0 0 16px 0;
-		color: #1f2937;
+		color: var(--text-primary);
 	}
 }
 
@@ -461,16 +460,16 @@ const templates = ref([
 }
 
 .action-card {
-	background: white;
+	background: var(--bg-base);
 	border-radius: 12px;
 	padding: 24px;
 	text-align: center;
 	cursor: pointer;
 	transition: all 0.3s;
-	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+	box-shadow: var(--shadow-sm);
 
 	&:hover {
-		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+		box-shadow: var(--shadow-md);
 		transform: translateY(-2px);
 
 		.action-icon {
@@ -483,25 +482,25 @@ const templates = ref([
 		width: 56px;
 		height: 56px;
 		border-radius: 12px;
-		background: #f3f4f6;
+		background: var(--bg-container);
 		display: flex;
 		align-items: center;
 		justify-content: center;
 		margin: 0 auto 12px;
 		transition: all 0.3s;
-		color: #6b7280;
+		color: var(--text-secondary);
 	}
 
 	.action-title {
 		font-size: 15px;
 		font-weight: 600;
-		color: #1f2937;
+		color: var(--text-primary);
 		margin-bottom: 4px;
 	}
 
 	.action-desc {
 		font-size: 13px;
-		color: #6b7280;
+		color: var(--text-secondary);
 	}
 }
 
@@ -514,12 +513,10 @@ const templates = ref([
 }
 
 .content-panel {
-	background: white;
+	background: var(--bg-base);
 	border-radius: 12px;
 	padding: 24px;
-	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-	overflow: hidden;
-	display: flex;
+	box-shadow: var(--shadow-sm);
 	flex-direction: column;
 
 	&:first-child {
@@ -584,7 +581,7 @@ const templates = ref([
 		font-size: 18px;
 		font-weight: 600;
 		margin: 0;
-		color: #1f2937;
+		color: var(--text-primary);
 	}
 }
 
@@ -604,7 +601,7 @@ const templates = ref([
 	cursor: pointer;
 
 	&:hover {
-		background: #f9fafb;
+		background: var(--bg-container);
 	}
 
 	.workflow-icon {
@@ -624,13 +621,13 @@ const templates = ref([
 		.workflow-title {
 			font-size: 14px;
 			font-weight: 600;
-			color: #1f2937;
+			color: var(--text-primary);
 			margin-bottom: 4px;
 		}
 
 		.workflow-meta {
 			font-size: 12px;
-			color: #6b7280;
+			color: var(--text-secondary);
 		}
 	}
 }
@@ -671,20 +668,20 @@ const templates = ref([
 
 		.activity-text {
 			font-size: 14px;
-			color: #1f2937;
+			color: var(--text-primary);
 			margin-bottom: 4px;
 		}
 
 		.activity-time {
 			font-size: 12px;
-			color: #9ca3af;
+			color: var(--text-tertiary);
 		}
 	}
 }
 
 .templates-section {
 	margin-bottom: 32px;
-	overflow: hidden;
+	// overflow: hidden;
 }
 
 .templates-grid {
@@ -694,19 +691,19 @@ const templates = ref([
 }
 
 .template-card {
-	background: white;
+	background: var(--bg-base);
 	border-radius: 12px;
 	padding: 20px;
 	cursor: pointer;
 	transition: all 0.3s;
-	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+	box-shadow: var(--shadow-sm);
 	display: flex;
 	flex-direction: column;
 	align-items: center;
 	text-align: center;
 
 	&:hover {
-		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+		box-shadow: var(--shadow-md);
 		transform: translateY(-2px);
 	}
 
@@ -714,7 +711,7 @@ const templates = ref([
 		width: 48px;
 		height: 48px;
 		border-radius: 10px;
-		background: #f3f4f6;
+		background: var(--bg-container);
 		display: flex;
 		align-items: center;
 		justify-content: center;
@@ -725,13 +722,13 @@ const templates = ref([
 	.template-title {
 		font-size: 15px;
 		font-weight: 600;
-		color: #1f2937;
+		color: var(--text-primary);
 		margin-bottom: 6px;
 	}
 
 	.template-desc {
 		font-size: 13px;
-		color: #6b7280;
+		color: var(--text-secondary);
 		margin-bottom: 12px;
 		min-height: 26px;
 	}

+ 57 - 62
apps/web/src/views/Docs.vue

@@ -142,23 +142,23 @@ const docDescription = computed(() => {
 .docs-container {
 	display: flex;
 	height: 100vh;
-	background: #f8f9fa;
+	background: var(--bg-page);
 
 	.sidebar {
 		width: 280px;
-		background: #fff;
-		border-right: 1px solid #e5e7eb;
+		background: var(--bg-base);
+		border-right: 1px solid var(--border-light);
 		overflow-y: auto;
 		flex-shrink: 0;
 
 		.sidebar-header {
 			padding: 0px 20px;
-			border-bottom: 1px solid #e5e7eb;
+			border-bottom: 1px solid var(--border-light);
 
 			h2 {
 				font-size: 18px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 			}
 		}
 
@@ -172,7 +172,7 @@ const docDescription = computed(() => {
 					padding: 8px 20px;
 					font-size: 12px;
 					font-weight: 600;
-					color: #999;
+					color: var(--text-tertiary);
 					text-transform: uppercase;
 					letter-spacing: 0.5px;
 				}
@@ -185,18 +185,18 @@ const docDescription = computed(() => {
 					li {
 						padding: 8px 20px 8px 32px;
 						font-size: 14px;
-						color: #666;
+						color: var(--text-secondary);
 						cursor: pointer;
 						transition: all 0.2s;
 
 						&:hover {
-							background: #f8f9fa;
-							color: #333;
+							background: var(--bg-container);
+							color: var(--text-primary);
 						}
 
 						&.active {
 							color: var(--el-color-primary);
-							background: #f0f3ff;
+							background: var(--el-color-primary-light-9);
 							border-right: 3px solid var(--el-color-primary);
 							font-weight: 500;
 						}
@@ -205,53 +205,51 @@ const docDescription = computed(() => {
 			}
 		}
 	}
+}
 
-	.docs-content {
-		flex: 1;
-		overflow-y: auto;
-		padding: 40px;
-
-		.doc-article {
-			max-width: 900px;
-			margin: 0 auto;
-			background: #fff;
-			border-radius: 12px;
-			padding: 48px;
-			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
-
-			h1 {
-				font-size: 36px;
-				font-weight: 700;
-				color: #333;
-				margin-bottom: 16px;
-			}
+.docs-content {
+	flex: 1;
+	overflow-y: auto;
+	padding: 40px;
+
+	.doc-article {
+		max-width: 900px;
+		margin: 0 auto;
+		background: var(--bg-base);
+		border-radius: 12px;
+		padding: 48px;
+		box-shadow: var(--shadow-sm);
+
+		h1 {
+			font-size: 36px;
+			font-weight: 700;
+			color: var(--text-primary);
+			margin-bottom: 16px;
+		}
 
-			.doc-body {
-				.lead {
-					font-size: 18px;
-					color: #666;
-					margin-bottom: 32px;
-					line-height: 1.6;
-				}
+		.doc-body {
+			.lead {
+				font-size: 18px;
+				color: var(--text-secondary);
+				margin-bottom: 32px;
+				line-height: 1.6;
+			}
 
-				.doc-section {
-					margin-bottom: 40px;
+			.doc-section {
+				margin-bottom: 40px;
 
-					h2 {
-						font-size: 24px;
-						font-weight: 600;
-						color: #333;
-						margin-bottom: 16px;
-						padding-bottom: 8px;
-						border-bottom: 2px solid #f0f0f0;
-					}
+				h2 {
+					font-size: 24px;
+					font-weight: 600;
+					color: var(--text-primary);
+					margin-bottom: 16px;
+					padding-bottom: 8px;
+					border-bottom: 2px solid var(--border-light);
+				}
 
-					p {
-						font-size: 15px;
-						color: #666;
-						line-height: 1.8;
-						margin-bottom: 16px;
-					}
+				p {
+					font-size: 15px;
+					color: var(--text-secondary);
 
 					.feature-list {
 						list-style: none;
@@ -261,7 +259,7 @@ const docDescription = computed(() => {
 							padding: 12px 0;
 							padding-left: 28px;
 							position: relative;
-							color: #666;
+							color: var(--text-secondary);
 							line-height: 1.6;
 
 							&:before {
@@ -273,7 +271,7 @@ const docDescription = computed(() => {
 							}
 
 							strong {
-								color: #333;
+								color: var(--text-primary);
 							}
 						}
 					}
@@ -308,20 +306,17 @@ const docDescription = computed(() => {
 							align-items: center;
 							gap: 12px;
 							padding: 16px 20px;
-							background: #f8f9fa;
-							border: 1px solid #e5e7eb;
+							background: var(--bg-container);
+							border: 1px solid var(--border-light);
 							border-radius: 8px;
 							text-decoration: none;
-							color: #333;
+							color: var(--text-primary);
 							transition: all 0.3s;
 
 							&:hover {
-								background: #fff;
+								background: var(--bg-base);
 								border-color: var(--el-color-primary);
-								box-shadow: 0 4px 12px var(--el-color-primary-light-9);
-							}
-
-							svg {
+							box-shadow: var(--shadow-md);
 								font-size: 24px;
 								color: var(--el-color-primary);
 							}

+ 9 - 12
apps/web/src/views/LogStream.vue

@@ -132,10 +132,7 @@ const refreshLogs = () => {
 		h1 {
 			font-size: 28px;
 			font-weight: 600;
-			color: #333;
-		}
-
-		.header-actions {
+				color: var(--text-primary);
 			display: flex;
 			gap: 12px;
 			align-items: center;
@@ -154,15 +151,15 @@ const refreshLogs = () => {
 		gap: 12px;
 
 		.log-item {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 8px;
 			padding: 16px;
-			border-left: 4px solid #e5e7eb;
-			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+			border-left: 4px solid var(--border-light);
+			box-shadow: var(--shadow-sm);
 			transition: all 0.3s;
 
 			&:hover {
-				box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+				box-shadow: var(--shadow-md);
 			}
 
 			&.log-info {
@@ -208,7 +205,7 @@ const refreshLogs = () => {
 
 				.log-time {
 					font-size: 13px;
-					color: #666;
+					color: var(--text-secondary);
 				}
 
 				.log-workflow {
@@ -220,13 +217,13 @@ const refreshLogs = () => {
 
 			.log-message {
 				font-size: 14px;
-				color: #333;
+				color: var(--text-primary);
 				line-height: 1.6;
 				margin-bottom: 8px;
 			}
 
 			.log-details {
-				background: #f8f9fa;
+				background: var(--bg-container);
 				border-radius: 4px;
 				padding: 12px;
 				margin-top: 12px;
@@ -234,7 +231,7 @@ const refreshLogs = () => {
 				pre {
 					margin: 0;
 					font-size: 12px;
-					color: #666;
+					color: var(--text-secondary);
 					line-height: 1.6;
 					overflow-x: auto;
 				}

+ 9 - 12
apps/web/src/views/ModelLog.vue

@@ -232,10 +232,7 @@ const viewDetails = (log: any) => {
 		h1 {
 			font-size: 28px;
 			font-weight: 600;
-			color: #333;
-		}
-
-		.header-actions {
+				color: var(--text-primary);
 			display: flex;
 			gap: 12px;
 		}
@@ -248,10 +245,10 @@ const viewDetails = (log: any) => {
 		margin-bottom: 24px;
 
 		.stat-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 24px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+			box-shadow: var(--shadow-sm);
 			display: flex;
 			align-items: center;
 			gap: 20px;
@@ -280,24 +277,24 @@ const viewDetails = (log: any) => {
 				.stat-value {
 					font-size: 28px;
 					font-weight: 700;
-					color: #333;
+					color: var(--text-primary);
 					line-height: 1;
 					margin-bottom: 8px;
 				}
 
 				.stat-label {
 					font-size: 13px;
-					color: #666;
+					color: var(--text-secondary);
 				}
 			}
 		}
 	}
 
 	.logs-table {
-		background: #fff;
+		background: var(--bg-base);
 		border-radius: 12px;
 		padding: 20px;
-		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+		box-shadow: var(--shadow-sm);
 	}
 
 	.log-detail {
@@ -339,7 +336,7 @@ const viewDetails = (log: any) => {
 			}
 
 			.code-block {
-				background: #f8f9fa;
+				background: var(--bg-container);
 				border-radius: 8px;
 				padding: 16px;
 				max-height: 300px;
@@ -348,7 +345,7 @@ const viewDetails = (log: any) => {
 				pre {
 					margin: 0;
 					font-size: 13px;
-					color: #333;
+					color: var(--text-primary);
 					line-height: 1.6;
 					white-space: pre-wrap;
 					word-wrap: break-word;

+ 14 - 14
apps/web/src/views/QuickStart.vue

@@ -89,13 +89,13 @@
 		h1 {
 			font-size: 36px;
 			font-weight: 700;
-			color: #333;
+			color: var(--text-primary);
 			margin-bottom: 12px;
 		}
 
 		.subtitle {
 			font-size: 16px;
-			color: #666;
+			color: var(--text-secondary);
 		}
 	}
 
@@ -134,7 +134,7 @@
 			h2 {
 				font-size: 28px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 				margin-bottom: 32px;
 			}
 
@@ -144,8 +144,8 @@
 				gap: 24px;
 
 				.step-card {
-					background: #fff;
-					border: 1px solid #f0f0f0;
+					background: var(--bg-base);
+					border: 1px solid var(--border-light);
 					border-radius: 12px;
 					padding: 24px;
 					display: flex;
@@ -153,7 +153,7 @@
 					transition: all 0.3s ease;
 
 					&:hover {
-						box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+						box-shadow: var(--shadow-md);
 						transform: translateY(-2px);
 					}
 
@@ -175,13 +175,13 @@
 						h3 {
 							font-size: 18px;
 							font-weight: 600;
-							color: #333;
+							color: var(--text-primary);
 							margin-bottom: 8px;
 						}
 
 						p {
 							font-size: 14px;
-							color: #666;
+							color: var(--text-secondary);
 							line-height: 1.6;
 						}
 					}
@@ -193,7 +193,7 @@
 			h2 {
 				font-size: 28px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 				margin-bottom: 32px;
 			}
 
@@ -203,8 +203,8 @@
 				gap: 24px;
 
 				.resource-card {
-					background: #fff;
-					border: 1px solid #f0f0f0;
+					background: var(--bg-base);
+					border: 1px solid var(--border-light);
 					border-radius: 12px;
 					padding: 32px;
 					text-align: center;
@@ -213,7 +213,7 @@
 
 					&:hover {
 						border-color: var(--el-color-primary);
-						box-shadow: 0 4px 12px var(--el-color-primary-light-7);
+						box-shadow: var(--shadow-md);
 						transform: translateY(-4px);
 					}
 
@@ -225,13 +225,13 @@
 					h3 {
 						font-size: 18px;
 						font-weight: 600;
-						color: #333;
+						color: var(--text-primary);
 						margin-bottom: 8px;
 					}
 
 					p {
 						font-size: 14px;
-						color: #666;
+						color: var(--text-secondary);
 					}
 				}
 			}

+ 39 - 19
apps/web/src/views/Statistics.vue

@@ -7,13 +7,13 @@
 			align-items: center;
 			padding: 0 16px;
 			justify-content: space-between;
-			background: #fff;
-			border-bottom: 1px solid #f0f0f0;
+			background: var(--bg-base);
+			border-bottom: 1px solid var(--border-light);
 		"
 	>
 		<div style="display: flex; align-items: center; gap: 12px">
 			<div style="font-weight: 700; font-size: 18px">统计</div>
-			<div style="color: #888; font-size: 13px">所有项目</div>
+			<div style="color: var(--text-tertiary); font-size: 13px">所有项目</div>
 		</div>
 
 		<div style="display: flex; align-items: center; gap: 12px">
@@ -30,31 +30,37 @@
 
 	<div style="padding: 16px">
 		<!-- 统计卡片 -->
-		<el-card shadow="never" style="padding: 18px; background-color: #fff">
+		<el-card shadow="never" style="padding: 18px; background-color: var(--bg-base)">
 			<el-row :gutter="24" justify="start">
 				<el-col :span="4" v-for="(card, idx) in statsData" :key="idx">
 					<div
 						@click="selectCard(idx)"
 						:style="{
-							background:
-								selectedCardIdx === idx
-									? 'linear-gradient(135deg, var(--el-color-primary-light-9) 0%, var(--el-color-primary-light-8) 100%)'
-									: 'linear-gradient(135deg, #fff 0%, #fafafa 100%)',
+							background: selectedCardIdx === idx ? 'var(--card-bg-selected)' : '',
 							padding: '20px 16px',
 							borderRadius: '8px',
 							boxShadow:
 								selectedCardIdx === idx
 									? '0 4px 12px var(--el-color-primary-light-7)'
-									: '0 2px 8px rgba(0, 0, 0, 0.08)',
-							border: selectedCardIdx === idx ? '1px solid var(--el-color-primary)' : '1px solid #f0f0f0',
+									: 'var(--shadow-sm)',
+							border:
+								selectedCardIdx === idx
+									? '1px solid var(--el-color-primary)'
+									: '1px solid var(--border-light)',
 							textAlign: 'center',
 							cursor: 'pointer',
 							transition: 'all 0.3s ease'
 						}"
 					>
-						<div style="font-size: 12px; color: #999; margin-bottom: 8px">{{ card.title }}</div>
-						<div style="font-size: 32px; font-weight: 600; color: #262626">{{ card.value }}</div>
-						<div style="font-size: 12px; color: #bbb; margin-top: 8px">{{ card.subtitle }}</div>
+						<div style="font-size: 12px; color: var(--text-tertiary); margin-bottom: 8px">
+							{{ card.title }}
+						</div>
+						<div style="font-size: 32px; font-weight: 600; color: var(--text-strong)">
+							{{ card.value }}
+						</div>
+						<div style="font-size: 12px; color: var(--text-placeholder); margin-top: 8px">
+							{{ card.subtitle }}
+						</div>
 					</div>
 				</el-col>
 			</el-row>
@@ -66,12 +72,26 @@
 				<div style="font-weight: 600">{{ currentChartTitle }}</div>
 				<div style="display: flex; gap: 8px">
 					<div style="display: flex; align-items: center; gap: 4px">
-						<div style="width: 12px; height: 12px; background: #13c2c2; border-radius: 2px"></div>
-						<span style="font-size: 12px; color: #666">Successful</span>
+						<div
+							style="
+								width: 12px;
+								height: 12px;
+								background: var(--el-color-success);
+								border-radius: 2px;
+							"
+						></div>
+						<span style="font-size: 12px; color: var(--text-secondary)">Successful</span>
 					</div>
 					<div style="display: flex; align-items: center; gap: 4px">
-						<div style="width: 12px; height: 12px; background: #ff6b6b; border-radius: 2px"></div>
-						<span style="font-size: 12px; color: #666">Failed</span>
+						<div
+							style="
+								width: 12px;
+								height: 12px;
+								background: var(--el-color-danger);
+								border-radius: 2px;
+							"
+						></div>
+						<span style="font-size: 12px; color: var(--text-secondary)">Failed</span>
 					</div>
 				</div>
 			</div>
@@ -356,7 +376,7 @@ const currentPage = ref(1)
 }
 
 :deep(.el-card) {
-	border: 1px solid #f0f0f0;
+	border: 1px solid var(--border-light);
 }
 
 :deep(.el-table) {
@@ -364,7 +384,7 @@ const currentPage = ref(1)
 }
 
 :deep(.el-table__header-wrapper) {
-	background-color: #fafafa;
+	background-color: var(--bg-container);
 }
 
 :deep(.el-pagination) {

+ 18 - 23
apps/web/src/views/TemplateDetail.vue

@@ -17,11 +17,7 @@
 		<div class="detail-content">
 			<!-- 流程图占位 -->
 			<div class="workflow-diagram">
-				<img
-					src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 400'%3E%3Crect width='800' height='400' fill='%23f5f5f5'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' font-size='16' fill='%23999'%3E流程图占位%3C/text%3E%3C/svg%3E"
-					alt="workflow-diagram"
-					class="diagram-image"
-				/>
+				<div class="diagram-placeholder">流程图占位</div>
 			</div>
 
 			<!-- 下方说明文本 -->
@@ -112,40 +108,40 @@ const useTemplate = () => {
 	height: 100%;
 	display: flex;
 	flex-direction: column;
-	background: #fff;
+	background: var(--bg-page);
 
 	.detail-header {
 		display: flex;
 		align-items: center;
 		justify-content: space-between;
 		padding: 0 24px;
-		border-bottom: 1px solid #f0f0f0;
+		border-bottom: 1px solid var(--border-light);
 		height: 50px;
 
 		.header-left {
 			display: flex;
 			align-items: center;
 			font-size: 14px;
-			color: #666;
+			color: var(--text-secondary);
 
 			.back-btn {
 				padding: 0;
-				color: #0076ff;
+				color: var(--el-color-primary);
 				font-size: 14px;
 
 				&:hover {
-					color: #0056cc;
+					color: var(--el-color-primary-dark-2);
 				}
 			}
 
 			:deep(.el-divider--vertical) {
 				margin: 0 12px;
 				height: 20px;
-				background-color: #e5e5e5;
+				background-color: var(--border-light);
 			}
 
 			.breadcrumb {
-				color: #666;
+				color: var(--text-secondary);
 			}
 		}
 
@@ -154,7 +150,7 @@ const useTemplate = () => {
 			text-align: center;
 			font-size: 18px;
 			font-weight: 600;
-			color: #2c2c2c;
+			color: var(--text-primary);
 			margin: 0 24px;
 		}
 	}
@@ -170,41 +166,40 @@ const useTemplate = () => {
 		.workflow-diagram {
 			flex: 1;
 			min-height: 400px;
-			background: #f9f9f9;
-			border: 1px solid #e5e5e5;
+			background: var(--bg-container);
+			border: 1px solid var(--border-light);
 			border-radius: 8px;
 			display: flex;
 			align-items: center;
 			justify-content: center;
 			overflow: hidden;
 
-			.diagram-image {
-				width: 100%;
-				height: 100%;
-				object-fit: contain;
+			.diagram-placeholder {
+				font-size: 14px;
+				color: var(--text-tertiary);
 			}
 		}
 
 		.detail-description {
 			padding: 24px;
-			background: #f5f7fa;
+			background: var(--bg-container);
 			border-radius: 8px;
 
 			h3 {
 				font-size: 16px;
 				font-weight: 600;
-				color: #2c2c2c;
+				color: var(--text-primary);
 				margin: 0 0 12px 0;
 			}
 
 			p {
 				font-size: 14px;
-				color: #666;
+				color: var(--text-secondary);
 				margin: 0 0 8px 0;
 				line-height: 1.6;
 
 				&.detail-text {
-					color: #555;
+					color: var(--text-secondary);
 				}
 			}
 		}

+ 13 - 13
apps/web/src/views/UserCenter.vue

@@ -133,11 +133,11 @@ const userInfo = ref({
 
 	.content {
 		.profile-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 32px;
 			margin-bottom: 24px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+			box-shadow: var(--shadow-sm);
 			display: flex;
 			gap: 48px;
 
@@ -166,7 +166,7 @@ const userInfo = ref({
 				h2 {
 					font-size: 20px;
 					font-weight: 600;
-					color: #333;
+					color: var(--text-primary);
 					margin-bottom: 24px;
 				}
 			}
@@ -179,10 +179,10 @@ const userInfo = ref({
 			margin-bottom: 24px;
 
 			.stat-card {
-				background: #fff;
+				background: var(--bg-base);
 				border-radius: 12px;
 				padding: 24px;
-				box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+				box-shadow: var(--shadow-sm);
 				display: flex;
 				align-items: center;
 				gap: 20px;
@@ -203,29 +203,29 @@ const userInfo = ref({
 					.stat-value {
 						font-size: 32px;
 						font-weight: 700;
-						color: #333;
+						color: var(--text-primary);
 						line-height: 1;
 						margin-bottom: 8px;
 					}
 
 					.stat-label {
 						font-size: 14px;
-						color: #666;
+						color: var(--text-secondary);
 					}
 				}
 			}
 		}
 
 		.security-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 32px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+			box-shadow: var(--shadow-sm);
 
 			h2 {
 				font-size: 20px;
 				font-weight: 600;
-				color: #333;
+				color: var(--text-primary);
 				margin-bottom: 24px;
 			}
 
@@ -239,7 +239,7 @@ const userInfo = ref({
 					justify-content: space-between;
 					align-items: center;
 					padding: 20px;
-					background: #f8f9fa;
+					background: var(--bg-container);
 					border-radius: 8px;
 
 					.security-left {
@@ -256,13 +256,13 @@ const userInfo = ref({
 							.security-title {
 								font-size: 15px;
 								font-weight: 500;
-								color: #333;
+								color: var(--text-primary);
 								margin-bottom: 4px;
 							}
 
 							.security-desc {
 								font-size: 13px;
-								color: #666;
+								color: var(--text-secondary);
 							}
 						}
 					}

+ 13 - 13
apps/web/src/views/WorkflowExecution.vue

@@ -216,12 +216,12 @@ const resetFilters = () => {
 		h1 {
 			font-size: 28px;
 			margin: 0;
-			color: #222;
+			color: var(--text-primary);
 		}
 
 		.subtitle {
 			margin: 6px 0 0;
-			color: #666;
+			color: var(--text-secondary);
 			font-size: 14px;
 		}
 	}
@@ -233,10 +233,10 @@ const resetFilters = () => {
 		margin-bottom: 20px;
 
 		.stat-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 18px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+			box-shadow: var(--shadow-sm);
 			display: flex;
 			gap: 12px;
 			align-items: center;
@@ -270,12 +270,12 @@ const resetFilters = () => {
 			.stat-value {
 				font-size: 22px;
 				font-weight: 700;
-				color: #1f2937;
+				color: var(--text-primary);
 			}
 
 			.stat-label {
 				font-size: 13px;
-				color: #6b7280;
+				color: var(--text-secondary);
 			}
 		}
 	}
@@ -293,10 +293,10 @@ const resetFilters = () => {
 	}
 
 	.panel {
-		background: #fff;
+		background: var(--bg-base);
 		border-radius: 12px;
 		padding: 20px;
-		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+		box-shadow: var(--shadow-sm);
 	}
 
 	.side-panels {
@@ -309,30 +309,30 @@ const resetFilters = () => {
 			font-size: 16px;
 			font-weight: 600;
 			margin-bottom: 12px;
-			color: #1f2937;
+			color: var(--text-primary);
 		}
 
 		.summary-item {
 			display: flex;
 			justify-content: space-between;
 			padding: 10px 0;
-			border-bottom: 1px solid #f1f5f9;
+			border-bottom: 1px solid var(--border-light);
 
 			.label {
-				color: #6b7280;
+				color: var(--text-secondary);
 				font-size: 13px;
 			}
 
 			.value {
 				font-weight: 600;
-				color: #111827;
+				color: var(--text-primary);
 			}
 		}
 
 		.tips {
 			margin: 0;
 			padding-left: 16px;
-			color: #6b7280;
+			color: var(--text-secondary);
 			line-height: 1.6;
 			font-size: 13px;
 		}

+ 44 - 41
apps/web/src/views/WorkflowOrchestration.vue

@@ -20,7 +20,9 @@
 		<!-- 编排核心概念 -->
 		<div class="core-concepts">
 			<div class="concept-card sequence">
-				<div class="concept-icon">🔗</div>
+				<div class="concept-icon">
+					<SvgIcon name="chain" size="24" />
+				</div>
 				<div class="concept-info">
 					<div class="concept-title">按顺序</div>
 					<div class="concept-desc">节点A → 节点B → 节点C,串联执行</div>
@@ -28,7 +30,9 @@
 				<div class="concept-example">开始 → HTTP请求 → 数据处理 → 发送通知</div>
 			</div>
 			<div class="concept-card condition">
-				<div class="concept-icon">🔀</div>
+				<div class="concept-icon">
+					<SvgIcon name="branch" size="24" />
+				</div>
 				<div class="concept-info">
 					<div class="concept-title">按条件</div>
 					<div class="concept-desc">判断结果,走不同的分支路径</div>
@@ -36,7 +40,9 @@
 				<div class="concept-example">if (状态=成功) → 路径A else → 路径B</div>
 			</div>
 			<div class="concept-card rule">
-				<div class="concept-icon">⚙️</div>
+				<div class="concept-icon">
+					<SvgIcon name="settings-gear" size="24" />
+				</div>
 				<div class="concept-info">
 					<div class="concept-title">按规则</div>
 					<div class="concept-desc">触发器、定时任务、事件驱动自动执行</div>
@@ -246,12 +252,12 @@ const useTemplate = (id: string) => {
 		h1 {
 			font-size: 28px;
 			margin: 0;
-			color: #222;
+			color: var(--text-primary);
 		}
 
 		.subtitle {
 			margin: 6px 0 0;
-			color: #666;
+			color: var(--text-secondary);
 			font-size: 14px;
 		}
 
@@ -278,10 +284,10 @@ const useTemplate = (id: string) => {
 		}
 
 		.concept-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 20px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+			box-shadow: var(--shadow-sm);
 			border-left: 4px solid #3b82f6;
 
 			&.sequence {
@@ -299,21 +305,24 @@ const useTemplate = (id: string) => {
 			.concept-icon {
 				font-size: 32px;
 				margin-bottom: 12px;
-			}
-
-			.concept-info {
+			color: var(--el-color-primary);
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			width: 40px;
+			height: 40px;
 				margin-bottom: 12px;
 
 				.concept-title {
 					font-size: 18px;
 					font-weight: 700;
-					color: #1f2937;
+					color: var(--text-primary);
 					margin-bottom: 6px;
 				}
 
 				.concept-desc {
 					font-size: 13px;
-					color: #6b7280;
+					color: var(--text-secondary);
 					line-height: 1.6;
 				}
 			}
@@ -321,9 +330,9 @@ const useTemplate = (id: string) => {
 			.concept-example {
 				font-size: 12px;
 				padding: 10px 12px;
-				background: #f9fafb;
+				background: var(--bg-container);
 				border-radius: 8px;
-				color: #374151;
+				color: var(--text-primary);
 				font-family: 'Consolas', 'Monaco', monospace;
 			}
 		}
@@ -336,13 +345,13 @@ const useTemplate = (id: string) => {
 		margin-bottom: 24px;
 
 		.stat-card {
-			background: #fff;
+			background: var(--bg-base);
 			border-radius: 12px;
 			padding: 18px;
 			display: flex;
 			align-items: center;
 			gap: 12px;
-			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+			box-shadow: var(--shadow-sm);
 
 			.stat-icon {
 				width: 40px;
@@ -374,12 +383,12 @@ const useTemplate = (id: string) => {
 				.stat-value {
 					font-size: 22px;
 					font-weight: 700;
-					color: #1f2937;
+					color: var(--text-primary);
 				}
 
 				.stat-label {
 					font-size: 13px;
-					color: #6b7280;
+					color: var(--text-secondary);
 				}
 			}
 		}
@@ -397,10 +406,10 @@ const useTemplate = (id: string) => {
 	}
 
 	.panel {
-		background: #fff;
+		background: var(--bg-base);
 		border-radius: 12px;
 		padding: 20px;
-		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+		box-shadow: var(--shadow-sm);
 
 		&.full {
 			margin-top: 8px;
@@ -410,7 +419,7 @@ const useTemplate = (id: string) => {
 			font-size: 16px;
 			font-weight: 600;
 			margin-bottom: 16px;
-			color: #1f2937;
+			color: var(--text-primary);
 		}
 	}
 
@@ -425,22 +434,16 @@ const useTemplate = (id: string) => {
 			align-items: center;
 			padding: 12px;
 			border-radius: 10px;
-			border: 1px solid #f0f0f0;
-
-			.workflow-title {
-				font-weight: 600;
-				color: #111827;
-			}
+				border: 1px solid var(--border-light);
 
-			.workflow-meta {
-				font-size: 12px;
-				color: #6b7280;
-				margin-top: 4px;
-			}
+				.workflow-title {
+					font-weight: 600;
+					color: var(--text-primary);
+				}
 
-			.workflow-tags {
-				display: flex;
-				gap: 8px;
+				.workflow-meta {
+					font-size: 12px;
+					color: var(--text-secondary);
 				align-items: center;
 			}
 		}
@@ -488,7 +491,7 @@ const useTemplate = (id: string) => {
 		.node-type-group {
 			.node-type-label {
 				font-size: 13px;
-				color: #6b7280;
+				color: var(--text-secondary);
 				margin-bottom: 8px;
 				font-weight: 600;
 			}
@@ -507,24 +510,24 @@ const useTemplate = (id: string) => {
 		gap: 16px;
 
 		.template-card {
-			border: 1px solid #f0f0f0;
+			border: 1px solid var(--border-light);
 			border-radius: 12px;
 			padding: 16px;
-			background: #fcfcff;
+			background: var(--bg-container);
 
 			.template-title {
 				font-weight: 600;
-				color: #111827;
+				color: var(--text-primary);
 				margin-bottom: 8px;
 			}
 
 			.template-desc {
 				font-size: 12px;
-				color: #6b7280;
+				color: var(--text-secondary);
 				line-height: 1.6;
 				min-height: 54px;
 				font-family: 'Consolas', 'Monaco', monospace;
-				background: #f9fafb;
+				background: var(--bg-container);
 				padding: 8px;
 				border-radius: 6px;
 				margin-bottom: 10px;

+ 2 - 1
apps/web/tsconfig.app.json

@@ -11,13 +11,14 @@
                 "src/*"
             ]
         },
+        "skipLibCheck": true,
         /* Linting */
         "strict": true,
         "noUnusedLocals": true,
         "noUnusedParameters": true,
         "erasableSyntaxOnly": true,
         "noFallthroughCasesInSwitch": true,
-        "noUncheckedSideEffectImports": true
+        "noUncheckedSideEffectImports": false
     },
     "include": [
         "src/**/*.ts",