From 294dea39f33be166991aca938ef9be97093c2c6f Mon Sep 17 00:00:00 2001 From: CI Test Date: Fri, 26 Jun 2026 21:40:50 +0800 Subject: [PATCH] feat: V21 design system alignment for admin pages - Create unified Admin.css with V21 design tokens - Update Dashboard with stat cards and V21 color scheme - Update Analytics with V21 chart colors and metrics - Update UserManagement with V21 table and search styles - Update LogViewer with V21 filter bar and log level tags - Update SystemMonitor with V21 progress and resource cards - Update AdminComingSoon with V21 result styling - Replace all inline styles with V21 CSS classes - Apply Indigo/Green/Amber/Purple V21 color palette --- apps/web/src/pages/admin/Admin.css | 517 +++++++++++++++++++ apps/web/src/pages/admin/AdminComingSoon.tsx | 34 +- apps/web/src/pages/admin/Analytics.tsx | 215 +++++--- apps/web/src/pages/admin/Dashboard.tsx | 66 ++- apps/web/src/pages/admin/LogViewer.tsx | 173 +++---- apps/web/src/pages/admin/SystemMonitor.tsx | 165 +++--- apps/web/src/pages/admin/UserManagement.tsx | 38 +- 7 files changed, 902 insertions(+), 306 deletions(-) create mode 100644 apps/web/src/pages/admin/Admin.css diff --git a/apps/web/src/pages/admin/Admin.css b/apps/web/src/pages/admin/Admin.css new file mode 100644 index 000000000..ea535aaf5 --- /dev/null +++ b/apps/web/src/pages/admin/Admin.css @@ -0,0 +1,517 @@ +/* V21 Admin 页面样式 */ + +/* 页面容器 */ +.dashboard-page, +.analytics-page, +.user-management-page, +.log-viewer-page, +.system-monitor-page, +.admin-coming-soon-page { + padding: 32px; + max-width: 1400px; + margin: 0 auto; +} + +/* 页面头部 */ +.xx-page-head { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 28px; + box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09); + padding: 32px 40px; + margin-bottom: 32px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.xx-page-head-content { + display: flex; + flex-direction: column; + gap: 8px; +} + +.xx-page-head h2 { + font-size: 28px; + font-weight: 900; + color: var(--slate, #0f172a); + margin: 0; + letter-spacing: -0.02em; +} + +.xx-page-head p { + font-size: 15px; + color: var(--muted, #64748b); + margin: 0; +} + +.xx-page-head-actions { + display: flex; + gap: 12px; + align-items: center; +} + +/* 简化页面头部(无操作按钮) */ +.xx-page-head-simple { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 28px; + box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09); + padding: 32px 40px; + margin-bottom: 32px; +} + +.xx-page-head-simple h2 { + font-size: 28px; + font-weight: 900; + color: var(--slate, #0f172a); + margin: 0 0 8px; + letter-spacing: -0.02em; +} + +.xx-page-head-simple p { + font-size: 15px; + color: var(--muted, #64748b); + margin: 0; +} + +/* V21 卡片 */ +.xx-card { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + padding: 24px; + transition: all 0.3s; +} + +.xx-card:hover { + box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08); +} + +.xx-card .ant-card-head { + border-bottom: 1px solid rgba(226, 232, 240, 0.8); + padding: 20px 24px; +} + +.xx-card .ant-card-head-title { + font-weight: 800; + font-size: 17px; + color: var(--slate, #0f172a); +} + +.xx-card .ant-card-body { + padding: 24px; +} + +/* 统计卡片网格 - 4列 */ +.xx-grid-4 { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + margin-bottom: 32px; +} + +@media (max-width: 1200px) { + .xx-grid-4 { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .xx-grid-4 { + grid-template-columns: 1fr; + } +} + +/* 统计卡片 */ +.xx-stat-card { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + padding: 24px; + transition: all 0.3s; +} + +.xx-stat-card:hover { + transform: translateY(-2px); + box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08); +} + +.xx-stat-card-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 16px; +} + +.xx-stat-card-icon { + width: 48px; + height: 48px; + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; +} + +.xx-stat-card-icon.primary { + background: linear-gradient(135deg, #6366f1, #4f46e5); + color: white; +} + +.xx-stat-card-icon.success { + background: linear-gradient(135deg, #34d399, #10b981); + color: white; +} + +.xx-stat-card-icon.warning { + background: linear-gradient(135deg, #fbbf24, #f59e0b); + color: white; +} + +.xx-stat-card-icon.purple { + background: linear-gradient(135deg, #a78bfa, #8b5cf6); + color: white; +} + +.xx-stat-card-icon.info { + background: linear-gradient(135deg, #60a5fa, #3b82f6); + color: white; +} + +.xx-stat-card-icon.orange { + background: linear-gradient(135deg, #fb923c, #f97316); + color: white; +} + +.xx-stat-card-label { + font-size: 14px; + color: var(--muted, #64748b); + font-weight: 500; + margin-bottom: 8px; +} + +.xx-stat-card-value { + font-size: 32px; + font-weight: 900; + color: var(--slate, #0f172a); + line-height: 1.2; + letter-spacing: -0.02em; +} + +.xx-stat-card-value.primary { + color: var(--indigo, #4f46e5); +} + +.xx-stat-card-value.success { + color: var(--green, #10b981); +} + +.xx-stat-card-value.warning { + color: var(--amber, #f59e0b); +} + +.xx-stat-card-value.purple { + color: #8b5cf6; +} + +.xx-stat-card-growth { + font-size: 13px; + color: var(--green, #10b981); + font-weight: 600; + margin-top: 8px; + display: flex; + align-items: center; + gap: 4px; +} + +/* 数据表格 */ +.xx-table-wrapper { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + overflow: hidden; +} + +.xx-table-wrapper .ant-table { + background: transparent; +} + +.xx-table-wrapper .ant-table-thead > tr > th { + background: rgba(248, 250, 252, 0.8); + font-weight: 800; + font-size: 13px; + color: var(--slate, #0f172a); + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 16px 20px; +} + +.xx-table-wrapper .ant-table-tbody > tr > td { + padding: 16px 20px; + font-size: 14px; +} + +.xx-table-wrapper .ant-table-tbody > tr:hover > td { + background: rgba(79, 70, 229, 0.03); +} + +/* V21 按钮 */ +.xx-primary-btn { + background: linear-gradient(135deg, #6366f1, #4f46e5) !important; + color: white !important; + border: none !important; + border-radius: 14px !important; + font-weight: 700 !important; + box-shadow: 0 8px 20px rgba(79, 70, 229, 0.25) !important; + transition: all 0.2s !important; +} + +.xx-primary-btn:hover { + box-shadow: 0 12px 28px rgba(79, 70, 229, 0.3) !important; + transform: translateY(-1px); +} + +.xx-ghost-btn { + background: white !important; + border: 1px solid rgba(226, 232, 240, 0.95) !important; + color: var(--slate, #0f172a) !important; + border-radius: 14px !important; + font-weight: 600 !important; + transition: all 0.2s !important; +} + +.xx-ghost-btn:hover { + border-color: var(--indigo, #4f46e5) !important; + color: var(--indigo, #4f46e5) !important; +} + +/* V21 输入框 */ +.xx-search-input { + border-radius: 14px !important; + border: 1px solid rgba(226, 232, 240, 0.95) !important; + padding: 8px 16px !important; +} + +.xx-search-input:hover, +.xx-search-input:focus { + border-color: var(--indigo, #4f46e5) !important; + box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1) !important; +} + +/* V21 Select */ +.xx-select { + border-radius: 14px !important; +} + +.xx-select:hover, +.xx-select:focus { + border-color: var(--indigo, #4f46e5) !important; + box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1) !important; +} + +/* V21 Tag */ +.xx-tag { + border-radius: 8px !important; + font-weight: 600 !important; + font-size: 12px !important; + padding: 4px 10px !important; +} + +.xx-tag.info { + background: rgba(59, 130, 246, 0.1) !important; + color: #3b82f6 !important; + border: 1px solid rgba(59, 130, 246, 0.2) !important; +} + +.xx-tag.success { + background: rgba(16, 185, 129, 0.1) !important; + color: #10b981 !important; + border: 1px solid rgba(16, 185, 129, 0.2) !important; +} + +.xx-tag.warning { + background: rgba(245, 158, 11, 0.1) !important; + color: #f59e0b !important; + border: 1px solid rgba(245, 158, 11, 0.2) !important; +} + +.xx-tag.error { + background: rgba(239, 68, 68, 0.1) !important; + color: #ef4444 !important; + border: 1px solid rgba(239, 68, 68, 0.2) !important; +} + +.xx-tag.debug { + background: rgba(100, 116, 139, 0.1) !important; + color: #64748b !important; + border: 1px solid rgba(100, 116, 139, 0.2) !important; +} + +/* V21 Progress */ +.xx-progress-primary .ant-progress-circle .ant-progress-text { + color: var(--indigo, #4f46e5) !important; + font-weight: 700 !important; +} + +.xx-progress-success .ant-progress-circle .ant-progress-text { + color: var(--green, #10b981) !important; + font-weight: 700 !important; +} + +.xx-progress-warning .ant-progress-circle .ant-progress-text { + color: var(--amber, #f59e0b) !important; + font-weight: 700 !important; +} + +/* 图表容器 */ +.xx-chart-container { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + padding: 24px; +} + +.xx-chart-container .ant-card-head { + border-bottom: 1px solid rgba(226, 232, 240, 0.8); + padding: 20px 24px; +} + +.xx-chart-container .ant-card-head-title { + font-weight: 800; + font-size: 17px; + color: var(--slate, #0f172a); +} + +/* 筛选器区域 */ +.xx-filter-bar { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + padding: 20px 24px; + margin-bottom: 24px; + display: flex; + flex-wrap: wrap; + gap: 16px; + align-items: center; +} + +/* 资源监控卡片 */ +.xx-resource-card { + background: rgba(255, 255, 255, 0.94); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 22px; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + padding: 24px; + text-align: center; +} + +.xx-resource-card-icon { + width: 64px; + height: 64px; + border-radius: 18px; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 16px; + font-size: 28px; +} + +.xx-resource-card-label { + font-size: 14px; + color: var(--muted, #64748b); + font-weight: 600; + margin-bottom: 16px; +} + +/* 日期选择器 */ +.xx-date-picker { + border-radius: 14px !important; +} + +/* Drawer */ +.xx-drawer .ant-drawer-header { + border-bottom: 1px solid rgba(226, 232, 240, 0.8); + padding: 20px 24px; +} + +.xx-drawer .ant-drawer-title { + font-weight: 800; + font-size: 18px; + color: var(--slate, #0f172a); +} + +/* 日志详情 */ +.xx-log-detail { + padding: 4px 0; +} + +.xx-log-detail-label { + font-size: 13px; + font-weight: 700; + color: var(--slate, #0f172a); + margin-bottom: 4px; +} + +.xx-log-detail-value { + font-size: 14px; + color: var(--muted, #64748b); + background: rgba(248, 250, 252, 0.8); + padding: 12px; + border-radius: 10px; + margin-bottom: 16px; +} + +.xx-log-detail-code { + font-family: 'JetBrains Mono', 'Fira Code', monospace; + background: rgba(248, 250, 252, 0.8); + padding: 12px; + border-radius: 10px; + white-space: pre-wrap; + word-break: break-all; +} + +/* Result 页面居中 */ +.xx-result-center { + display: flex; + justify-content: center; + align-items: center; + min-height: 400px; +} + +.xx-result-center .ant-result { + padding: 48px; +} + +/* 刷新时间显示 */ +.xx-refresh-time { + font-size: 13px; + color: var(--muted, #64748b); + margin-right: 12px; +} + +/* 图表配色覆盖 */ +.recharts-text { + fill: #64748b !important; + font-size: 12px !important; +} + +.recharts-cartesian-grid-horizontal line, +.recharts-cartesian-grid-vertical line { + stroke: rgba(226, 232, 240, 0.8) !important; +} + +/* 图表 Legend */ +.recharts-legend-wrapper { + padding-top: 16px !important; +} + +.recharts-legend-item-text { + color: #64748b !important; + font-size: 13px !important; +} diff --git a/apps/web/src/pages/admin/AdminComingSoon.tsx b/apps/web/src/pages/admin/AdminComingSoon.tsx index 33c52e335..e2a8abd46 100644 --- a/apps/web/src/pages/admin/AdminComingSoon.tsx +++ b/apps/web/src/pages/admin/AdminComingSoon.tsx @@ -1,24 +1,32 @@ import React from 'react'; import { Button, Card, Result } from 'antd'; import { useNavigate } from 'react-router-dom'; +import './Admin.css'; const AdminComingSoon: React.FC = () => { const navigate = useNavigate(); return ( -
- - navigate('/workspaces')}> - 返回工作空间 - , - ]} - /> - +
+
+ + navigate('/workspaces')} + className="xx-primary-btn" + > + 返回工作空间 + , + ]} + /> + +
); }; diff --git a/apps/web/src/pages/admin/Analytics.tsx b/apps/web/src/pages/admin/Analytics.tsx index f2c14b852..186e6e67a 100644 --- a/apps/web/src/pages/admin/Analytics.tsx +++ b/apps/web/src/pages/admin/Analytics.tsx @@ -24,9 +24,22 @@ import { DollarOutlined, ProjectOutlined, } from '@ant-design/icons'; +import './Admin.css'; const { RangePicker } = DatePicker; +// V21 配色 +const V21_COLORS = { + primary: '#4f46e5', + primaryLight: '#6366f1', + success: '#10b981', + successLight: '#34d399', + warning: '#f59e0b', + warningLight: '#fbbf24', + purple: '#8b5cf6', + purpleLight: '#a78bfa', +}; + const Analytics: React.FC = () => { // 模拟用户增长数据 const userGrowthData = [ @@ -50,17 +63,17 @@ const Analytics: React.FC = () => { // 订阅计划分布 const planDistribution = [ - { name: 'Free', value: 485, color: '#8884d8' }, - { name: 'Pro', value: 120, color: '#82ca9d' }, - { name: 'Enterprise', value: 15, color: '#ffc658' }, + { name: 'Free', value: 485, color: '#a78bfa' }, + { name: 'Pro', value: 120, color: '#34d399' }, + { name: 'Enterprise', value: 15, color: '#fbbf24' }, ]; // 活跃度统计 const activityStats = [ - { metric: '日活跃用户 (DAU)', value: 892, growth: '+12.5%', icon: }, - { metric: '月活跃用户 (MAU)', value: 3456, growth: '+8.3%', icon: }, - { metric: '本月收入', value: 13365, prefix: '¥', growth: '+51.6%', icon: }, - { metric: '活跃项目数', value: 2341, growth: '+18.2%', icon: }, + { metric: '日活跃用户 (DAU)', value: 892, growth: '+12.5%', icon: , colorClass: 'primary' }, + { metric: '月活跃用户 (MAU)', value: 3456, growth: '+8.3%', icon: , colorClass: 'success' }, + { metric: '本月收入', value: 13365, prefix: '¥', growth: '+51.6%', icon: , colorClass: 'warning' }, + { metric: '活跃项目数', value: 2341, growth: '+18.2%', icon: , colorClass: 'purple' }, ]; // 用户留存表格 @@ -80,107 +93,149 @@ const Analytics: React.FC = () => { { title: 'Day 90', dataIndex: 'day90', key: 'day90' }, ]; + const colorMap: Record = { + primary: '#4f46e5', + success: '#10b981', + warning: '#f59e0b', + purple: '#8b5cf6', + }; + return ( -
-
-

