diff --git a/internal/handlers/setup.go b/internal/handlers/setup.go
index c4b6c40..ec4990c 100644
--- a/internal/handlers/setup.go
+++ b/internal/handlers/setup.go
@@ -166,6 +166,41 @@ func (h *SetupHandler) enableUserSystem(adminConfig AdminConfig) error {
})
}
+func (h *SetupHandler) isSystemInitialized() (bool, error) {
+ return isSystemInitialized(h.manager, h.daoManager)
+}
+
+func isSystemInitialized(manager *config.ConfigManager, daoManager *repository.RepositoryManager) (bool, error) {
+ if daoManager != nil && daoManager.User != nil {
+ count, err := daoManager.User.CountAdminUsers()
+ if err != nil {
+ return false, err
+ }
+ return count > 0, nil
+ }
+
+ if manager == nil {
+ return false, nil
+ }
+
+ db := manager.GetDB()
+ if db == nil {
+ return false, nil
+ }
+
+ repo := repository.NewRepositoryManager(db)
+ if repo.User == nil {
+ return false, nil
+ }
+
+ count, err := repo.User.CountAdminUsers()
+ if err != nil {
+ return false, err
+ }
+
+ return count > 0, nil
+}
+
// contains 检查字符串是否包含子字符串
func contains(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
@@ -197,6 +232,17 @@ func InitializeNoDB(manager *config.ConfigManager) gin.HandlerFunc {
return
}
defer atomic.StoreInt32(&initInProgress, 0)
+
+ initialized, err := isSystemInitialized(manager, nil)
+ if err != nil {
+ logrus.WithError(err).Error("[InitializeNoDB] 检查系统初始化状态失败")
+ common.InternalServerErrorResponse(c, "检查系统初始化状态失败")
+ return
+ }
+ if initialized {
+ common.ForbiddenResponse(c, "系统已初始化,禁止重复初始化")
+ return
+ }
// 解析 JSON(仅接受嵌套结构),不再兼容 legacy 扁平字段
var req SetupRequest
if !utils.BindJSONWithValidation(c, &req) {
@@ -431,6 +477,17 @@ func (h *SetupHandler) Initialize(c *gin.Context) {
return
}
+ initialized, err := h.isSystemInitialized()
+ if err != nil {
+ logrus.WithError(err).Error("[SetupHandler.Initialize] 检查系统初始化状态失败")
+ common.InternalServerErrorResponse(c, "检查系统初始化状态失败")
+ return
+ }
+ if initialized {
+ common.ForbiddenResponse(c, "系统已初始化,禁止重复初始化")
+ return
+ }
+
var req SetupRequest
if !utils.BindJSONWithValidation(c, &req) {
return
diff --git a/internal/middleware/setup_guard.go b/internal/middleware/setup_guard.go
new file mode 100644
index 0000000..2da08fd
--- /dev/null
+++ b/internal/middleware/setup_guard.go
@@ -0,0 +1,109 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+ "github.com/sirupsen/logrus"
+)
+
+// SetupGuardConfig controls how the setup guard middleware behaves.
+type SetupGuardConfig struct {
+ // IsInitialized returns the current initialization status.
+ IsInitialized func() (bool, error)
+ // SetupPath denotes the setup entry path, defaults to /setup.
+ SetupPath string
+ // RedirectPath denotes the path to redirect to once initialized, defaults to /.
+ RedirectPath string
+ // AllowPaths lists exact paths that should remain accessible before initialization.
+ AllowPaths []string
+ // AllowPrefixes lists path prefixes that should remain accessible before initialization.
+ AllowPrefixes []string
+}
+
+// SetupGuard ensures only setup resources are accessible before initialization
+// and blocks setup routes after initialization is complete.
+func SetupGuard(cfg SetupGuardConfig) gin.HandlerFunc {
+ setupPath := cfg.SetupPath
+ if setupPath == "" {
+ setupPath = "/setup"
+ }
+ redirectPath := cfg.RedirectPath
+ if redirectPath == "" {
+ redirectPath = "/"
+ }
+
+ allowPaths := map[string]struct{}{
+ setupPath: {},
+ setupPath + "/": {},
+ }
+
+ for _, p := range cfg.AllowPaths {
+ allowPaths[p] = struct{}{}
+ }
+
+ allowPrefixes := []string{setupPath + "/"}
+ allowPrefixes = append(allowPrefixes, cfg.AllowPrefixes...)
+
+ return func(c *gin.Context) {
+ initialized := false
+ if cfg.IsInitialized != nil {
+ var err error
+ initialized, err = cfg.IsInitialized()
+ if err != nil {
+ logrus.WithError(err).Warn("setup guard: failed to determine initialization state")
+ // Fail closed on error so users can still reach setup for recovery.
+ initialized = false
+ }
+ }
+
+ path := c.Request.URL.Path
+
+ if initialized {
+ if path == setupPath || strings.HasPrefix(path, setupPath+"/") {
+ switch c.Request.Method {
+ case http.MethodGet, http.MethodHead:
+ c.Redirect(http.StatusFound, redirectPath)
+ case http.MethodOptions:
+ c.Status(http.StatusNoContent)
+ default:
+ c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
+ "code": http.StatusForbidden,
+ "message": "系统已初始化,禁止重新初始化",
+ })
+ }
+ c.Abort()
+ return
+ }
+
+ c.Next()
+ return
+ }
+
+ if _, ok := allowPaths[path]; ok {
+ c.Next()
+ return
+ }
+ for _, prefix := range allowPrefixes {
+ if strings.HasPrefix(path, prefix) {
+ c.Next()
+ return
+ }
+ }
+
+ switch c.Request.Method {
+ case http.MethodGet, http.MethodHead:
+ c.Redirect(http.StatusFound, setupPath)
+ case http.MethodOptions:
+ // Allow CORS preflight to complete without redirect loops.
+ c.Status(http.StatusNoContent)
+ default:
+ c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
+ "code": http.StatusForbidden,
+ "message": "系统未初始化,请访问 /setup 完成初始化",
+ })
+ }
+ c.Abort()
+ }
+}
diff --git a/internal/routes/setup.go b/internal/routes/setup.go
index 6898e34..92ebfe4 100644
--- a/internal/routes/setup.go
+++ b/internal/routes/setup.go
@@ -90,6 +90,71 @@ func CreateAndSetupRouter(
router.Use(middleware.CORS())
router.Use(middleware.RateLimit(manager))
+ var cachedInitialized atomic.Bool
+ var cachedRepo atomic.Pointer[repository.RepositoryManager]
+
+ guardConfig := middleware.SetupGuardConfig{
+ SetupPath: "/setup",
+ RedirectPath: "/",
+ AllowPaths: []string{
+ "/setup/initialize",
+ "/check-init",
+ "/user/system-info",
+ "/health",
+ },
+ AllowPrefixes: []string{
+ "/assets/",
+ "/css/",
+ "/js/",
+ "/components/",
+ },
+ }
+
+ guardConfig.IsInitialized = func() (bool, error) {
+ if cachedInitialized.Load() {
+ return true, nil
+ }
+
+ if daoManager != nil && daoManager.User != nil {
+ count, err := daoManager.User.CountAdminUsers()
+ if err != nil {
+ return false, err
+ }
+ if count > 0 {
+ cachedInitialized.Store(true)
+ return true, nil
+ }
+ return false, nil
+ }
+
+ db := manager.GetDB()
+ if db == nil {
+ return false, nil
+ }
+
+ repo := cachedRepo.Load()
+ if repo == nil || repo.DB() != db {
+ repo = repository.NewRepositoryManager(db)
+ cachedRepo.Store(repo)
+ }
+ if repo.User == nil {
+ return false, nil
+ }
+
+ count, err := repo.User.CountAdminUsers()
+ if err != nil {
+ return false, err
+ }
+
+ if count > 0 {
+ cachedInitialized.Store(true)
+ return true, nil
+ }
+ return false, nil
+ }
+
+ router.Use(middleware.SetupGuard(guardConfig))
+
// 如果 daoManager 为 nil,表示尚未初始化数据库,只注册基础和初始化相关的路由
if daoManager == nil {
// 基础路由(不传 userHandler)
diff --git a/themes/2025/admin/css/admin-modern.css b/themes/2025/admin/css/admin-modern.css
index 2e66ebe..9ded24b 100644
--- a/themes/2025/admin/css/admin-modern.css
+++ b/themes/2025/admin/css/admin-modern.css
@@ -60,6 +60,20 @@
--admin-status-dot-online: #34d399;
--admin-status-dot-warning: #facc15;
--admin-status-dot-offline: #f87171;
+ --admin-radius-lg: 20px;
+ --admin-radius-md: 16px;
+ --admin-radius-sm: 12px;
+ --admin-input-bg: rgba(255, 255, 255, 0.9);
+ --admin-input-border: rgba(148, 163, 184, 0.25);
+ --admin-input-focus: rgba(99, 102, 241, 0.28);
+ --admin-table-header-bg: rgba(99, 102, 241, 0.08);
+ --admin-table-row-hover: rgba(99, 102, 241, 0.05);
+ --admin-chip-bg: rgba(79, 70, 229, 0.12);
+ --admin-chip-text: #4338ca;
+ --admin-warning-bg: rgba(250, 204, 21, 0.14);
+ --admin-warning-text: #b45309;
+ --admin-info-bg: rgba(59, 130, 246, 0.14);
+ --admin-info-text: #1d4ed8;
}
.admin-theme-dark {
@@ -124,6 +138,260 @@
--admin-status-dot-online: #34d399;
--admin-status-dot-warning: #facc15;
--admin-status-dot-offline: #f87171;
+ --admin-radius-lg: 18px;
+ --admin-radius-md: 14px;
+ --admin-radius-sm: 10px;
+ --admin-input-bg: rgba(15, 23, 42, 0.72);
+ --admin-input-border: rgba(99, 102, 241, 0.32);
+ --admin-input-focus: rgba(129, 140, 248, 0.45);
+ --admin-table-header-bg: rgba(79, 70, 229, 0.24);
+ --admin-table-row-hover: rgba(79, 70, 229, 0.14);
+ --admin-chip-bg: rgba(129, 140, 248, 0.24);
+ --admin-chip-text: #e0e7ff;
+ --admin-warning-bg: rgba(250, 204, 21, 0.18);
+ --admin-warning-text: #facc15;
+ --admin-info-bg: rgba(59, 130, 246, 0.24);
+ --admin-info-text: #93c5fd;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Shared Admin Components */
+/* -------------------------------------------------------------------------- */
+
+.admin-card,
+.admin-surface-card,
+.admin-panel,
+.admin-shell-card {
+ position: relative;
+ background: var(--admin-panel-bg);
+ border: 1px solid var(--admin-panel-border);
+ border-radius: var(--admin-radius-lg);
+ box-shadow: var(--admin-panel-shadow);
+ padding: 24px;
+ backdrop-filter: blur(14px);
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
+}
+
+.admin-card:hover,
+.admin-surface-card:hover,
+.admin-panel:hover,
+.admin-shell-card:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--admin-shadow-soft);
+ border-color: rgba(79, 70, 229, 0.22);
+}
+
+.admin-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 18px;
+ flex-wrap: wrap;
+ padding: 22px;
+ border-radius: var(--admin-radius-lg);
+ background: rgba(255, 255, 255, 0.78);
+ border: 1px solid var(--admin-border);
+ box-shadow: var(--admin-shadow-card);
+}
+
+.admin-toolbar .toolbar-actions {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.admin-input,
+.admin-toolbar input[type="text"],
+.admin-toolbar input[type="search"],
+.admin-toolbar select,
+.admin-modal input,
+.admin-modal select {
+ width: 100%;
+ padding: 12px 16px;
+ border-radius: var(--admin-radius-sm);
+ border: 1px solid var(--admin-input-border);
+ background: var(--admin-input-bg);
+ color: var(--admin-text);
+ font-size: 14px;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
+}
+
+.admin-input:focus,
+.admin-toolbar input[type="text"]:focus,
+.admin-toolbar input[type="search"]:focus,
+.admin-toolbar select:focus,
+.admin-modal input:focus,
+.admin-modal select:focus {
+ outline: none;
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
+ background: rgba(255, 255, 255, 0.95);
+}
+
+.admin-chip,
+.admin-pill,
+.admin-tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 14px;
+ border-radius: 999px;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ background: var(--admin-chip-bg);
+ color: var(--admin-chip-text);
+}
+
+.admin-chip.icon i,
+.admin-pill.icon i,
+.admin-tag.icon i {
+ font-size: 12px;
+}
+
+.admin-chip.warning {
+ background: var(--admin-warning-bg);
+ color: var(--admin-warning-text);
+}
+
+.admin-chip.info {
+ background: var(--admin-info-bg);
+ color: var(--admin-info-text);
+}
+
+.admin-button,
+.admin-toolbar .btn,
+.admin-chip-action {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ border-radius: var(--admin-radius-sm);
+ border: none;
+ padding: 12px 18px;
+ font-size: 14px;
+ font-weight: 600;
+ background: linear-gradient(135deg, var(--admin-primary-btn-start) 0%, var(--admin-primary-btn-end) 100%);
+ color: #fff;
+ box-shadow: var(--admin-primary-btn-shadow);
+ cursor: pointer;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.admin-button:hover,
+.admin-toolbar .btn:hover,
+.admin-chip-action:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 16px 28px rgba(99, 102, 241, 0.3);
+}
+
+.admin-button.ghost,
+.admin-toolbar .btn.ghost {
+ background: var(--admin-ghost-bg);
+ color: var(--admin-accent);
+ box-shadow: none;
+}
+
+.admin-button.ghost:hover,
+.admin-toolbar .btn.ghost:hover {
+ background: var(--admin-ghost-bg-hover);
+}
+
+.admin-table {
+ width: 100%;
+ border-collapse: collapse;
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
+ overflow: hidden;
+ border: 1px solid var(--admin-panel-border);
+ box-shadow: var(--admin-shadow-card);
+}
+
+.admin-table thead {
+ background: var(--admin-table-header-bg);
+ color: var(--admin-heading);
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ font-size: 12px;
+}
+
+.admin-table th,
+.admin-table td {
+ padding: 16px 20px;
+ text-align: left;
+ border-bottom: 1px solid rgba(148, 163, 184, 0.18);
+ font-size: 14px;
+}
+
+.admin-table tbody tr:hover {
+ background: var(--admin-table-row-hover);
+}
+
+.admin-table tbody tr:last-child td {
+ border-bottom: none;
+}
+
+.admin-muted-note {
+ color: var(--admin-muted);
+ font-size: 13px;
+}
+
+.admin-modal {
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
+ border: 1px solid var(--admin-panel-border);
+ box-shadow: 0 40px 80px rgba(15, 23, 42, 0.28);
+ overflow: hidden;
+ backdrop-filter: blur(24px);
+}
+
+.admin-modal-header {
+ padding: 24px 28px;
+ background: linear-gradient(145deg, var(--admin-nav-active-start) 0%, var(--admin-nav-active-end) 100%);
+ color: #fff;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.admin-modal-body {
+ padding: 24px 28px;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ background: rgba(255, 255, 255, 0.92);
+}
+
+.admin-modal-footer {
+ padding: 20px 28px;
+ background: rgba(249, 250, 255, 0.85);
+ display: flex;
+ justify-content: flex-end;
+ gap: 12px;
+ border-top: 1px solid rgba(148, 163, 184, 0.18);
+}
+
+.admin-form-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 20px;
+}
+
+.admin-form-group label {
+ display: block;
+ font-size: 13px;
+ letter-spacing: 0.02em;
+ font-weight: 600;
+ margin-bottom: 8px;
+ color: var(--admin-muted);
+}
+
+.admin-description {
+ font-size: 14px;
+ color: var(--admin-muted);
+ line-height: 1.7;
+ margin-bottom: 16px;
}
body.admin-modern-body {
diff --git a/themes/2025/admin/css/files.css b/themes/2025/admin/css/files.css
index 13a65f8..3866869 100644
--- a/themes/2025/admin/css/files.css
+++ b/themes/2025/admin/css/files.css
@@ -2,15 +2,16 @@
/* 文件管理工具栏 */
.files-toolbar {
- background: white;
- border-radius: 8px;
- padding: 20px;
- margin-bottom: 20px;
+ background: rgba(255, 255, 255, 0.86);
+ border-radius: var(--admin-radius-lg);
+ padding: 22px;
+ margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ box-shadow: var(--admin-shadow-card);
+ border: 1px solid var(--admin-border);
flex-wrap: wrap;
}
@@ -28,17 +29,19 @@
.files-search-input {
flex: 1;
- padding: 10px 16px;
- border: 1px solid #ced4da;
- border-radius: 6px;
+ padding: 12px 16px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
font-size: 14px;
- transition: border-color 0.2s ease;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ background: var(--admin-input-bg);
}
.files-search-input:focus {
outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 0.2rem rgba(0,123,255,0.25);
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
+ background: rgba(255, 255, 255, 0.98);
}
.files-actions {
@@ -57,40 +60,41 @@
}
.files-stat-card {
- background: white;
- border-radius: 8px;
- padding: 16px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
+ padding: 20px;
+ box-shadow: var(--admin-panel-shadow);
text-align: center;
- border-left: 4px solid #007bff;
+ border-left: 4px solid var(--admin-accent-strong);
+ border: 1px solid var(--admin-panel-border);
}
.files-stat-value {
font-size: 24px;
font-weight: 700;
- color: #333;
+ color: var(--admin-heading);
margin-bottom: 4px;
}
.files-stat-label {
font-size: 13px;
- color: #6c757d;
+ color: var(--admin-muted);
font-weight: 500;
}
/* 文件视图切换 */
.view-toggle {
display: flex;
- border: 1px solid #e9ecef;
- border-radius: 6px;
+ border: 1px solid var(--admin-border);
+ border-radius: var(--admin-radius-sm);
overflow: hidden;
}
.view-toggle-btn {
padding: 8px 12px;
border: none;
- background: white;
- color: #6c757d;
+ background: var(--admin-surface);
+ color: var(--admin-muted);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
@@ -99,48 +103,53 @@
}
.view-toggle-btn.active {
- background: #007bff;
- color: white;
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
+ color: #fff;
}
.view-toggle-btn:hover:not(.active) {
- background: #f8f9fa;
+ background: var(--admin-interactive-bg-hover);
}
/* 文件列表视图 */
.files-list-container {
- background: white;
- border-radius: 8px;
+ background: transparent;
+ border-radius: var(--admin-radius-lg);
overflow: hidden;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ box-shadow: none;
margin-bottom: 20px;
}
.files-table {
width: 100%;
border-collapse: collapse;
+ background: var(--admin-panel-bg);
+ border: 1px solid var(--admin-panel-border);
+ border-radius: var(--admin-radius-lg);
+ overflow: hidden;
+ box-shadow: var(--admin-shadow-card);
}
.files-table th {
- background: #f8f9fa;
- padding: 12px 16px;
+ background: var(--admin-table-header-bg);
+ padding: 16px 20px;
text-align: left;
font-weight: 600;
- color: #333;
- border-bottom: 2px solid #e9ecef;
- font-size: 14px;
+ color: var(--admin-heading);
+ border-bottom: 1px solid rgba(148, 163, 184, 0.22);
+ font-size: 13px;
white-space: nowrap;
}
.files-table td {
- padding: 12px 16px;
- border-bottom: 1px solid #e9ecef;
+ padding: 16px 20px;
+ border-bottom: 1px solid rgba(148, 163, 184, 0.18);
vertical-align: middle;
font-size: 14px;
}
.files-table tbody tr:hover {
- background: #f8f9fa;
+ background: var(--admin-table-row-hover);
}
.files-table tbody tr:last-child td {
@@ -182,7 +191,7 @@
.file-name {
font-weight: 600;
- color: #333;
+ color: var(--admin-heading);
display: block;
margin-bottom: 2px;
word-break: break-all;
@@ -193,49 +202,50 @@
gap: 12px;
align-items: center;
flex-wrap: wrap;
+ color: var(--admin-muted);
}
.file-code {
font-family: monospace;
font-size: 12px;
- color: #6c757d;
- background: #f8f9fa;
+ color: var(--admin-subtle);
+ background: rgba(148, 163, 184, 0.16);
padding: 2px 6px;
- border-radius: 3px;
+ border-radius: var(--admin-radius-sm);
}
.file-size {
font-size: 12px;
- color: #6c757d;
+ color: var(--admin-muted);
}
.file-date {
font-size: 12px;
- color: #6c757d;
+ color: var(--admin-muted);
}
/* 文件状态标签 */
.file-status {
padding: 2px 8px;
- border-radius: 12px;
+ border-radius: 999px;
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
}
.file-status.public {
- background: #d4edda;
- color: #155724;
+ background: rgba(34, 197, 94, 0.18);
+ color: #047857;
}
.file-status.private {
- background: #f8d7da;
- color: #721c24;
+ background: rgba(239, 68, 68, 0.18);
+ color: #b91c1c;
}
.file-status.expired {
- background: #fff3cd;
- color: #856404;
+ background: rgba(245, 158, 11, 0.18);
+ color: #b45309;
}
/* 文件操作按钮 */
@@ -248,7 +258,7 @@
.file-action-btn {
padding: 4px 8px;
border: none;
- border-radius: 4px;
+ border-radius: var(--admin-radius-sm);
cursor: pointer;
transition: all 0.2s ease;
font-size: 12px;
@@ -261,32 +271,32 @@
.file-action-btn:hover {
transform: translateY(-1px);
- box-shadow: 0 2px 4px rgba(0,0,0,0.15);
+ box-shadow: 0 6px 12px rgba(79, 70, 229, 0.16);
}
.btn-view {
- background: #17a2b8;
- color: white;
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.85), rgba(29, 78, 216, 0.95));
+ color: #eff6ff;
}
.btn-download {
- background: #28a745;
- color: white;
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.9), rgba(5, 150, 105, 0.96));
+ color: #ecfdf5;
}
.btn-copy {
- background: #6c757d;
- color: white;
+ background: linear-gradient(135deg, rgba(148, 163, 184, 0.95), rgba(100, 116, 139, 0.92));
+ color: #f8fafc;
}
.btn-edit {
- background: #ffc107;
- color: #212529;
+ background: linear-gradient(135deg, rgba(249, 115, 22, 0.92), rgba(217, 119, 6, 0.92));
+ color: #fff7ed;
}
.btn-delete {
- background: #dc3545;
- color: white;
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.9), rgba(220, 38, 38, 0.96));
+ color: #fee2e2;
}
/* 文件网格视图 */
@@ -298,22 +308,23 @@
}
.file-card {
- background: white;
- border-radius: 8px;
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
overflow: hidden;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ box-shadow: var(--admin-panel-shadow);
transition: all 0.2s ease;
cursor: pointer;
+ border: 1px solid var(--admin-panel-border);
}
.file-card:hover {
transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+ box-shadow: var(--admin-shadow-soft);
}
.file-card-preview {
height: 120px;
- background: #f8f9fa;
+ background: rgba(148, 163, 184, 0.12);
display: flex;
align-items: center;
justify-content: center;
@@ -344,7 +355,7 @@
.file-card-name {
font-weight: 600;
- color: #333;
+ color: var(--admin-heading);
margin-bottom: 4px;
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -359,7 +370,7 @@
justify-content: space-between;
align-items: center;
font-size: 11px;
- color: #6c757d;
+ color: var(--admin-muted);
margin-bottom: 8px;
}
@@ -371,9 +382,9 @@
/* 批量操作 */
.bulk-actions {
- background: #e9ecef;
+ background: rgba(99, 102, 241, 0.08);
padding: 12px 16px;
- border-radius: 6px;
+ border-radius: var(--admin-radius-lg);
margin-bottom: 15px;
display: none;
align-items: center;
@@ -387,7 +398,7 @@
.bulk-info {
flex: 1;
font-size: 14px;
- color: #495057;
+ color: var(--admin-text);
}
.bulk-buttons {
@@ -397,25 +408,25 @@
/* 文件上传区域 */
.upload-area {
- border: 2px dashed #ced4da;
- border-radius: 8px;
+ border: 2px dashed rgba(99, 102, 241, 0.25);
+ border-radius: var(--admin-radius-lg);
padding: 40px 20px;
text-align: center;
- background: #f8f9fa;
+ background: rgba(99, 102, 241, 0.06);
transition: all 0.2s ease;
margin-bottom: 20px;
}
.upload-area.dragover {
- border-color: #007bff;
- background: #e6f3ff;
+ border-color: var(--admin-accent-strong);
+ background: rgba(99, 102, 241, 0.12);
}
.upload-icon {
width: 48px;
height: 48px;
border-radius: 50%;
- background: #007bff;
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
color: white;
display: flex;
align-items: center;
@@ -426,13 +437,13 @@
.upload-text {
font-size: 16px;
- color: #495057;
+ color: var(--admin-heading);
margin-bottom: 8px;
}
.upload-hint {
font-size: 14px;
- color: #6c757d;
+ color: var(--admin-muted);
}
/* 文件过滤器 */
@@ -446,36 +457,36 @@
.filter-label {
font-size: 14px;
- color: #495057;
+ color: var(--admin-text);
font-weight: 500;
}
.filter-select {
- padding: 6px 10px;
- border: 1px solid #ced4da;
- border-radius: 4px;
+ padding: 8px 12px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
font-size: 13px;
- background: white;
+ background: var(--admin-input-bg);
}
.filter-tag {
padding: 4px 8px;
- background: #e9ecef;
- border-radius: 12px;
+ background: var(--admin-chip-bg);
+ border-radius: 999px;
font-size: 12px;
- color: #495057;
+ color: var(--admin-chip-text);
cursor: pointer;
transition: all 0.2s ease;
}
.filter-tag.active {
- background: #007bff;
- color: white;
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
+ color: #fff;
}
.filter-tag:hover {
- background: #007bff;
- color: white;
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
+ color: #fff;
}
/* 响应式设计 */
@@ -552,4 +563,4 @@
align-items: flex-start;
gap: 4px;
}
-}
\ No newline at end of file
+}
diff --git a/themes/2025/admin/css/pagination.css b/themes/2025/admin/css/pagination.css
index 4116c9b..e7674e8 100644
--- a/themes/2025/admin/css/pagination.css
+++ b/themes/2025/admin/css/pagination.css
@@ -7,10 +7,11 @@
gap: 8px;
flex-wrap: wrap;
margin: 20px 0;
- padding: 16px;
- background: #f8f9fa;
- border-radius: 8px;
- border: 1px solid #e9ecef;
+ padding: 16px 20px;
+ background: rgba(255, 255, 255, 0.82);
+ border-radius: var(--admin-radius-lg);
+ border: 1px solid var(--admin-border);
+ box-shadow: var(--admin-shadow-card);
}
.pagination-numbers {
@@ -30,10 +31,10 @@
margin: 0 2px;
font-size: 14px;
font-weight: 500;
- color: #495057;
- background: #fff;
- border: 1px solid #dee2e6;
- border-radius: 6px;
+ color: var(--admin-text);
+ background: var(--admin-surface);
+ border: 1px solid var(--admin-border);
+ border-radius: var(--admin-radius-sm);
cursor: pointer;
transition: all 0.2s ease;
text-decoration: none;
@@ -41,11 +42,11 @@
}
.btn-page:hover {
- color: #007bff;
- background: #e7f3ff;
- border-color: #007bff;
+ color: var(--admin-accent);
+ background: var(--admin-interactive-bg-hover);
+ border-color: rgba(99, 102, 241, 0.24);
transform: translateY(-1px);
- box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
+ box-shadow: 0 6px 12px rgba(99, 102, 241, 0.16);
}
.btn-page:active {
@@ -55,15 +56,14 @@
.btn-page.active {
color: #fff;
- background: #007bff;
- border-color: #007bff;
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
+ border-color: transparent;
font-weight: 600;
- box-shadow: 0 2px 4px rgba(0, 123, 255, 0.3);
+ box-shadow: 0 8px 18px rgba(99, 102, 241, 0.32);
}
.btn-page.active:hover {
- background: #0056b3;
- border-color: #0056b3;
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
}
/* 特殊按钮样式 */
@@ -91,7 +91,7 @@
justify-content: center;
min-width: 36px;
height: 36px;
- color: #6c757d;
+ color: var(--admin-muted);
font-weight: bold;
user-select: none;
}
@@ -103,11 +103,11 @@
gap: 8px;
margin-left: 16px;
padding-left: 16px;
- border-left: 1px solid #dee2e6;
+ border-left: 1px solid var(--admin-border);
}
.pagination-jump span {
- color: #495057;
+ color: var(--admin-muted);
font-size: 14px;
white-space: nowrap;
}
@@ -116,8 +116,8 @@
width: 60px;
height: 32px;
padding: 4px 8px;
- border: 1px solid #ced4da;
- border-radius: 4px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
text-align: center;
font-size: 14px;
outline: none;
@@ -125,15 +125,15 @@
}
.pagination-jump input:focus {
- border-color: #007bff;
- box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
}
.pagination-jump .btn {
height: 32px;
padding: 4px 12px;
font-size: 13px;
- border-radius: 4px;
+ border-radius: var(--admin-radius-sm);
}
/* 页面大小选择器样式 */
@@ -143,11 +143,11 @@
gap: 8px;
margin-left: 16px;
padding-left: 16px;
- border-left: 1px solid #dee2e6;
+ border-left: 1px solid var(--admin-border);
}
.pagination-size span {
- color: #495057;
+ color: var(--admin-muted);
font-size: 14px;
white-space: nowrap;
}
@@ -155,18 +155,18 @@
.pagination-size select {
height: 32px;
padding: 4px 8px;
- border: 1px solid #ced4da;
- border-radius: 4px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
font-size: 14px;
- background: #fff;
+ background: var(--admin-input-bg);
outline: none;
cursor: pointer;
transition: border-color 0.2s ease;
}
.pagination-size select:focus {
- border-color: #007bff;
- box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
}
/* 分页信息样式 */
@@ -175,15 +175,15 @@
align-items: center;
margin-bottom: 12px;
padding: 8px 16px;
- background: #e9ecef;
- border-radius: 6px;
- color: #495057;
+ background: rgba(99, 102, 241, 0.08);
+ border-radius: var(--admin-radius-sm);
+ color: var(--admin-text);
font-size: 14px;
font-weight: 500;
}
.pagination-info span {
- color: #007bff;
+ color: var(--admin-accent-strong);
font-weight: 600;
}
@@ -191,9 +191,10 @@
.pagination-container {
margin-top: 24px;
padding: 20px;
- background: #fff;
- border-radius: 8px;
- border: 1px solid #e9ecef;
+ background: rgba(255, 255, 255, 0.86);
+ border-radius: var(--admin-radius-lg);
+ border: 1px solid var(--admin-border);
+ box-shadow: var(--admin-shadow-card);
}
/* 响应式设计 */
@@ -214,7 +215,7 @@
margin-left: 0;
padding-left: 0;
border-left: none;
- border-top: 1px solid #dee2e6;
+ border-top: 1px solid var(--admin-border);
padding-top: 12px;
}
@@ -257,17 +258,17 @@
/* 禁用状态 */
.btn-page:disabled {
- color: #6c757d;
- background: #f8f9fa;
- border-color: #dee2e6;
+ color: rgba(71, 85, 105, 0.65);
+ background: rgba(148, 163, 184, 0.16);
+ border-color: transparent;
cursor: not-allowed;
opacity: 0.6;
}
.btn-page:disabled:hover {
- color: #6c757d;
- background: #f8f9fa;
- border-color: #dee2e6;
+ color: rgba(71, 85, 105, 0.65);
+ background: rgba(148, 163, 184, 0.16);
+ border-color: transparent;
transform: none;
box-shadow: none;
}
@@ -310,49 +311,4 @@
}
}
-/* 暗色主题支持 */
-@media (prefers-color-scheme: dark) {
- .pagination-wrapper {
- background: #343a40;
- border-color: #495057;
- }
-
- .btn-page {
- color: #e9ecef;
- background: #495057;
- border-color: #6c757d;
- }
-
- .btn-page:hover {
- color: #007bff;
- background: #343a40;
- border-color: #007bff;
- }
-
- .btn-page.active {
- color: #fff;
- background: #007bff;
- border-color: #007bff;
- }
-
- .pagination-info {
- background: #495057;
- color: #e9ecef;
- }
-
- .pagination-jump input,
- .pagination-size select {
- background: #495057;
- border-color: #6c757d;
- color: #e9ecef;
- }
-
- .pagination-ellipsis {
- color: #adb5bd;
- }
-
- .pagination-container {
- background: #343a40;
- border-color: #495057;
- }
-}
\ No newline at end of file
+/* 暗色主题支持通过 admin-theme-dark 变量自动生效 */
diff --git a/themes/2025/admin/css/users.css b/themes/2025/admin/css/users.css
index 078c517..729057a 100644
--- a/themes/2025/admin/css/users.css
+++ b/themes/2025/admin/css/users.css
@@ -2,12 +2,14 @@
/* 用户模态框美化 */
#user-modal .modal-content {
- max-width: 700px;
- background: white;
- border-radius: 16px;
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
+ max-width: 720px;
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
+ border: 1px solid var(--admin-panel-border);
+ box-shadow: var(--admin-panel-shadow);
overflow: hidden;
animation: modalSlideIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ backdrop-filter: blur(24px);
}
@keyframes modalSlideIn {
@@ -22,7 +24,7 @@
}
#user-modal .modal-header {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ background: linear-gradient(135deg, var(--admin-nav-active-start) 0%, var(--admin-nav-active-end) 100%);
padding: 24px 32px;
border-bottom: none;
position: relative;
@@ -74,7 +76,7 @@
transition: all 0.3s ease;
position: relative;
z-index: 2;
- background: rgba(255, 255, 255, 0.1);
+ background: rgba(255, 255, 255, 0.16);
border-radius: 50%;
width: 40px;
height: 40px;
@@ -91,7 +93,7 @@
#user-modal .modal-body {
padding: 32px;
- background: #fafbfc;
+ background: rgba(255, 255, 255, 0.9);
}
#user-modal .form-row {
@@ -108,7 +110,7 @@
#user-modal .form-group label {
font-weight: 600;
- color: #374151;
+ color: var(--admin-muted);
margin-bottom: 8px;
display: flex;
align-items: center;
@@ -120,35 +122,35 @@
content: '';
width: 3px;
height: 16px;
- background: linear-gradient(135deg, #667eea, #764ba2);
- border-radius: 2px;
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
+ border-radius: 999px;
}
#user-modal .form-control {
width: 100%;
padding: 12px 16px;
- border: 2px solid #e5e7eb;
- border-radius: 12px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
font-size: 14px;
transition: all 0.3s ease;
- background: white;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+ background: var(--admin-input-bg);
+ box-shadow: none;
}
#user-modal .form-control:focus {
- border-color: #667eea;
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
outline: none;
- background: white;
+ background: rgba(255, 255, 255, 0.98);
}
#user-modal .form-control:hover {
- border-color: #d1d5db;
+ border-color: rgba(99, 102, 241, 0.2);
}
#user-modal .form-text {
font-size: 12px;
- color: #6b7280;
+ color: var(--admin-subtle);
margin-top: 6px;
display: flex;
align-items: center;
@@ -157,7 +159,7 @@
#user-modal .form-text::before {
content: 'ℹ';
- color: #9ca3af;
+ color: var(--admin-subtle);
font-style: normal;
font-weight: bold;
}
@@ -167,31 +169,31 @@
align-items: center;
gap: 12px;
padding: 16px;
- background: white;
- border: 2px solid #e5e7eb;
- border-radius: 12px;
+ background: var(--admin-surface);
+ border: 1px solid var(--admin-border);
+ border-radius: var(--admin-radius-md);
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
- color: #374151;
+ color: var(--admin-text);
}
#user-modal .checkbox-label:hover {
- border-color: #667eea;
- background: #f8faff;
+ border-color: rgba(99, 102, 241, 0.28);
+ background: rgba(99, 102, 241, 0.08);
}
#user-modal .checkbox-label input[type="checkbox"] {
width: 20px;
height: 20px;
- accent-color: #667eea;
+ accent-color: var(--admin-accent-strong);
cursor: pointer;
}
#user-modal .modal-footer {
padding: 24px 32px;
- background: white;
- border-top: 1px solid #e5e7eb;
+ background: rgba(249, 250, 255, 0.92);
+ border-top: 1px solid rgba(148, 163, 184, 0.18);
display: flex;
justify-content: flex-end;
gap: 12px;
@@ -199,7 +201,7 @@
#user-modal .modal-footer .btn {
padding: 12px 24px;
- border-radius: 8px;
+ border-radius: var(--admin-radius-sm);
font-weight: 600;
font-size: 14px;
border: none;
@@ -213,26 +215,25 @@
}
#user-modal .modal-footer .btn-secondary {
- background: #f3f4f6;
- color: #374151;
- border: 2px solid #e5e7eb;
+ background: var(--admin-ghost-bg);
+ color: var(--admin-accent);
+ border: 1px solid transparent;
}
#user-modal .modal-footer .btn-secondary:hover {
- background: #e5e7eb;
- border-color: #d1d5db;
+ background: var(--admin-ghost-bg-hover);
}
#user-modal .modal-footer .btn-primary {
- background: linear-gradient(135deg, #667eea, #764ba2);
- color: white;
- border: 2px solid transparent;
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
+ color: #fff;
+ border: 1px solid transparent;
+ box-shadow: var(--admin-primary-btn-shadow);
}
#user-modal .modal-footer .btn-primary:hover {
transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
+ box-shadow: 0 16px 28px rgba(99, 102, 241, 0.32);
}
#user-modal .modal-footer .btn-primary:active {
@@ -241,13 +242,13 @@
/* 表单错误样式增强 */
#user-modal .form-control.error {
- border-color: #ef4444 !important;
- box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important;
- background: #fef2f2;
+ border-color: rgba(239, 68, 68, 0.52) !important;
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18) !important;
+ background: rgba(254, 242, 242, 0.92);
}
#user-modal .form-error {
- color: #ef4444;
+ color: var(--admin-danger);
font-size: 12px;
margin-top: 6px;
display: flex;
@@ -258,13 +259,13 @@
#user-modal .form-error::before {
content: '⚠';
- color: #ef4444;
+ color: currentColor;
}
#user-modal .form-control.success {
- border-color: #10b981;
- box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
- background: #f0fdf4;
+ border-color: rgba(34, 197, 94, 0.55);
+ box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18);
+ background: rgba(240, 253, 244, 0.94);
}
/* 特殊字段样式 */
@@ -278,7 +279,7 @@
}
#user-modal input[type="number"].form-control {
- background-image: url('data:image/svg+xml,');
+ background-image: url('data:image/svg+xml,');
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 16px;
@@ -314,14 +315,26 @@
}
}
-/* 表单错误样式 */
+/* 表单状态增强 */
+.form-control:focus {
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
+ outline: none;
+}
+
.form-control.error {
- border-color: #dc3545 !important;
- box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
+ border-color: rgba(239, 68, 68, 0.52) !important;
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18) !important;
+ background: rgba(254, 242, 242, 0.94);
+}
+
+.form-control.success {
+ border-color: rgba(34, 197, 94, 0.55);
+ box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18);
}
.form-error {
- color: #dc3545;
+ color: var(--admin-danger);
font-size: 12px;
margin-top: 4px;
display: block;
@@ -332,17 +345,6 @@
margin-bottom: 1rem;
}
-.form-control:focus {
- border-color: #007bff;
- box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
- outline: 0;
-}
-
-.form-control.success {
- border-color: #28a745;
- box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
-}
-
/* 用户统计卡片 */
.stats-row {
display: grid;
@@ -352,12 +354,12 @@
}
.stat-card {
- background: white;
- border-radius: 8px;
- padding: 20px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ background: var(--admin-panel-bg);
+ border-radius: var(--admin-radius-lg);
+ padding: 22px;
+ box-shadow: var(--admin-panel-shadow);
text-align: center;
- transition: all 0.3s ease;
+ transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
min-height: 120px;
display: flex;
flex-direction: column;
@@ -365,6 +367,7 @@
justify-content: center;
position: relative;
overflow: hidden;
+ border: 1px solid var(--admin-panel-border);
}
.stat-card::before {
@@ -373,13 +376,14 @@
top: 0;
left: 0;
right: 0;
- height: 3px;
- background: linear-gradient(135deg, #007bff, #0056b3);
+ height: 4px;
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
}
.stat-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+ transform: translateY(-4px);
+ box-shadow: var(--admin-shadow-soft);
+ border-color: rgba(79, 70, 229, 0.22);
}
.stat-icon {
@@ -392,50 +396,52 @@
margin-bottom: 12px;
font-size: 24px;
color: white;
+ box-shadow: 0 12px 24px rgba(79, 70, 229, 0.24);
}
.stat-icon.users {
- background: linear-gradient(135deg, #007bff, #0056b3);
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
}
.stat-icon.admins {
- background: linear-gradient(135deg, #28a745, #1e7e34);
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.8), rgba(5, 150, 105, 0.95));
}
.stat-icon.active {
- background: linear-gradient(135deg, #17a2b8, #138496);
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.85), rgba(29, 78, 216, 0.95));
}
.stat-icon.uploads {
- background: linear-gradient(135deg, #ffc107, #e0a800);
+ background: linear-gradient(135deg, rgba(249, 115, 22, 0.9), rgba(217, 119, 6, 0.95));
}
.stat-value {
font-size: 28px;
font-weight: 700;
- color: #333;
+ color: var(--admin-heading);
margin-bottom: 4px;
line-height: 1;
}
.stat-label {
font-size: 14px;
- color: #6c757d;
+ color: var(--admin-muted);
font-weight: 500;
margin: 0;
}
/* 工具栏样式 */
.user-toolbar {
- background: white;
- border-radius: 8px;
+ background: rgba(255, 255, 255, 0.86);
+ border-radius: var(--admin-radius-lg);
padding: 24px;
- margin-bottom: 20px;
+ margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 24px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ box-shadow: var(--admin-shadow-card);
+ border: 1px solid var(--admin-border);
flex-wrap: wrap;
}
@@ -453,17 +459,19 @@
.search-input {
flex: 1;
- padding: 10px 16px;
- border: 1px solid #ced4da;
- border-radius: 6px;
+ padding: 12px 16px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
font-size: 14px;
- transition: border-color 0.2s ease;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ background: var(--admin-input-bg);
}
.search-input:focus {
outline: none;
- border-color: #007bff;
- box-shadow: 0 0 0 0.2rem rgba(0,123,255,0.25);
+ border-color: var(--admin-accent-strong);
+ box-shadow: 0 0 0 3px var(--admin-input-focus);
+ background: rgba(255, 255, 255, 0.98);
}
.action-section {
@@ -475,52 +483,54 @@
/* 用户表格样式 */
.users-table-container {
- background: white;
- border-radius: 12px;
+ background: transparent;
+ border-radius: var(--admin-radius-lg);
overflow: hidden;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-bottom: 20px;
- border: 1px solid #e5e7eb;
}
.users-table {
width: 100%;
border-collapse: collapse;
margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
+ font-family: inherit;
+ background: var(--admin-panel-bg);
+ border: 1px solid var(--admin-panel-border);
+ border-radius: var(--admin-radius-lg);
+ overflow: hidden;
+ box-shadow: var(--admin-shadow-card);
}
.users-table th {
- background: linear-gradient(135deg, #f8faff 0%, #f1f5f9 100%);
+ background: var(--admin-table-header-bg);
padding: 18px 24px;
text-align: left;
font-weight: 600;
- color: #1e293b;
- border-bottom: 2px solid #e2e8f0;
+ color: var(--admin-heading);
+ border-bottom: 1px solid rgba(148, 163, 184, 0.22);
position: sticky;
top: 0;
z-index: 10;
- font-size: 14px;
white-space: nowrap;
text-transform: uppercase;
- letter-spacing: 0.5px;
+ letter-spacing: 0.08em;
font-size: 12px;
}
.users-table th:first-child {
- border-top-left-radius: 12px;
+ border-top-left-radius: var(--admin-radius-lg);
}
.users-table th:last-child {
- border-top-right-radius: 12px;
+ border-top-right-radius: var(--admin-radius-lg);
}
.users-table td {
- padding: 16px 24px;
- border-bottom: 1px solid #f1f5f9;
+ padding: 18px 24px;
+ border-bottom: 1px solid rgba(148, 163, 184, 0.18);
vertical-align: middle;
font-size: 14px;
- color: #374151;
+ color: var(--admin-text);
transition: background-color 0.2s ease;
}
@@ -530,13 +540,13 @@
}
.users-table tbody tr:hover {
- background: linear-gradient(135deg, #f8faff 0%, #f0f9ff 100%);
+ background: var(--admin-table-row-hover);
transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 4px 12px rgba(79, 70, 229, 0.12);
}
.users-table tbody tr:hover td {
- border-color: #e0e7ff;
+ border-color: rgba(99, 102, 241, 0.2);
}
.users-table tbody tr:last-child td {
@@ -546,7 +556,7 @@
.loading-cell {
text-align: center;
padding: 60px 20px;
- background: linear-gradient(135deg, #f8faff 0%, #f0f9ff 100%);
+ background: linear-gradient(135deg, rgba(99, 102, 241, 0.08), rgba(129, 140, 248, 0.12));
}
.loading-spinner {
@@ -554,12 +564,12 @@
flex-direction: column;
align-items: center;
gap: 16px;
- color: #6b7280;
+ color: var(--admin-muted);
}
.loading-spinner i {
font-size: 32px;
- color: #667eea;
+ color: var(--admin-accent-strong);
animation: spin 1s linear infinite;
}
@@ -578,7 +588,7 @@
width: 44px;
height: 44px;
border-radius: 50%;
- background: linear-gradient(135deg, #667eea, #764ba2);
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
display: flex;
align-items: center;
justify-content: center;
@@ -586,7 +596,7 @@
font-weight: 700;
font-size: 16px;
flex-shrink: 0;
- box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
+ box-shadow: 0 12px 24px rgba(79, 70, 229, 0.24);
position: relative;
}
@@ -597,8 +607,8 @@
right: -2px;
width: 12px;
height: 12px;
- background: #10b981;
- border: 2px solid white;
+ background: var(--admin-status-dot-online);
+ border: 2px solid var(--admin-panel-bg);
border-radius: 50%;
opacity: 0;
transition: opacity 0.3s ease;
@@ -617,16 +627,16 @@
.user-name {
font-weight: 600;
- color: #1e293b;
+ color: var(--admin-heading);
font-size: 15px;
line-height: 1.2;
}
.user-id {
font-size: 12px;
- color: #64748b;
+ color: var(--admin-subtle);
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
- background: #f1f5f9;
+ background: rgba(148, 163, 184, 0.18);
padding: 2px 6px;
border-radius: 4px;
display: inline-block;
@@ -639,7 +649,7 @@
align-items: center;
gap: 6px;
padding: 6px 14px;
- border-radius: 20px;
+ border-radius: 999px;
font-size: 12px;
font-weight: 600;
min-width: 80px;
@@ -649,6 +659,9 @@
letter-spacing: 0.5px;
position: relative;
overflow: hidden;
+ background: var(--admin-chip-bg);
+ color: var(--admin-chip-text);
+ border: 1px solid transparent;
}
.status-badge::before {
@@ -667,9 +680,9 @@
}
.status-active {
- background: linear-gradient(135deg, #10b981, #059669);
- color: white;
- box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.88), rgba(5, 150, 105, 0.96));
+ color: #ecfdf5;
+ box-shadow: 0 2px 10px rgba(16, 185, 129, 0.28);
}
.status-active::after {
@@ -679,9 +692,9 @@
}
.status-inactive {
- background: linear-gradient(135deg, #ef4444, #dc2626);
- color: white;
- box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.9), rgba(220, 38, 38, 0.96));
+ color: #fee2e2;
+ box-shadow: 0 2px 10px rgba(239, 68, 68, 0.28);
}
.status-inactive::after {
@@ -706,7 +719,7 @@
padding: 8px 10px;
font-size: 12px;
border: none;
- border-radius: 8px;
+ border-radius: var(--admin-radius-sm);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
@@ -753,28 +766,28 @@
/* 编辑按钮 */
.btn-small:nth-child(1) {
- background: linear-gradient(135deg, #3b82f6, #2563eb);
- color: white;
- box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
+ color: #fff;
+ box-shadow: 0 8px 16px rgba(99, 102, 241, 0.28);
}
/* 删除按钮 */
.btn-small:nth-child(2) {
- background: linear-gradient(135deg, #ef4444, #dc2626);
- color: white;
- box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.9), rgba(220, 38, 38, 0.96));
+ color: #fee2e2;
+ box-shadow: 0 8px 16px rgba(239, 68, 68, 0.28);
}
/* 激活/禁用按钮 */
.btn-small:nth-child(3) {
- background: linear-gradient(135deg, #10b981, #059669);
- color: white;
- box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.9), rgba(5, 150, 105, 0.96));
+ color: #ecfdf5;
+ box-shadow: 0 8px 16px rgba(16, 185, 129, 0.28);
}
.btn-small:nth-child(3).inactive {
- background: linear-gradient(135deg, #f59e0b, #d97706);
- box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.88), rgba(217, 119, 6, 0.94));
+ box-shadow: 0 8px 16px rgba(217, 119, 6, 0.26);
}
/* 分页样式 */
@@ -783,16 +796,17 @@
justify-content: space-between;
align-items: center;
padding: 20px 24px;
- background: white;
- border-radius: 8px;
+ background: rgba(255, 255, 255, 0.82);
+ border-radius: var(--admin-radius-lg);
margin-top: 20px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ box-shadow: var(--admin-shadow-card);
+ border: 1px solid var(--admin-border);
flex-wrap: wrap;
gap: 16px;
}
.pagination-info {
- color: #6c757d;
+ color: var(--admin-muted);
font-size: 14px;
font-weight: 500;
}
@@ -806,10 +820,10 @@
.btn-page {
padding: 8px 12px;
margin: 0 2px;
- border: 1px solid #dee2e6;
- background: white;
- color: #495057;
- border-radius: 6px;
+ border: 1px solid var(--admin-border);
+ background: var(--admin-surface);
+ color: var(--admin-text);
+ border-radius: var(--admin-radius-sm);
cursor: pointer;
transition: all 0.2s ease;
font-size: 14px;
@@ -822,22 +836,22 @@
}
.btn-page:hover {
- background: #e9ecef;
- border-color: #adb5bd;
+ background: var(--admin-interactive-bg-hover);
+ border-color: rgba(99, 102, 241, 0.24);
transform: translateY(-1px);
}
.btn-page.active {
- background: #007bff;
- color: white;
- border-color: #007bff;
- box-shadow: 0 2px 4px rgba(0,123,255,0.25);
+ background: linear-gradient(135deg, var(--admin-primary-btn-start), var(--admin-primary-btn-end));
+ color: #fff;
+ border-color: transparent;
+ box-shadow: 0 6px 16px rgba(99, 102, 241, 0.32);
}
.btn-page:disabled {
- background: #f8f9fa;
- color: #6c757d;
- border-color: #e9ecef;
+ background: rgba(148, 163, 184, 0.16);
+ color: rgba(71, 85, 105, 0.65);
+ border-color: transparent;
cursor: not-allowed;
transform: none;
}
@@ -847,14 +861,14 @@
width: 18px;
height: 18px;
cursor: pointer;
- accent-color: #007bff;
+ accent-color: var(--admin-accent-strong);
}
.select-all-checkbox {
width: 18px;
height: 18px;
cursor: pointer;
- accent-color: #007bff;
+ accent-color: var(--admin-accent-strong);
}
/* 用户详情模态框 */
@@ -868,14 +882,14 @@
gap: 16px;
margin-bottom: 20px;
padding-bottom: 16px;
- border-bottom: 1px solid #e9ecef;
+ border-bottom: 1px solid var(--admin-border);
}
.user-detail-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
- background: linear-gradient(135deg, #007bff, #0056b3);
+ background: linear-gradient(135deg, var(--admin-nav-active-start), var(--admin-nav-active-end));
display: flex;
align-items: center;
justify-content: center;
@@ -886,12 +900,12 @@
.user-detail-info h3 {
margin: 0 0 4px 0;
- color: #333;
+ color: var(--admin-heading);
}
.user-detail-info p {
margin: 0;
- color: #6c757d;
+ color: var(--admin-muted);
font-size: 14px;
}
@@ -901,7 +915,7 @@
.user-detail-section h4 {
margin: 0 0 12px 0;
- color: #495057;
+ color: var(--admin-heading);
font-size: 16px;
font-weight: 600;
}
@@ -916,18 +930,18 @@
display: flex;
justify-content: space-between;
padding: 8px 12px;
- background: #f8f9fa;
- border-radius: 4px;
+ background: rgba(148, 163, 184, 0.12);
+ border-radius: var(--admin-radius-sm);
font-size: 14px;
}
.user-detail-label {
font-weight: 500;
- color: #495057;
+ color: var(--admin-heading);
}
.user-detail-value {
- color: #6c757d;
+ color: var(--admin-muted);
font-family: monospace;
}
@@ -1053,7 +1067,7 @@
}
.user-filters label {
font-weight: 500;
- color: #495057;
+ color: var(--admin-muted);
margin-right: 6px;
}
@@ -1075,11 +1089,12 @@
align-items: center;
}
.search-input {
- padding: 8px 12px;
- border: 1px solid #e9ecef;
- border-radius: 6px;
+ padding: 12px 16px;
+ border: 1px solid var(--admin-input-border);
+ border-radius: var(--admin-radius-sm);
min-width: 280px;
- box-shadow: inset 0 1px 2px rgba(0,0,0,0.03);
+ box-shadow: none;
+ background: var(--admin-input-bg);
}
.action-section {
@@ -1088,18 +1103,18 @@
align-items: center;
}
.btn {
- padding: 8px 12px;
- border-radius: 6px;
+ padding: 10px 16px;
+ border-radius: var(--admin-radius-sm);
cursor: pointer;
border: none;
- background: #f5f7fa;
- color: #333;
+ background: var(--admin-ghost-bg);
+ color: var(--admin-accent);
font-weight: 500;
}
.btn:hover { opacity: 0.95; }
.btn-secondary {
- background: #ffffff;
- border: 1px solid #e9ecef;
+ background: var(--admin-surface);
+ border: 1px solid var(--admin-border);
}
/* 简单的下拉菜单样式(批量操作) */
@@ -1108,17 +1123,17 @@
position: absolute;
right: 0;
top: 100%;
- background: #ffffff;
- border: 1px solid #e9ecef;
- box-shadow: 0 6px 12px rgba(0,0,0,0.08);
+ background: var(--admin-surface);
+ border: 1px solid var(--admin-border);
+ box-shadow: 0 18px 32px rgba(15, 23, 42, 0.12);
display: none;
min-width: 180px;
- border-radius: 6px;
+ border-radius: var(--admin-radius-sm);
z-index: 1000;
overflow: hidden;
}
- .dropdown-menu a { display: block; padding: 8px 12px; color: #333; text-decoration: none; }
- .dropdown-menu a:hover { background: #f8f9fa; }
+ .dropdown-menu a { display: block; padding: 10px 14px; color: var(--admin-text); text-decoration: none; }
+ .dropdown-menu a:hover { background: var(--admin-interactive-bg-hover); }
.dropdown.open .dropdown-menu { display: block; }
}
-/* End: 强制桌面端布局 */
\ No newline at end of file
+/* End: 强制桌面端布局 */