Checkpoint: v2.0完整版本:新增社区排行榜、每日打卡、24种成就徽章、实时摄像头姿势分析、在线录制(稳定压缩流/断线重连/自动剪辑)、移动端全面适配。47个测试通过。包含完整开发文档。
这个提交包含在:
@@ -22,19 +22,23 @@ import {
|
||||
import { useIsMobile } from "@/hooks/useMobile";
|
||||
import {
|
||||
LayoutDashboard, LogOut, PanelLeft, Target, Video,
|
||||
Award, Activity, FileVideo
|
||||
Award, Activity, FileVideo, Trophy, Flame, Camera, CircleDot
|
||||
} from "lucide-react";
|
||||
import { CSSProperties, useEffect, useRef, useState } from "react";
|
||||
import { useLocation, Redirect } from "wouter";
|
||||
import { DashboardLayoutSkeleton } from './DashboardLayoutSkeleton';
|
||||
|
||||
const menuItems = [
|
||||
{ icon: LayoutDashboard, label: "仪表盘", path: "/dashboard" },
|
||||
{ icon: Target, label: "训练计划", path: "/training" },
|
||||
{ icon: Video, label: "视频分析", path: "/analysis" },
|
||||
{ icon: FileVideo, label: "视频库", path: "/videos" },
|
||||
{ icon: Activity, label: "训练进度", path: "/progress" },
|
||||
{ icon: Award, label: "NTRP评分", path: "/rating" },
|
||||
{ icon: LayoutDashboard, label: "仪表盘", path: "/dashboard", group: "main" },
|
||||
{ icon: Target, label: "训练计划", path: "/training", group: "main" },
|
||||
{ icon: Flame, label: "每日打卡", path: "/checkin", group: "main" },
|
||||
{ icon: Camera, label: "实时分析", path: "/live-camera", group: "analysis" },
|
||||
{ icon: CircleDot, label: "在线录制", path: "/recorder", group: "analysis" },
|
||||
{ icon: Video, label: "视频分析", path: "/analysis", group: "analysis" },
|
||||
{ icon: FileVideo, label: "视频库", path: "/videos", group: "analysis" },
|
||||
{ icon: Activity, label: "训练进度", path: "/progress", group: "stats" },
|
||||
{ icon: Award, label: "NTRP评分", path: "/rating", group: "stats" },
|
||||
{ icon: Trophy, label: "排行榜", path: "/leaderboard", group: "stats" },
|
||||
];
|
||||
|
||||
const SIDEBAR_WIDTH_KEY = "sidebar-width";
|
||||
@@ -163,7 +167,8 @@ function DashboardLayoutContent({
|
||||
|
||||
<SidebarContent className="gap-0">
|
||||
<SidebarMenu className="px-2 py-1">
|
||||
{menuItems.map(item => {
|
||||
{/* Main group */}
|
||||
{menuItems.filter(i => i.group === "main").map(item => {
|
||||
const isActive = location === item.path;
|
||||
return (
|
||||
<SidebarMenuItem key={item.path}>
|
||||
@@ -173,9 +178,49 @@ function DashboardLayoutContent({
|
||||
tooltip={item.label}
|
||||
className={`h-10 transition-all font-normal`}
|
||||
>
|
||||
<item.icon
|
||||
className={`h-4 w-4 ${isActive ? "text-primary" : ""}`}
|
||||
/>
|
||||
<item.icon className={`h-4 w-4 ${isActive ? "text-primary" : ""}`} />
|
||||
<span>{item.label}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Divider */}
|
||||
{!isCollapsed && <div className="my-2 mx-2 border-t border-border/50" />}
|
||||
{!isCollapsed && <p className="px-3 text-[10px] font-medium text-muted-foreground uppercase tracking-wider mb-1">分析与录制</p>}
|
||||
|
||||
{menuItems.filter(i => i.group === "analysis").map(item => {
|
||||
const isActive = location === item.path;
|
||||
return (
|
||||
<SidebarMenuItem key={item.path}>
|
||||
<SidebarMenuButton
|
||||
isActive={isActive}
|
||||
onClick={() => setLocation(item.path)}
|
||||
tooltip={item.label}
|
||||
className={`h-10 transition-all font-normal`}
|
||||
>
|
||||
<item.icon className={`h-4 w-4 ${isActive ? "text-primary" : ""}`} />
|
||||
<span>{item.label}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Divider */}
|
||||
{!isCollapsed && <div className="my-2 mx-2 border-t border-border/50" />}
|
||||
{!isCollapsed && <p className="px-3 text-[10px] font-medium text-muted-foreground uppercase tracking-wider mb-1">统计与排名</p>}
|
||||
|
||||
{menuItems.filter(i => i.group === "stats").map(item => {
|
||||
const isActive = location === item.path;
|
||||
return (
|
||||
<SidebarMenuItem key={item.path}>
|
||||
<SidebarMenuButton
|
||||
isActive={isActive}
|
||||
onClick={() => setLocation(item.path)}
|
||||
tooltip={item.label}
|
||||
className={`h-10 transition-all font-normal`}
|
||||
>
|
||||
<item.icon className={`h-4 w-4 ${isActive ? "text-primary" : ""}`} />
|
||||
<span>{item.label}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
|
||||
在新工单中引用
屏蔽一个用户