数据分析

- - - +
+
+
+

数据分析

+

用户增长、营收趋势与留存分析

+
+
+ + + +
{/* 关键指标 */} - + {activityStats.map((stat, index) => ( - - -
+
+
+
+ {stat.icon} +
+
+
{stat.metric}
+
+ {stat.prefix}{stat.value.toLocaleString()} +
+
{stat.growth} vs 上月
- +
))} {/* 图表区域 */} - + {/* 用户增长趋势 */} - - - - - - - - - - - - - +
+ + + + + + + + + + + + + +
{/* 订阅计划分布 */} - - - - `${entry.name}: ${entry.value}`} - outerRadius={80} - fill="#8884d8" - dataKey="value" - > - {planDistribution.map((entry, index) => ( - - ))} - - - - - +
+ + + + `${entry.name}: ${entry.value}`} + outerRadius={80} + fill="#8884d8" + dataKey="value" + > + {planDistribution.map((entry, index) => ( + + ))} + + + + + +
{/* 营收趋势 */} - + - - - - - - - - - - - - +
+ + + + + + + + + + + + +
{/* 用户留存表 */} - - - +
+ +
+ + ); }; diff --git a/apps/web/src/pages/admin/Dashboard.tsx b/apps/web/src/pages/admin/Dashboard.tsx index e508e7ad7..469b6c2d7 100644 --- a/apps/web/src/pages/admin/Dashboard.tsx +++ b/apps/web/src/pages/admin/Dashboard.tsx @@ -9,14 +9,15 @@ import { DollarOutlined, RiseOutlined, } from '@ant-design/icons'; +import './Admin.css'; const Dashboard: React.FC = () => { // 模拟数据 const stats = [ - { title: '总用户数', value: 1234, icon: , color: '#1890ff' }, - { title: '付费用户', value: 156, icon: , color: '#52c41a' }, - { title: '月收入', value: 15444, prefix: '¥', icon: , color: '#faad14' }, - { title: '活跃用户', value: 892, icon: , color: '#722ed1' }, + { title: '总用户数', value: 1234, icon: , colorClass: 'primary' }, + { title: '付费用户', value: 156, icon: , colorClass: 'success' }, + { title: '月收入', value: 15444, prefix: '¥', icon: , colorClass: 'warning' }, + { title: '活跃用户', value: 892, icon: , colorClass: 'purple' }, ]; const recentUsers = [ @@ -31,34 +32,51 @@ const Dashboard: React.FC = () => { { title: '注册时间', dataIndex: 'created_at', key: 'created_at' }, ]; + const colorMap: Record = { + primary: '#4f46e5', + success: '#10b981', + warning: '#f59e0b', + purple: '#8b5cf6', + }; + return ( -
-

Dashboard

+
+
+

Dashboard

+

系统数据总览与关键指标

+
- + {stats.map((stat, index) => (
- - - +
+
+
+ {stat.icon} +
+
+
{stat.title}
+
+ {stat.prefix}{stat.value.toLocaleString()} +
+
))} - -
- +
+ +
+ + ); }; diff --git a/apps/web/src/pages/admin/LogViewer.tsx b/apps/web/src/pages/admin/LogViewer.tsx index 39bcb98e3..af0d6d527 100644 --- a/apps/web/src/pages/admin/LogViewer.tsx +++ b/apps/web/src/pages/admin/LogViewer.tsx @@ -10,6 +10,7 @@ import { EyeOutlined, } from '@ant-design/icons'; import type { ColumnsType } from 'antd/es/table'; +import './Admin.css'; const { Search } = Input; const { RangePicker } = DatePicker; @@ -118,14 +119,14 @@ const LogViewer: React.FC = () => { }, ]; - const getLevelColor = (level: string) => { - const colors: Record = { - INFO: 'blue', - WARN: 'orange', - ERROR: 'red', - DEBUG: 'default', + const getLevelTagClass = (level: string) => { + const classes: Record = { + INFO: 'xx-tag info', + WARN: 'xx-tag warning', + ERROR: 'xx-tag error', + DEBUG: 'xx-tag debug', }; - return colors[level] || 'default'; + return classes[level] || 'xx-tag debug'; }; const handleViewDetails = (log: LogEntry) => { @@ -146,7 +147,7 @@ const LogViewer: React.FC = () => { dataIndex: 'level', key: 'level', width: 100, - render: (level: string) => {level}, + render: (level: string) => {level}, filters: [ { text: 'INFO', value: 'INFO' }, { text: 'WARN', value: 'WARN' }, @@ -205,53 +206,61 @@ const LogViewer: React.FC = () => { ]; return ( -
-

日志查看器

+
+
+

日志查看器

+

系统日志查询与监控

+
- - - } - style={{ width: 300 }} - /> +
+ } + className="xx-search-input" + style={{ width: 280 }} + /> - + - + - + - - - - + + +
- +
{ }} scroll={{ x: 1200 }} /> - + {/* 日志详情抽屉 */} { width={600} open={drawerVisible} onClose={() => setDrawerVisible(false)} + className="xx-drawer" > {selectedLog && (
-
- 时间: -
{selectedLog.timestamp}
+
+
时间
+
{selectedLog.timestamp}
-
- 级别: -
- {selectedLog.level} +
+
级别
+
+ {selectedLog.level}
-
- 服务: -
{selectedLog.service}
+
+
服务
+
{selectedLog.service}
{selectedLog.user && ( -
- 用户: -
{selectedLog.user}
+
+
用户
+
{selectedLog.user}
)} -
- 操作: -
{selectedLog.action}
+
+
操作
+
{selectedLog.action}
-
- 详细信息: -
- {selectedLog.details} -
+
+
详细信息
+
{selectedLog.details}
{selectedLog.ip && ( -
- IP 地址: -
{selectedLog.ip}
+
+
IP 地址
+
{selectedLog.ip}
)} {selectedLog.request_id && ( -
- Request ID: -
- {selectedLog.request_id} -
+
+
Request ID
+
{selectedLog.request_id}
)}
diff --git a/apps/web/src/pages/admin/SystemMonitor.tsx b/apps/web/src/pages/admin/SystemMonitor.tsx index 680bea4d7..9d9109bbc 100644 --- a/apps/web/src/pages/admin/SystemMonitor.tsx +++ b/apps/web/src/pages/admin/SystemMonitor.tsx @@ -13,6 +13,7 @@ import { CloudServerOutlined, ThunderboltOutlined, } from '@ant-design/icons'; +import './Admin.css'; const SystemMonitor: React.FC = () => { const [refreshTime, setRefreshTime] = useState(new Date()); @@ -84,7 +85,7 @@ const SystemMonitor: React.FC = () => { dataIndex: 'errors', key: 'errors', render: (errors: number) => ( - 10 ? 'red' : errors > 5 ? 'orange' : 'green'}>{errors} + 10 ? 'xx-tag error' : errors > 5 ? 'xx-tag warning' : 'xx-tag success'}>{errors} ), }, ]; @@ -97,7 +98,7 @@ const SystemMonitor: React.FC = () => { key: 'level', width: 100, render: (level: string) => ( - {level} + {level} ), }, { title: '服务', dataIndex: 'service', key: 'service', width: 120 }, @@ -117,111 +118,103 @@ const SystemMonitor: React.FC = () => { // 模拟实时更新 useEffect(() => { const interval = setInterval(refreshMetrics, 5000); - return () => clearInterval(interval); }, []); const getProgressColor = (value: number) => { - if (value > 80) return '#ff4d4f'; - if (value > 60) return '#faad14'; - return '#52c41a'; + if (value > 80) return '#ef4444'; + if (value > 60) return '#f59e0b'; + return '#10b981'; }; + const getProgressClass = (value: number) => { + if (value > 80) return 'xx-progress-warning'; + if (value > 60) return 'xx-progress-warning'; + return 'xx-progress-success'; + }; + + const resourceMetrics = [ + { key: 'cpu', label: 'CPU 使用率', value: systemMetrics.cpu, icon: , bg: 'linear-gradient(135deg, #6366f1, #4f46e5)' }, + { key: 'memory', label: '内存使用率', value: systemMetrics.memory, icon: , bg: 'linear-gradient(135deg, #34d399, #10b981)' }, + { key: 'disk', label: '磁盘使用率', value: systemMetrics.disk, icon: , bg: 'linear-gradient(135deg, #fbbf24, #f59e0b)' }, + { key: 'network', label: '网络使用率', value: systemMetrics.network, icon: , bg: 'linear-gradient(135deg, #a78bfa, #8b5cf6)' }, + ]; + return ( -
-
-

系统监控

- - 上次更新: {refreshTime.toLocaleTimeString()} - - +
+
+
+

系统监控

+

服务器资源、服务健康与 API 统计

+
+
+ + 上次更新: {refreshTime.toLocaleTimeString()} + + +
{/* 系统资源监控 */} - -
- -
- -
CPU 使用率
+ + {resourceMetrics.map((metric) => ( +
+
+
+ {metric.icon} +
+
{metric.label}
- - - - -
- -
内存使用率
- -
-
- - - -
- -
磁盘使用率
- -
-
- - - -
- -
网络使用率
- -
-
- + + ))} {/* 服务健康状态 */} - -
- +
+ +
+ + {/* API 请求统计 */} - -
- +
+ +
+ + {/* 最近错误 */} - -
- +
+ +
+ + ); }; diff --git a/apps/web/src/pages/admin/UserManagement.tsx b/apps/web/src/pages/admin/UserManagement.tsx index e8d25e75a..18d3ac53b 100644 --- a/apps/web/src/pages/admin/UserManagement.tsx +++ b/apps/web/src/pages/admin/UserManagement.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { Table, Button, Space, Tag, Input, Card } from 'antd'; import { SearchOutlined, LockOutlined, UnlockOutlined } from '@ant-design/icons'; +import './Admin.css'; const { Search } = Input; @@ -44,7 +45,7 @@ const UserManagement: React.FC = () => { dataIndex: 'is_email_verified', key: 'is_email_verified', render: (verified: boolean) => ( - + {verified ? '已验证' : '未验证'} ), @@ -54,7 +55,7 @@ const UserManagement: React.FC = () => { dataIndex: 'status', key: 'status', render: (status: string) => ( - + {status === 'active' ? '正常' : '已封禁'} ), @@ -87,19 +88,26 @@ const UserManagement: React.FC = () => { ]; return ( -
-

用户管理

- -
- } - style={{ width: 300 }} - /> -
-
- +
+
+

用户管理

+

管理系统用户与账户状态

+
+ +
+ +
+ } + className="xx-search-input" + style={{ width: 320 }} + /> +
+
+ + ); };