重构代理池系统:简化架构并增强核心功能
后端变更: - 移除 tasks_manager.py 和 core/auth.py,简化架构 - 新增 core/scheduler.py 验证调度器,替代原有任务管理 - 大幅优化 api_server.py:统一错误处理、增强参数验证、支持调度器控制 - validator.py 增强 SOCKS4/SOCKS5 代理验证支持 - config.py 清理废弃配置(WebSocket、API Key、认证开关) - SQLite 数据库操作性能优化 前端变更: - 移除任务管理页面 (CrawlerTasks) 和 WebSocket 相关代码 - 路由简化为 4 个核心页面:总览、代理列表、插件管理、设置 - 提取前端工具函数(clipboard、confirm、format)和 API 类型定义 - 优化 CSS 架构:完善 variables、utilities、element-plus 样式 - Dashboard、Plugins、ProxyList、Settings 页面 UI/UX 优化 - App.vue 响应式侧边栏和页面过渡动画优化 其他: - 移除 PowerShell 启动脚本,简化 Windows 批处理脚本 - 新增 README_SOCKS.md SOCKS 代理支持文档 - .env.example 和 .gitignore 更新
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
/* ==================== Element Plus 冷灰紫主题覆盖 ==================== */
|
||||
|
||||
/* -------------------- 输入框 -------------------- */
|
||||
.el-input__wrapper {
|
||||
background-color: var(--surface-3) !important;
|
||||
box-shadow: 0 0 0 1px var(--border) inset !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-input__wrapper:hover,
|
||||
@@ -7,8 +12,23 @@
|
||||
box-shadow: 0 0 0 1px var(--primary) inset !important;
|
||||
}
|
||||
|
||||
.el-input__wrapper.is-focus {
|
||||
box-shadow: 0 0 0 1px var(--primary) inset, var(--shadow-primary-sm) !important;
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
color: var(--text-primary) !important;
|
||||
}
|
||||
|
||||
.el-input__inner::placeholder {
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 选择器 -------------------- */
|
||||
.el-select__wrapper {
|
||||
background-color: var(--surface-3) !important;
|
||||
box-shadow: 0 0 0 1px var(--border) inset !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-select__wrapper:hover,
|
||||
@@ -16,55 +36,67 @@
|
||||
box-shadow: 0 0 0 1px var(--primary) inset !important;
|
||||
}
|
||||
|
||||
.el-select__wrapper.is-focused {
|
||||
box-shadow: 0 0 0 1px var(--primary) inset, var(--shadow-primary-sm) !important;
|
||||
}
|
||||
|
||||
.el-select__placeholder {
|
||||
color: var(--text-secondary) !important;
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
.el-select__caret {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.el-select__caret.is-reverse {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown {
|
||||
border: 1px solid var(--border) !important;
|
||||
box-shadow: var(--shadow-md) !important;
|
||||
background: white !important;
|
||||
box-shadow: var(--shadow-lg) !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: var(--text-primary) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item:hover {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item.is-selected {
|
||||
color: var(--primary) !important;
|
||||
font-weight: 600;
|
||||
background: var(--primary-soft) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 数字输入框 -------------------- */
|
||||
.el-input-number__decrease,
|
||||
.el-input-number__increase {
|
||||
background: var(--bg-light) !important;
|
||||
background: var(--surface-2) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
.el-input-number__decrease:hover,
|
||||
.el-input-number__increase:hover {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary) !important;
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-input-number__decrease.is-disabled,
|
||||
.el-input-number__increase.is-disabled {
|
||||
color: #ccc !important;
|
||||
color: var(--el-disabled-text) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
.el-input-number__wrapper {
|
||||
background-color: var(--surface-3) !important;
|
||||
box-shadow: 0 0 0 1px var(--border) inset !important;
|
||||
}
|
||||
|
||||
@@ -73,79 +105,132 @@
|
||||
box-shadow: 0 0 0 1px var(--primary) inset !important;
|
||||
}
|
||||
|
||||
/* -------------------- 按钮 -------------------- */
|
||||
.el-button {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: var(--surface-2) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
background: var(--gradient-primary) !important;
|
||||
.el-button:hover {
|
||||
border-color: var(--primary) !important;
|
||||
color: var(--primary) !important;
|
||||
background: var(--surface-3) !important;
|
||||
}
|
||||
|
||||
/* 主要按钮 - 深紫实心 */
|
||||
.el-button--primary {
|
||||
background: var(--primary-solid) !important;
|
||||
border-color: var(--primary-solid) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.el-button--primary:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 107, 157, 0.3) !important;
|
||||
transform: translateY(-2px);
|
||||
background: var(--primary-solid-hover) !important;
|
||||
border-color: var(--primary-solid-hover) !important;
|
||||
box-shadow: var(--shadow-primary-md) !important;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 成功按钮 - 青绿 */
|
||||
.el-button--success {
|
||||
background: var(--gradient-cyan) !important;
|
||||
border-color: var(--cyan) !important;
|
||||
color: white !important;
|
||||
background: var(--success) !important;
|
||||
border-color: var(--success) !important;
|
||||
color: var(--bg) !important;
|
||||
}
|
||||
|
||||
.el-button--success:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.3) !important;
|
||||
transform: translateY(-2px);
|
||||
background: #2DD4BF !important;
|
||||
border-color: #2DD4BF !important;
|
||||
box-shadow: 0 0 20px rgba(34, 197, 94, 0.3) !important;
|
||||
}
|
||||
|
||||
/* 警告按钮 - 橙黄 */
|
||||
.el-button--warning {
|
||||
background: var(--gradient-yellow) !important;
|
||||
border-color: var(--yellow) !important;
|
||||
color: white !important;
|
||||
background: var(--warning) !important;
|
||||
border-color: var(--warning) !important;
|
||||
color: var(--bg) !important;
|
||||
}
|
||||
|
||||
.el-button--warning:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 184, 0, 0.3) !important;
|
||||
transform: translateY(-2px);
|
||||
background: #FBBF24 !important;
|
||||
border-color: #FBBF24 !important;
|
||||
box-shadow: 0 0 20px rgba(245, 158, 11, 0.3) !important;
|
||||
}
|
||||
|
||||
/* 危险按钮 - 粉红 */
|
||||
.el-button--danger {
|
||||
background: var(--gradient-danger) !important;
|
||||
background: var(--danger) !important;
|
||||
border-color: var(--danger) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.el-button--danger:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3) !important;
|
||||
transform: translateY(-2px);
|
||||
background: #FCA5A5 !important;
|
||||
border-color: #FCA5A5 !important;
|
||||
box-shadow: 0 0 20px rgba(251, 113, 133, 0.3) !important;
|
||||
}
|
||||
|
||||
/* 纯文字按钮 */
|
||||
.el-button--text {
|
||||
background: transparent !important;
|
||||
border-color: transparent !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-button--text:hover {
|
||||
color: var(--primary-hover) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 卡片 -------------------- */
|
||||
.el-card {
|
||||
border: 1px solid var(--border) !important;
|
||||
box-shadow: var(--shadow-sm) !important;
|
||||
box-shadow: none !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-lg) !important;
|
||||
}
|
||||
|
||||
.el-card:hover {
|
||||
border-color: var(--border-light) !important;
|
||||
}
|
||||
|
||||
.el-card__header {
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
background: var(--bg-card) !important;
|
||||
background: transparent !important;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* -------------------- 表格 -------------------- */
|
||||
.el-table {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: white !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-lg) !important;
|
||||
--el-table-row-hover-bg-color: var(--surface-2);
|
||||
--el-table-current-row-bg-color: var(--primary-soft);
|
||||
--el-table-header-bg-color: var(--surface-2);
|
||||
--el-table-tr-bg-color: var(--surface);
|
||||
--el-table-expanded-cell-bg-color: var(--surface);
|
||||
}
|
||||
|
||||
.el-table th.el-table__cell {
|
||||
background: var(--bg-light) !important;
|
||||
color: var(--text-primary) !important;
|
||||
background: var(--surface-2) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.el-table td.el-table__cell {
|
||||
color: var(--text-primary) !important;
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
@@ -158,16 +243,22 @@
|
||||
}
|
||||
|
||||
.el-table tr:hover > td {
|
||||
background: #FFF0F5 !important;
|
||||
background: var(--surface-2) !important;
|
||||
}
|
||||
|
||||
.el-table__body tr.current-row > td.el-table__cell {
|
||||
background: var(--border) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
}
|
||||
|
||||
/* 表格行选中左侧高亮条 */
|
||||
.el-table__body tr.current-row > td.el-table__cell:first-child {
|
||||
border-left: 3px solid var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 复选框 -------------------- */
|
||||
.el-checkbox__inner {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: white !important;
|
||||
background: var(--surface-3) !important;
|
||||
}
|
||||
|
||||
.el-checkbox__inner:hover {
|
||||
@@ -180,61 +271,86 @@
|
||||
}
|
||||
|
||||
.el-checkbox__input.is-disabled .el-checkbox__inner {
|
||||
background: #f5f5f5 !important;
|
||||
border-color: #e4e7ed !important;
|
||||
background: var(--el-disabled-bg) !important;
|
||||
border-color: var(--el-disabled-border) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 分页 -------------------- */
|
||||
.el-pagination button {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: var(--bg-light) !important;
|
||||
background: var(--surface) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
border-radius: var(--radius-sm) !important;
|
||||
}
|
||||
|
||||
.el-pagination button:hover {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
background: var(--surface-2) !important;
|
||||
border-color: var(--primary) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-pagination li.is-active {
|
||||
background: var(--primary) !important;
|
||||
color: white !important;
|
||||
border-color: var(--primary) !important;
|
||||
.el-pagination button:disabled {
|
||||
background: var(--surface) !important;
|
||||
color: var(--text-muted) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
.el-pager li {
|
||||
background: var(--bg-light) !important;
|
||||
background: var(--surface) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
border-radius: var(--radius-sm) !important;
|
||||
}
|
||||
|
||||
.el-pager li:hover {
|
||||
color: var(--primary) !important;
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-pager li.is-active {
|
||||
background: var(--primary) !important;
|
||||
color: var(--bg) !important;
|
||||
border-color: var(--primary) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* -------------------- 标签 -------------------- */
|
||||
.el-tag {
|
||||
border-radius: var(--radius-sm) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-tag--primary {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary) !important;
|
||||
border-color: rgba(255, 107, 157, 0.3) !important;
|
||||
border-color: rgba(146, 124, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-tag--success {
|
||||
background: rgba(0, 212, 255, 0.1) !important;
|
||||
color: var(--cyan) !important;
|
||||
border-color: rgba(0, 212, 255, 0.3) !important;
|
||||
background: var(--success-soft) !important;
|
||||
color: var(--success) !important;
|
||||
border-color: rgba(34, 197, 94, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-tag--warning {
|
||||
background: rgba(255, 184, 0, 0.1) !important;
|
||||
color: var(--yellow) !important;
|
||||
border-color: rgba(255, 184, 0, 0.3) !important;
|
||||
background: var(--warning-soft) !important;
|
||||
color: var(--warning) !important;
|
||||
border-color: rgba(245, 158, 11, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-tag--danger {
|
||||
background: rgba(255, 107, 107, 0.1) !important;
|
||||
background: var(--danger-soft) !important;
|
||||
color: var(--danger) !important;
|
||||
border-color: rgba(255, 107, 107, 0.3) !important;
|
||||
border-color: rgba(251, 113, 133, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-tag--info {
|
||||
background: var(--info-soft) !important;
|
||||
color: var(--info) !important;
|
||||
border-color: rgba(56, 189, 248, 0.3) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 评分 -------------------- */
|
||||
.el-rate__icon {
|
||||
color: var(--border) !important;
|
||||
}
|
||||
@@ -243,36 +359,54 @@
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 对话框 -------------------- */
|
||||
.el-dialog {
|
||||
border: 1px solid var(--border) !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-lg) !important;
|
||||
box-shadow: var(--shadow-xl) !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid var(--border) !important;
|
||||
padding: 16px 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
color: var(--text-primary) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
background: white !important;
|
||||
background: transparent !important;
|
||||
color: var(--text-secondary) !important;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
border-top: 1px solid var(--border) !important;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
/* -------------------- 下拉菜单 -------------------- */
|
||||
.el-dropdown-menu {
|
||||
border: 1px solid var(--border) !important;
|
||||
box-shadow: var(--shadow-md) !important;
|
||||
box-shadow: var(--shadow-lg) !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-dropdown-menu__item {
|
||||
color: var(--text-primary) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.el-dropdown-menu__item:hover {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 滚动条 -------------------- */
|
||||
.el-scrollbar__wrap::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
@@ -287,46 +421,54 @@
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
/* -------------------- 表单 -------------------- */
|
||||
.el-form-item__label {
|
||||
color: var(--text-muted) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-form-item__error {
|
||||
color: var(--danger) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 消息提示 -------------------- */
|
||||
.el-message {
|
||||
border: 1px solid var(--border) !important;
|
||||
box-shadow: var(--shadow-md) !important;
|
||||
box-shadow: var(--shadow-lg) !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-message--success {
|
||||
background: rgba(0, 212, 255, 0.1) !important;
|
||||
border-color: rgba(0, 212, 255, 0.3) !important;
|
||||
color: var(--cyan) !important;
|
||||
background: var(--surface) !important;
|
||||
border-color: var(--success) !important;
|
||||
color: var(--success) !important;
|
||||
}
|
||||
|
||||
.el-message--error {
|
||||
background: rgba(255, 107, 107, 0.1) !important;
|
||||
border-color: rgba(255, 107, 107, 0.3) !important;
|
||||
background: var(--surface) !important;
|
||||
border-color: var(--danger) !important;
|
||||
color: var(--danger) !important;
|
||||
}
|
||||
|
||||
.el-message--warning {
|
||||
background: rgba(255, 184, 0, 0.1) !important;
|
||||
border-color: rgba(255, 184, 0, 0.3) !important;
|
||||
color: var(--yellow) !important;
|
||||
background: var(--surface) !important;
|
||||
border-color: var(--warning) !important;
|
||||
color: var(--warning) !important;
|
||||
}
|
||||
|
||||
.el-message--info {
|
||||
background: rgba(255, 107, 157, 0.1) !important;
|
||||
border-color: rgba(255, 107, 157, 0.3) !important;
|
||||
background: var(--surface) !important;
|
||||
border-color: var(--primary) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 消息盒子 -------------------- */
|
||||
.el-message-box {
|
||||
border: 1px solid var(--border) !important;
|
||||
box-shadow: var(--shadow-md) !important;
|
||||
box-shadow: var(--shadow-xl) !important;
|
||||
background: var(--surface) !important;
|
||||
border-radius: var(--radius-lg) !important;
|
||||
}
|
||||
|
||||
.el-message-box__header {
|
||||
@@ -334,33 +476,118 @@
|
||||
}
|
||||
|
||||
.el-message-box__title {
|
||||
color: var(--primary) !important;
|
||||
color: var(--text-primary) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.el-message-box__content {
|
||||
color: var(--text-primary) !important;
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.el-message-box__btns {
|
||||
border-top: 1px solid var(--border) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 警告提示 -------------------- */
|
||||
.el-alert {
|
||||
border-radius: var(--radius-md) !important;
|
||||
}
|
||||
|
||||
.el-alert--success {
|
||||
background-color: rgba(0, 255, 136, 0.1) !important;
|
||||
border-color: var(--green) !important;
|
||||
background-color: var(--success-soft) !important;
|
||||
border: 1px solid rgba(34, 197, 94, 0.3) !important;
|
||||
color: var(--success) !important;
|
||||
}
|
||||
|
||||
.el-alert--info {
|
||||
background-color: rgba(255, 107, 157, 0.1) !important;
|
||||
border-color: var(--primary) !important;
|
||||
background-color: var(--primary-soft) !important;
|
||||
border: 1px solid rgba(146, 124, 255, 0.3) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-alert--warning {
|
||||
background-color: rgba(255, 184, 0, 0.1) !important;
|
||||
border-color: var(--yellow) !important;
|
||||
background-color: var(--warning-soft) !important;
|
||||
border: 1px solid rgba(245, 158, 11, 0.3) !important;
|
||||
color: var(--warning) !important;
|
||||
}
|
||||
|
||||
.el-alert--error {
|
||||
background-color: rgba(255, 51, 102, 0.1) !important;
|
||||
border-color: var(--danger) !important;
|
||||
background-color: var(--danger-soft) !important;
|
||||
border: 1px solid rgba(251, 113, 133, 0.3) !important;
|
||||
color: var(--danger) !important;
|
||||
}
|
||||
|
||||
/* -------------------- Switch 开关 -------------------- */
|
||||
.theme-switch.el-switch .el-switch__core {
|
||||
background: var(--surface-3);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
.theme-switch.el-switch.is-checked .el-switch__core {
|
||||
border-color: var(--primary) !important;
|
||||
background-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 进度条 -------------------- */
|
||||
.el-progress-bar__outer {
|
||||
background-color: var(--surface-3) !important;
|
||||
}
|
||||
|
||||
.el-progress-bar__inner {
|
||||
background: var(--gradient-primary) !important;
|
||||
}
|
||||
|
||||
.el-progress__text {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- 菜单 -------------------- */
|
||||
.el-menu {
|
||||
background: transparent !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
.el-menu-item {
|
||||
color: var(--text-secondary) !important;
|
||||
border-radius: var(--radius-md);
|
||||
margin: 4px 8px;
|
||||
}
|
||||
|
||||
.el-menu-item:hover {
|
||||
background: var(--surface-2) !important;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* -------------------- Tabs -------------------- */
|
||||
.el-tabs__nav-wrap::after {
|
||||
background-color: var(--border) !important;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
.el-tabs__item:hover {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-tabs__item.is-active {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.el-tabs__active-bar {
|
||||
background-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
/* -------------------- Tooltip -------------------- */
|
||||
.el-tooltip__popper {
|
||||
background: var(--surface-2) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--text-primary) !important;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/**
|
||||
* 工具类 CSS - 冷灰紫主题
|
||||
* 提供通用的布局和样式工具类
|
||||
*/
|
||||
|
||||
/* ==================== 卡片 ==================== */
|
||||
.card-base {
|
||||
border-radius: var(--radius-xl);
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: var(--transition-hover);
|
||||
}
|
||||
|
||||
.card-base:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--border-light);
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
@@ -22,14 +26,15 @@
|
||||
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
letter-spacing: 1px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* ==================== 按钮工具类 ==================== */
|
||||
.btn-base {
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
transition: var(--transition-base);
|
||||
border: 1px solid var(--border);
|
||||
display: inline-flex;
|
||||
@@ -38,61 +43,87 @@
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
padding: 8px 16px;
|
||||
background: var(--surface-2);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--gradient-primary);
|
||||
.btn-base:hover {
|
||||
border-color: var(--primary);
|
||||
color: var(--primary);
|
||||
background: var(--surface-3);
|
||||
}
|
||||
|
||||
/* 主要按钮 - 深紫实心 */
|
||||
.btn-primary {
|
||||
background: var(--primary-solid);
|
||||
border-color: var(--primary-solid);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 107, 157, 0.3);
|
||||
transform: translateY(-2px);
|
||||
background: var(--primary-solid-hover);
|
||||
border-color: var(--primary-solid-hover);
|
||||
box-shadow: var(--shadow-primary-md);
|
||||
transform: translateY(-1px);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 成功按钮 */
|
||||
.btn-success {
|
||||
background: var(--gradient-cyan);
|
||||
border-color: var(--cyan);
|
||||
color: white;
|
||||
background: var(--success);
|
||||
border-color: var(--success);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
background: #2DD4BF;
|
||||
border-color: #2DD4BF;
|
||||
box-shadow: 0 0 20px rgba(34, 197, 94, 0.3);
|
||||
transform: translateY(-1px);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
/* 警告按钮 */
|
||||
.btn-warning {
|
||||
background: var(--gradient-yellow);
|
||||
border-color: var(--yellow);
|
||||
color: white;
|
||||
background: var(--warning);
|
||||
border-color: var(--warning);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
.btn-warning:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 184, 0, 0.3);
|
||||
transform: translateY(-2px);
|
||||
background: #FBBF24;
|
||||
border-color: #FBBF24;
|
||||
box-shadow: 0 0 20px rgba(245, 158, 11, 0.3);
|
||||
transform: translateY(-1px);
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
/* 危险按钮 */
|
||||
.btn-danger {
|
||||
background: var(--gradient-danger);
|
||||
background: var(--danger);
|
||||
border-color: var(--danger);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);
|
||||
transform: translateY(-2px);
|
||||
background: #FCA5A5;
|
||||
border-color: #FCA5A5;
|
||||
box-shadow: 0 0 20px rgba(251, 113, 133, 0.3);
|
||||
transform: translateY(-1px);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
margin-right: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* ==================== 布局 ==================== */
|
||||
.page-container {
|
||||
padding: 20px;
|
||||
background: var(--bg-page);
|
||||
padding: 24px;
|
||||
background: var(--bg);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@@ -104,7 +135,7 @@
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
@@ -114,12 +145,19 @@
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@media (max-width: 1200px) {
|
||||
.stat-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.stat-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flex 工具类 */
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -137,50 +175,103 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* ==================== 文字颜色 ==================== */
|
||||
.text-primary {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.text-cyan {
|
||||
color: var(--cyan);
|
||||
.text-accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: var(--green);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: var(--yellow);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.text-info {
|
||||
color: var(--info);
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* ==================== 背景 ==================== */
|
||||
.bg-gradient-primary {
|
||||
background: var(--gradient-primary);
|
||||
}
|
||||
|
||||
.bg-gradient-cyan {
|
||||
background: var(--gradient-cyan);
|
||||
.bg-gradient-accent {
|
||||
background: var(--gradient-accent);
|
||||
}
|
||||
|
||||
.border-pink {
|
||||
.bg-surface {
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.bg-surface-2 {
|
||||
background: var(--surface-2);
|
||||
}
|
||||
|
||||
.bg-surface-3 {
|
||||
background: var(--surface-3);
|
||||
}
|
||||
|
||||
/* ==================== 边框 ==================== */
|
||||
.border-default {
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.rounded-xl {
|
||||
border-radius: var(--radius-xl);
|
||||
.border-light {
|
||||
border: 1px solid var(--border-light);
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
|
||||
.border-none {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* ==================== 圆角 ==================== */
|
||||
.rounded-sm {
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.rounded-xl {
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
/* ==================== 阴影 ==================== */
|
||||
.shadow-sm {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
@@ -188,3 +279,156 @@
|
||||
.shadow-md {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.shadow-lg {
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.shadow-xl {
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
.shadow-none {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.shadow-primary {
|
||||
box-shadow: var(--shadow-primary-md);
|
||||
}
|
||||
|
||||
/* ==================== 间距 ==================== */
|
||||
.gap-4 {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.gap-8 {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.gap-12 {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.gap-16 {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.gap-20 {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* ==================== 文本工具 ==================== */
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.text-truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ==================== 显示 ==================== */
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* ==================== 响应式隐藏 ==================== */
|
||||
@media (max-width: 768px) {
|
||||
.hidden-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.hidden-desktop {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 焦点样式 ==================== */
|
||||
.focus-primary:focus {
|
||||
outline: none;
|
||||
box-shadow: var(--shadow-primary-sm);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.focus-accent:focus {
|
||||
outline: none;
|
||||
box-shadow: var(--shadow-accent-sm);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* ==================== 状态指示器 ==================== */
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.status-dot--success {
|
||||
background: var(--success);
|
||||
box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);
|
||||
}
|
||||
|
||||
.status-dot--warning {
|
||||
background: var(--warning);
|
||||
box-shadow: 0 0 8px rgba(245, 158, 11, 0.5);
|
||||
}
|
||||
|
||||
.status-dot--danger {
|
||||
background: var(--danger);
|
||||
box-shadow: 0 0 8px rgba(251, 113, 133, 0.5);
|
||||
}
|
||||
|
||||
.status-dot--info {
|
||||
background: var(--info);
|
||||
box-shadow: 0 0 8px rgba(56, 189, 248, 0.5);
|
||||
}
|
||||
|
||||
/* ==================== 分隔线 ==================== */
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: var(--border);
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.divider-vertical {
|
||||
width: 1px;
|
||||
background: var(--border);
|
||||
margin: 0 16px;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,87 @@
|
||||
/**
|
||||
* CSS 变量定义 - 冷灰紫主题
|
||||
* 设计理念:冷灰做信息底座,克制紫色做品牌识别和交互强调
|
||||
* 参考:Material 3 颜色角色体系
|
||||
*/
|
||||
|
||||
:root {
|
||||
--primary: #FF6B9D;
|
||||
--primary-light: #FF8FB3;
|
||||
--primary-dark: #FF5A8F;
|
||||
|
||||
--cyan: #00D4FF;
|
||||
--cyan-light: #00E5FF;
|
||||
--cyan-dark: #00B8E0;
|
||||
|
||||
--green: #34D399;
|
||||
--yellow: #FFB800;
|
||||
--danger: #FF6B6B;
|
||||
--purple: #A855F7;
|
||||
|
||||
--bg-page: #FAFAFA;
|
||||
--bg-card: #FFFFFF;
|
||||
--bg-light: #FFF9FB;
|
||||
|
||||
--text-primary: #333333;
|
||||
--text-secondary: #999999;
|
||||
--text-muted: #666666;
|
||||
|
||||
--border: #FFE4EC;
|
||||
--border-light: #FFD6E3;
|
||||
|
||||
--gradient-primary: linear-gradient(135deg, #FF6B9D 0%, #FF8FB3 100%);
|
||||
--gradient-cyan: linear-gradient(135deg, #00D4FF 0%, #00E5FF 100%);
|
||||
--gradient-yellow: linear-gradient(135deg, #FFB800 0%, #FFD000 100%);
|
||||
--gradient-danger: linear-gradient(135deg, #FF6B6B 0%, #FF8B8B 100%);
|
||||
|
||||
/* ==================== 背景层次 (Surface Roles) ==================== */
|
||||
--bg: #0F1117; /* 最底层背景,接近黑但不是纯黑 */
|
||||
--surface: #181C25; /* 卡片、表格、侧边栏 */
|
||||
--surface-2: #1F2430; /* 悬停状态、次级面板 */
|
||||
--surface-3: #262C3A; /* 输入框、选中行背景 */
|
||||
--border: #2E3545; /* 边框,负责把结构切出来 */
|
||||
--border-light: #3A4356; /* 稍亮的边框 */
|
||||
|
||||
/* ==================== 文字颜色 ==================== */
|
||||
--text-primary: #F5F7FA; /* 主要文字,对比度充足 */
|
||||
--text-secondary: #A5AEBD; /* 次要文字 */
|
||||
--text-muted: #7C8596; /* 弱化文字、placeholder */
|
||||
|
||||
/* ==================== 品牌紫色系 (Brand Purple) ==================== */
|
||||
/* 亮紫:用于链接、选中、图标、焦点 - "发光"和识别 */
|
||||
--primary: #927CFF;
|
||||
--primary-rgb: 146, 124, 255;
|
||||
--primary-hover: #A78BFA;
|
||||
--primary-soft: #2A2442; /* 淡紫背景,用于选中态底色 */
|
||||
|
||||
/* 深紫:用于实心按钮,配白字更稳 - "承载文字" */
|
||||
--primary-solid: #6B4EFF;
|
||||
--primary-solid-hover: #5B3DF5;
|
||||
|
||||
/* ==================== 辅助色 (Accent) ==================== */
|
||||
--accent: #2DD4BF; /* 青绿色,辅助强调 */
|
||||
--accent-rgb: 45, 212, 191;
|
||||
--accent-soft: #163A39; /* 淡青背景 */
|
||||
|
||||
/* ==================== 语义状态色 (Semantic Colors) ==================== */
|
||||
/* 紫色只表示"交互和品牌";绿/橙/红只表示"系统状态" */
|
||||
--success: #22C55E;
|
||||
--success-rgb: 34, 197, 94;
|
||||
--success-soft: #1A3A28;
|
||||
|
||||
--warning: #F59E0B;
|
||||
--warning-rgb: 245, 158, 11;
|
||||
--warning-soft: #3D3118;
|
||||
|
||||
--danger: #FB7185;
|
||||
--danger-rgb: 251, 113, 133;
|
||||
--danger-soft: #3D1F26;
|
||||
|
||||
--info: #38BDF8;
|
||||
--info-rgb: 56, 189, 248;
|
||||
--info-soft: #1A3A4A;
|
||||
|
||||
/* ==================== 渐变 ==================== */
|
||||
--gradient-primary: linear-gradient(135deg, #6B4EFF 0%, #927CFF 100%);
|
||||
--gradient-accent: linear-gradient(135deg, #2DD4BF 0%, #38BDF8 100%);
|
||||
--gradient-surface: linear-gradient(180deg, #181C25 0%, #1F2430 100%);
|
||||
|
||||
/* ==================== 圆角 ==================== */
|
||||
--radius-sm: 6px;
|
||||
--radius-md: 8px;
|
||||
--radius-md: 10px;
|
||||
--radius-lg: 12px;
|
||||
--radius-xl: 16px;
|
||||
--radius-2xl: 20px;
|
||||
|
||||
--shadow-sm: 0 2px 8px rgba(255, 107, 157, 0.08);
|
||||
--shadow-md: 0 4px 12px rgba(255, 107, 157, 0.15);
|
||||
--shadow-lg: 0 8px 20px rgba(255, 107, 157, 0.2);
|
||||
|
||||
--transition-base: all 0.3s ease;
|
||||
--transition-hover: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--radius-xl: 14px;
|
||||
--radius-2xl: 16px;
|
||||
|
||||
/* ==================== 阴影 (克制使用,更多靠层级和边框) ==================== */
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
|
||||
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.6);
|
||||
|
||||
/* 紫色光晕 - 用于焦点态 */
|
||||
--shadow-primary-sm: 0 0 0 2px rgba(146, 124, 255, 0.2);
|
||||
--shadow-primary-md: 0 0 20px rgba(146, 124, 255, 0.15);
|
||||
--shadow-accent-sm: 0 0 0 2px rgba(45, 212, 191, 0.2);
|
||||
|
||||
/* ==================== 过渡 ==================== */
|
||||
--transition-base: all 0.2s ease;
|
||||
--transition-hover: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
/* ==================== Element Plus 专用覆盖 ==================== */
|
||||
--el-disabled-bg: #262C3A;
|
||||
--el-disabled-border: #3A4356;
|
||||
--el-disabled-text: #7C8596;
|
||||
--el-switch-inactive: #3A4356;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user