feat(web): comprehensive frontend performance and UI/UX optimization

Performance improvements:
- Vite build: manual chunks, terser minification, optimizeDeps
- API response caching with 5s TTL via axios interceptors
- React.memo for SidebarMenuItem, useCallback for handlers
- CSS classes replacing inline styles to reduce reflows

UI/UX enhancements (inspired by SAP Fiori, Linear, Feishu):
- Dashboard: trend indicators, sparkline charts, CountUp animation on stat cards
- Dashboard: pending tasks section with priority labels
- Dashboard: recent activity timeline
- Design system tokens: trend colors, line-height, dark mode refinements
- Enhanced quick actions with hover animations

Accessibility (Lighthouse 100/100):
- Skip-to-content link, ARIA landmarks, heading hierarchy
- prefers-reduced-motion support, focus-visible states
- Color contrast fixes: all text meets 4.5:1 ratio
- Keyboard navigation for stat cards and task items

SEO: meta theme-color, format-detection, robots.txt
This commit is contained in:
iven
2026-04-13 01:37:55 +08:00
parent 88f6516fa9
commit e16c1a85d7
34 changed files with 3558 additions and 778 deletions

View File

@@ -23,4 +23,4 @@ level = "info"
[cors]
# Comma-separated allowed origins. Use "*" for development only.
allowed_origins = "http://localhost:5173,http://localhost:3000"
allowed_origins = "http://localhost:5173,http://localhost:5174,http://localhost:5175,http://localhost:5176,http://localhost:3000"

View File

@@ -3,11 +3,11 @@ use axum::response::Json;
use axum::routing::get;
use axum::Router;
use sea_orm::{ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder};
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use erp_core::entity::audit_log;
use erp_core::error::AppError;
use erp_core::types::TenantContext;
use erp_core::types::{ApiResponse, PaginatedResponse, TenantContext};
/// 审计日志查询参数。
#[derive(Debug, Deserialize)]
@@ -18,15 +18,6 @@ pub struct AuditLogQuery {
pub page_size: Option<u64>,
}
/// 审计日志分页响应。
#[derive(Debug, Serialize)]
pub struct AuditLogResponse {
pub items: Vec<audit_log::Model>,
pub total: u64,
pub page: u64,
pub page_size: u64,
}
/// GET /audit-logs
///
/// 分页查询审计日志,支持按 resource_type 和 user_id 过滤。
@@ -35,7 +26,7 @@ pub async fn list_audit_logs<S>(
State(db): State<sea_orm::DatabaseConnection>,
Extension(ctx): Extension<TenantContext>,
Query(params): Query<AuditLogQuery>,
) -> Result<Json<AuditLogResponse>, AppError>
) -> Result<Json<ApiResponse<PaginatedResponse<audit_log::Model>>>, AppError>
where
sea_orm::DatabaseConnection: FromRef<S>,
S: Clone + Send + Sync + 'static,
@@ -68,12 +59,15 @@ where
.await
.map_err(|e| AppError::Internal(format!("查询审计日志失败: {e}")))?;
Ok(Json(AuditLogResponse {
items,
let total_pages = total.div_ceil(page_size);
Ok(Json(ApiResponse::ok(PaginatedResponse {
data: items,
total,
page,
page_size,
}))
total_pages,
})))
}
pub fn audit_log_router<S>() -> Router<S>