feat: M3-M7 全模块落地 + 集成接线

- M3 认证/权限/审计/限流 + 全部 REST 接口
- M4 管理面板(MIUIx + 成绩录入/积分榜下钻/大屏控制)
- M5a 大屏页面(六页 + 明细覆盖层 + 缩放适配)
- M6 WebSocket 实时同步中心
- M7 xlsx 导出 + 赛事包 zip + 备份
- 规则包 YAML 导入导出(差异预览)
- 字体 vendor 子集化(4 套 x2 字重)
- 集成:realtime/export/rules 接入 main+httpapi;backup 子命令
- 修复:中间件包装 ResponseWriter 丢失 Hijacker,导致 WS 握手 501
This commit is contained in:
AskaEth committed 2026-09-09 19:02:24 +08:00
1 parent d0e3b93e76
commit bc8b1ee6c0
145 files changed
+25159 -321

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
/* ═══════════════════════════════════════════
MIUIX CONSOLE — Animations
═══════════════════════════════════════════ */
/* ── Entry animations ── */
@keyframes mx-slide-up{
from{opacity:0;transform:translateY(16px)}
to{opacity:1;transform:translateY(0)}
}
@keyframes mx-card-in{
from{opacity:0;transform:scale(0.96) translateY(10px)}
to{opacity:1;transform:scale(1) translateY(0)}
}
@keyframes mx-fade-item{
from{opacity:0;transform:translateX(-8px)}
to{opacity:1;transform:translateX(0)}
}
@keyframes mx-fade-row{
from{opacity:0;transform:translateY(4px)}
to{opacity:1;transform:translateY(0)}
}
@keyframes mx-bar-grow{
from{transform:scaleY(0);opacity:0}
to{transform:scaleY(1);opacity:1}
}
@keyframes mx-pulse{
0%,100%{opacity:1;transform:scale(1)}
50%{opacity:0.5;transform:scale(1.3)}
}
@keyframes mx-dot-in{
from{transform:translateX(-50%) scale(0);opacity:0}
to{transform:translateX(-50%) scale(1);opacity:1}
}
@keyframes mx-ripple{
to{transform:scale(4);opacity:0}
}
@keyframes mx-shimmer{
from{background-position:200% 0}
to{background-position:-200% 0}
}
/* ── Animation classes ── */
.mx-anim-slide-up{animation:mx-slide-up var(--mx-d3) var(--mx-ease)}
.mx-anim-card-in{animation:mx-card-in var(--mx-d3) var(--mx-ease) both}
.mx-anim-fade-item{animation:mx-fade-item var(--mx-d3) var(--mx-ease) both}
.mx-anim-fade-row{animation:mx-fade-row var(--mx-d3) var(--mx-ease) both}
.mx-anim-bar-grow{
transform-origin:bottom;
animation:mx-bar-grow var(--mx-d4) var(--mx-ease) both;
}
/* ── Stagger delays ── */
.mx-delay-0{animation-delay:0ms}
.mx-delay-1{animation-delay:50ms}
.mx-delay-2{animation-delay:100ms}
.mx-delay-3{animation-delay:150ms}
.mx-delay-4{animation-delay:200ms}
.mx-delay-5{animation-delay:250ms}
.mx-delay-6{animation-delay:300ms}
.mx-delay-7{animation-delay:350ms}
.mx-delay-8{animation-delay:400ms}
/* ── Skeleton loading — dual-layer overlay ── */
.mx-skeleton{
background:
linear-gradient(90deg, transparent 25%, rgba(255,255,255,0.06) 50%, transparent 75%),
var(--mx-s3);
background-size:200% 100%, 100% 100%;
animation:mx-shimmer 1.5s ease-in-out infinite;
border-radius:var(--mx-r-sm);
}
+50
View File
@@ -0,0 +1,50 @@
/* ═══════════════════════════════════════════
MIUIX CONSOLE — Base Reset & Globals
═══════════════════════════════════════════ */
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
html{font-size:14px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
body{
font-family:var(--mx-font);
background:var(--mx-bg);
color:var(--mx-text);
overflow-x:hidden;
min-height:100dvh;
}
button,input,textarea,select{font-family:inherit;border:none;outline:none;background:none}
ul,ol{list-style:none}
a{text-decoration:none;color:inherit}
img{display:block;max-width:100%}
/* Smooth scroll */
html{scroll-behavior:smooth}
/* Selection */
::selection{background:var(--mx-primary-glow);color:var(--mx-text)}
/* Scrollbar — Miuix thin style, auto-hide */
::-webkit-scrollbar{width:4px;height:4px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--mx-s4);border-radius:2px;opacity:0;transition:opacity 0.3s}
::-webkit-scrollbar-thumb:hover{background:var(--mx-t3)}
body:hover ::-webkit-scrollbar-thumb{opacity:1}
/* Firefox scrollbar auto-hide */
*{scrollbar-color:transparent transparent}
body:hover *{scrollbar-color:var(--mx-s4) transparent}
/* Prevent selection on interactive */
.no-select{-webkit-user-select:none;user-select:none}
/* ═══ DARK MODE INNER GLOW — Miuix signature depth ═══ */
[data-theme="dark"] .mx-card,
[data-theme="dark"] .mx-stat{
box-shadow:var(--mx-sh1),inset 0 1px 0 rgba(255,255,255,0.04);
}
/* ═══ prefers-reduced-motion — kill all animation ═══ */
@media(prefers-reduced-motion:reduce){
*,*::before,*::after{
animation-duration:0.01ms !important;
transition-duration:0.01ms !important;
}
}
+230
View File
@@ -0,0 +1,230 @@
/* ═══════════════════════════════════════════
MIUIX CONSOLE — Liquid Glass Effect v2
液体玻璃效果系统(完整版)
通过 [data-glass="liquid"] 属性启用
═══════════════════════════════════════════ */
/* ── Glass Variables ── */
:root {
--mx-glass-blur: 12px;
--mx-glass-saturation: 180%;
--mx-glass-displacement: 25;
--mx-glass-aberration: 2;
--mx-glass-elasticity: 0.15;
--mx-glass-corner-radius: 16px;
--mx-glass-activation-zone: 200;
--mx-glass-bg-light: rgba(255, 255, 255, 0.25);
--mx-glass-bg-dark: rgba(0, 0, 0, 0.35);
--mx-glass-border-light: rgba(255, 255, 255, 0.2);
--mx-glass-border-dark: rgba(255, 255, 255, 0.08);
--mx-glass-mouse-x: 0;
--mx-glass-mouse-y: 0;
}
/* ═══════════════════════════════════════════
DARK MODE (default)
═══════════════════════════════════════════ */
/* ── TopBar ── */
[data-glass="liquid"] .mx-topbar {
background: rgba(22, 22, 22, 0.45);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border-bottom: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Sidebar ── */
[data-glass="liquid"] .mx-sidebar {
background: rgba(22, 22, 22, 0.45);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border-right: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Bottom Nav ── */
[data-glass="liquid"] .mx-bottom-nav {
background: rgba(22, 22, 22, 0.45);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border-top: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Modal ── */
[data-glass="liquid"] .mx-modal {
background: rgba(30, 30, 30, 0.5);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Drawer ── */
[data-glass="liquid"] .mx-drawer {
background: rgba(22, 22, 22, 0.5);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border-left: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Popover ── */
[data-glass="liquid"] .mx-popover {
background: rgba(30, 30, 30, 0.5);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Select Dropdown ── */
[data-glass="liquid"] .mx-select-dropdown {
background: rgba(30, 30, 30, 0.5);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ── Card (opt-in via .mx-card-glass) ── */
[data-glass="liquid"] .mx-card-glass {
background: rgba(30, 30, 30, 0.4);
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
border: 1px solid var(--mx-glass-border-dark);
filter: url(#mx-glass-filter);
}
/* ═══════════════════════════════════════════
LIGHT MODE
═══════════════════════════════════════════ */
[data-theme="light"][data-glass="liquid"] .mx-topbar {
background: rgba(255, 255, 255, 0.45);
border-bottom: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-sidebar {
background: rgba(255, 255, 255, 0.45);
border-right: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-bottom-nav {
background: rgba(255, 255, 255, 0.45);
border-top: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-modal {
background: rgba(255, 255, 255, 0.5);
border: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-drawer {
background: rgba(255, 255, 255, 0.5);
border-left: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-popover {
background: rgba(255, 255, 255, 0.5);
border: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-select-dropdown {
background: rgba(255, 255, 255, 0.5);
border: 1px solid var(--mx-glass-border-light);
}
[data-theme="light"][data-glass="liquid"] .mx-card-glass {
background: rgba(255, 255, 255, 0.4);
border: 1px solid var(--mx-glass-border-light);
}
/* ═══════════════════════════════════════════
OVER-LIGHT 模式
亮色背景上使用的深色玻璃
═══════════════════════════════════════════ */
[data-glass="liquid"][data-glass-over-light="true"] .mx-topbar,
[data-glass="liquid"][data-glass-over-light="true"] .mx-sidebar,
[data-glass="liquid"][data-glass-over-light="true"] .mx-bottom-nav,
[data-glass="liquid"][data-glass-over-light="true"] .mx-modal,
[data-glass="liquid"][data-glass-over-light="true"] .mx-drawer,
[data-glass="liquid"][data-glass-over-light="true"] .mx-popover,
[data-glass="liquid"][data-glass-over-light="true"] .mx-select-dropdown,
[data-glass="liquid"][data-glass-over-light="true"] .mx-card-glass {
background: rgba(0, 0, 0, 0.45);
border-color: rgba(255, 255, 255, 0.1);
}
/* ═══════════════════════════════════════════
GLASS 可追踪元素
鼠标跟踪 + 弹性变换 + 双层边框
═══════════════════════════════════════════ */
.mx-glass-trackable {
position: relative;
transition: transform 0.2s ease-out;
will-change: transform;
}
.mx-glass-trackable .mx-glass-border-layer {
position: absolute;
inset: 0;
pointer-events: none;
border-radius: inherit;
z-index: 2;
}
/* Hover 高光层 */
.mx-glass-trackable::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease-out;
background-image: radial-gradient(circle at 50% 0%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 50%);
mix-blend-mode: overlay;
z-index: 3;
}
.mx-glass-trackable:hover::after {
opacity: 0.5;
}
.mx-glass-trackable:active::after {
opacity: 0.8;
background-image: radial-gradient(circle at 50% 0%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 80%);
}
/* ═══════════════════════════════════════════
FALLBACK — browsers without SVG filter support
═══════════════════════════════════════════ */
@supports not (filter: url(#mx-glass-filter)) {
[data-glass="liquid"] .mx-topbar,
[data-glass="liquid"] .mx-sidebar,
[data-glass="liquid"] .mx-bottom-nav,
[data-glass="liquid"] .mx-modal,
[data-glass="liquid"] .mx-drawer,
[data-glass="liquid"] .mx-popover,
[data-glass="liquid"] .mx-select-dropdown,
[data-glass="liquid"] .mx-card-glass {
filter: none;
}
}
/* ═══════════════════════════════════════════
REDUCED MOTION
═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.mx-glass-trackable {
transition: none !important;
transform: none !important;
}
.mx-glass-trackable::after {
transition: none !important;
}
}
+198
View File
@@ -0,0 +1,198 @@
/* ═══════════════════════════════════════════
MIUIX CONSOLE — Design Tokens
直接从 Miuix Colors.kt lightColorScheme() / darkColorScheme() 移植
═══════════════════════════════════════════ */
:root {
/* ── Primary — from Miuix lightColorScheme primary = Color(0xFF3482FF) ── */
--mx-primary: #3482FF;
--mx-primary-hover: #5D9BFF;
--mx-primary-active: #277AF7;
--mx-primary-on: #FFFFFF;
--mx-primary-glow: rgba(52,130,255,0.12);
--mx-primary-container: #5D9BFF;
--mx-primary-container-on: #FFFFFF;
--mx-primary-variant: #3482FF;
--mx-primary-variant-on: #AECDFF;
--mx-tertiary-container: #EAF2FF;
--mx-tertiary-container-on: #3482FF;
/* ── Error — from Miuix error = Color(0xFFE94634) ── */
--mx-error: #E94634;
--mx-error-on: #FFFFFF;
--mx-error-container: #FDF6F4;
--mx-error-container-on: #410002;
/* ── Semantic ── */
--mx-green: #34D399;
--mx-amber: #FBBF24;
--mx-blue: #60A5FA;
/* ── Surface — from Miuix lightColorScheme() 源码 ── */
--mx-bg: #FFFFFF; /* background = White */
--mx-surface: #F7F7F7; /* surface = 0xFFF7F7F7 */
--mx-surface-variant: #FFFFFF; /* surfaceVariant = White */
--mx-s1: #F7F7F7; /* surface */
--mx-s2: #FFFFFF; /* surfaceContainer = White */
--mx-s3: #E8E8E8; /* surfaceContainerHigh = 0xFFE8E8E8 */
--mx-s4: #E8E8E8; /* surfaceContainerHighest = 0xFFE8E8E8 */
--mx-s-hover: rgba(0,0,0,0.04);
--mx-s-active: rgba(0,0,0,0.07);
/* ── Text — from Miuix 源码 ── */
--mx-text: #000000; /* onSurface = Black */
--mx-text-on-surface: rgba(0,0,0,0.8); /* onSurfaceSecondary = 0xCC000000 */
--mx-text-variant: rgba(0,0,0,0.6); /* onSurfaceVariantSummary = 0x99000000 */
--mx-text-actions: rgba(0,0,0,0.4); /* onSurfaceVariantActions = 0x66000000 */
--mx-t2: rgba(0,0,0,0.6);
--mx-t3: rgba(0,0,0,0.4);
--mx-text-bg-variant: #8C93B0; /* onBackgroundVariant */
--mx-text-container-variant: #959595; /* onSurfaceContainerVariant */
--mx-text-container-high: #A2A2A2; /* onSurfaceContainerHigh */
--mx-text-disabled: #B2B2B2; /* disabledOnSurface */
/* ── Secondary — from Miuix 源码 ── */
--mx-secondary: #E6E6E6; /* secondary */
--mx-secondary-variant: #F0F0F0; /* secondaryVariant */
--mx-secondary-container: #F0F0F0;
--mx-secondary-container-on: #A9A9A9;
/* ── Border / Divider — from Miuix 源码 ── */
--mx-border: #D9D9D9; /* outline = 0xFFD9D9D9 */
--mx-divider: #E0E0E0; /* dividerLine = 0xFFE0E0E0 */
/* ── Disabled — from Miuix 源码 ── */
--mx-disabled-primary: #C2D9FF;
--mx-disabled-primary-on: #F3F8FF;
--mx-disabled-secondary: #F0F0F0;
--mx-disabled-secondary-on: #FCFCFC;
/* ── Window ── */
--mx-window-dim: rgba(0,0,0,0.3); /* windowDimming */
/* ── Slider — from Miuix 源码 ── */
--mx-slider-bg: rgba(0,0,0,0.06); /* 0x0F000000 */
--mx-slider-key: rgba(163,179,205,0.3);
--mx-slider-key-fg: #6EB5FF;
/* ── Radius (Miuix Smooth Corner — 16dp default) ── */
--mx-r: 16px;
--mx-r-sm: 12px;
--mx-r-xs: 8px;
--mx-r-pill: 9999px;
/* ── Shadow (Miuix multi-layer soft shadow) ── */
--mx-sh1: 0 1px 4px rgba(0,0,0,0.08);
--mx-sh2: 0 4px 16px rgba(0,0,0,0.06);
--mx-sh3: 0 8px 32px rgba(0,0,0,0.08);
--mx-glow: 0 0 0 1px rgba(52,130,255,0.06), 0 2px 12px rgba(52,130,255,0.04);
/* ── Motion (Miuix spring + ease) ── */
--mx-ease: cubic-bezier(0.16, 1, 0.3, 1);
--mx-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--mx-d1: 100ms;
--mx-d2: 200ms;
--mx-d3: 320ms;
--mx-d4: 500ms;
/* ── Typography ── */
--mx-font: "MiSans", "Mi Sans", -apple-system, "PingFang SC", "Noto Sans SC", sans-serif;
--mx-mono: "JetBrains Mono", "SF Mono", monospace;
/* Typography scale */
--mx-text-xs: 11px;
--mx-text-sm: 12px;
--mx-text-base: 13px;
--mx-text-md: 14px;
--mx-text-lg: 15px;
--mx-text-xl: 16px;
--mx-text-2xl: 20px;
--mx-text-3xl: 24px;
/* ── Safe area ── */
--mx-safe-t: env(safe-area-inset-top, 0px);
--mx-safe-b: env(safe-area-inset-bottom, 0px);
}
/* ═══════════════════════════════════════════
DARK MODE — from Miuix darkColorScheme() 源码
═══════════════════════════════════════════ */
[data-theme="dark"] {
/* Primary — darkColorScheme primary = Color(0xFF277AF7) */
--mx-primary: #277AF7;
--mx-primary-hover: #338FE4;
--mx-primary-active: #0073DD;
--mx-primary-on: #FFFFFF;
--mx-primary-glow: rgba(39,122,247,0.15);
--mx-primary-container: #338FE4;
--mx-primary-container-on: #FFFFFF;
--mx-primary-variant: #0073DD;
--mx-primary-variant-on: #99C7F1;
--mx-tertiary-container: #2B3B54;
--mx-tertiary-container-on: #4788FF;
/* Error — darkColorScheme error = Color(0xFFF12522) */
--mx-error: #F12522;
--mx-error-on: #FFFFFF;
--mx-error-container: #2E0603;
--mx-error-container-on: #FFDAD6;
/* Surface — 5-level gradient with 3-5% brightness steps */
--mx-bg: #161616; /* 页面背景 — 最底层 */
--mx-surface: #0C0C0C; /* surface = s1 */
--mx-surface-variant: #1C1C1C; /* surfaceVariant = s2 */
--mx-s1: #0C0C0C; /* 导航栏、侧边栏 — 比 bg 深 */
--mx-s2: #1C1C1C; /* 卡片 — 比 bg 浅 */
--mx-s3: #242424; /* 输入框、浮层 — 比 s2 浅 */
--mx-s4: #2C2C2C; /* 下拉菜单 — 最亮 */
--mx-s-hover: rgba(255,255,255,0.04);
--mx-s-active: rgba(255,255,255,0.07);
/* Text — from Miuix darkColorScheme() 源码 */
--mx-text: #F2F2F2; /* onSurface = 0xFFF2F2F2 */
--mx-text-on-surface: rgba(255,255,255,0.8); /* 0xCCFFFFFF */
--mx-text-variant: rgba(255,255,255,0.5); /* 0x80FFFFFF */
--mx-text-actions: rgba(255,255,255,0.4); /* 0x66FFFFFF */
--mx-t2: rgba(255,255,255,0.6);
--mx-t3: rgba(255,255,255,0.4);
--mx-text-bg-variant: #787E96;
--mx-text-container-variant: #737373;
--mx-text-container-high: #666666;
--mx-text-disabled: #666666;
/* Secondary — from Miuix darkColorScheme() 源码 */
--mx-secondary: #505050;
--mx-secondary-variant: #434343;
--mx-secondary-container: #434343;
--mx-secondary-container-on: #7C7C7C;
/* Border / Divider — 提升对比度 */
--mx-border: #484848; /* outline = 提升到可见 */
--mx-divider: #404040; /* dividerLine = 提升到可见 */
/* Disabled */
--mx-disabled-primary: #253E64;
--mx-disabled-primary-on: #677993;
--mx-disabled-secondary: #3F3F3F;
--mx-disabled-secondary-on: #797979;
/* Window */
--mx-window-dim: rgba(0,0,0,0.6);
/* Slider */
--mx-slider-bg: rgba(255,255,255,0.15);
--mx-slider-key: rgba(122,138,166,0.3);
--mx-slider-key-fg: #5DAAFF;
/* Shadow — dark mode 阴影更重 */
--mx-sh1: 0 1px 4px rgba(0,0,0,0.5);
--mx-sh2: 0 4px 16px rgba(0,0,0,0.4);
--mx-sh3: 0 8px 32px rgba(0,0,0,0.45);
--mx-glow: 0 0 0 1px rgba(39,122,247,0.08), 0 2px 12px rgba(39,122,247,0.06);
}
/* ═══ COMPACT DENSITY ═══ */
[data-density="compact"] {
--mx-r: 14px;
--mx-r-sm: 10px;
}