完善skills;测试用例生成页面功能初步实现
This commit is contained in:
@@ -1,29 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Book,
|
||||
ChevronRight,
|
||||
FileText,
|
||||
MessageSquare,
|
||||
LogOut,
|
||||
Menu,
|
||||
MessageSquare,
|
||||
Search,
|
||||
User,
|
||||
} from "lucide-react";
|
||||
import Breadcrumb from "@/components/ui/breadcrumb";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type NavigationChild = {
|
||||
name: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
type NavigationItem = {
|
||||
name: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
href?: string;
|
||||
children?: Array<{
|
||||
name: string;
|
||||
href: string;
|
||||
}>;
|
||||
children?: NavigationChild[];
|
||||
defaultOpen?: boolean;
|
||||
};
|
||||
|
||||
export default function DashboardLayout({
|
||||
@@ -34,9 +37,10 @@ export default function DashboardLayout({
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [isDocProcessingOpen, setIsDocProcessingOpen] = useState(
|
||||
pathname.startsWith("/dashboard/doc-processing")
|
||||
);
|
||||
const [openGroups, setOpenGroups] = useState<Record<string, boolean>>({
|
||||
knowledge: pathname.startsWith("/dashboard/knowledge"),
|
||||
"doc-processing": pathname.startsWith("/dashboard/doc-processing"),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("token");
|
||||
@@ -51,13 +55,31 @@ export default function DashboardLayout({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (pathname.startsWith("/dashboard/knowledge")) {
|
||||
setOpenGroups((prev) => ({ ...prev, knowledge: true }));
|
||||
}
|
||||
if (pathname.startsWith("/dashboard/doc-processing")) {
|
||||
setIsDocProcessingOpen(true);
|
||||
setOpenGroups((prev) => ({ ...prev, "doc-processing": true }));
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
const toggleGroup = (key: string) => {
|
||||
setOpenGroups((prev) => ({
|
||||
...prev,
|
||||
[key]: !prev[key],
|
||||
}));
|
||||
};
|
||||
|
||||
const navigation: NavigationItem[] = [
|
||||
{ name: "知识库", href: "/dashboard/knowledge", icon: Book },
|
||||
{
|
||||
name: "知识库",
|
||||
icon: Book,
|
||||
defaultOpen: true,
|
||||
children: [
|
||||
{ name: "文档知识库", href: "/dashboard/knowledge/document" },
|
||||
{ name: "代码知识库", href: "/dashboard/knowledge/code" },
|
||||
],
|
||||
},
|
||||
{ name: "对话", href: "/dashboard/chat", icon: MessageSquare },
|
||||
{
|
||||
name: "文档处理",
|
||||
@@ -80,42 +102,39 @@ export default function DashboardLayout({
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Mobile menu button */}
|
||||
<div className="lg:hidden fixed top-0 left-0 m-4 z-50">
|
||||
<div className="fixed left-0 top-0 z-50 m-4 lg:hidden">
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
className="p-2 rounded-md bg-primary text-primary-foreground"
|
||||
className="rounded-md bg-primary p-2 text-primary-foreground"
|
||||
>
|
||||
<Menu className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div
|
||||
className={`fixed inset-y-0 left-0 z-40 w-64 transform bg-card border-r transition-transform duration-200 ease-in-out lg:translate-x-0 ${
|
||||
className={`fixed inset-y-0 left-0 z-40 w-64 transform border-r bg-card transition-transform duration-200 ease-in-out lg:translate-x-0 ${
|
||||
isMobileMenuOpen ? "translate-x-0" : "-translate-x-full"
|
||||
}`}
|
||||
>
|
||||
<div className="flex h-full flex-col">
|
||||
{/* Sidebar header */}
|
||||
<div className="flex h-16 items-center border-b pl-8">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className="flex items-center text-lg font-semibold hover:text-primary transition-colors"
|
||||
className="flex items-center text-lg font-semibold transition-colors hover:text-primary"
|
||||
>
|
||||
<img
|
||||
src="/logo.svg"
|
||||
alt="标志"
|
||||
className="w-16 h-16 rounded-lg"
|
||||
/>
|
||||
<img src="/logo.svg" alt="标志" className="h-16 w-16 rounded-lg" />
|
||||
RAG 知识助手
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 space-y-2 px-4 py-6">
|
||||
{navigation.map((item) => {
|
||||
if (item.children) {
|
||||
const groupKey =
|
||||
item.children[0]?.href.split("/")[2] === "knowledge"
|
||||
? "knowledge"
|
||||
: "doc-processing";
|
||||
const isOpen = openGroups[groupKey] ?? item.defaultOpen ?? false;
|
||||
const hasActiveChild = item.children.some((child) =>
|
||||
pathname.startsWith(child.href)
|
||||
);
|
||||
@@ -124,7 +143,7 @@ export default function DashboardLayout({
|
||||
<div key={item.name} className="space-y-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsDocProcessingOpen((prev) => !prev)}
|
||||
onClick={() => toggleGroup(groupKey)}
|
||||
className={cn(
|
||||
"group flex w-full items-center rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200",
|
||||
hasActiveChild
|
||||
@@ -136,7 +155,7 @@ export default function DashboardLayout({
|
||||
className={cn(
|
||||
"mr-3 h-5 w-5 transition-transform duration-200",
|
||||
hasActiveChild
|
||||
? "text-primary scale-110"
|
||||
? "scale-110 text-primary"
|
||||
: "group-hover:scale-110"
|
||||
)}
|
||||
/>
|
||||
@@ -144,12 +163,12 @@ export default function DashboardLayout({
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"ml-auto h-4 w-4 transition-transform duration-200",
|
||||
isDocProcessingOpen ? "rotate-90" : ""
|
||||
isOpen && "rotate-90"
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{isDocProcessingOpen && (
|
||||
{isOpen && (
|
||||
<div className="ml-7 space-y-1 border-l pl-3">
|
||||
{item.children.map((child) => {
|
||||
const isChildActive = pathname.startsWith(child.href);
|
||||
@@ -188,18 +207,20 @@ export default function DashboardLayout({
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href || "/dashboard"}
|
||||
className={`group flex items-center rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200 ${
|
||||
className={cn(
|
||||
"group flex items-center rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200",
|
||||
isActive
|
||||
? "bg-gradient-to-r from-primary/10 to-primary/5 text-primary shadow-sm"
|
||||
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground hover:shadow-sm"
|
||||
}`}
|
||||
)}
|
||||
>
|
||||
<item.icon
|
||||
className={`mr-3 h-5 w-5 transition-transform duration-200 ${
|
||||
className={cn(
|
||||
"mr-3 h-5 w-5 transition-transform duration-200",
|
||||
isActive
|
||||
? "text-primary scale-110"
|
||||
? "scale-110 text-primary"
|
||||
: "group-hover:scale-110"
|
||||
}`}
|
||||
)}
|
||||
/>
|
||||
<span className="font-medium">{item.name}</span>
|
||||
{isActive && (
|
||||
@@ -209,11 +230,11 @@ export default function DashboardLayout({
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
{/* User profile and logout */}
|
||||
<div className="border-t p-4 space-y-4">
|
||||
|
||||
<div className="space-y-4 border-t p-4">
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="flex w-full items-center rounded-lg px-3 py-2.5 text-sm font-medium text-destructive hover:bg-destructive/10 transition-colors duration-200"
|
||||
className="flex w-full items-center rounded-lg px-3 py-2.5 text-sm font-medium text-destructive transition-colors duration-200 hover:bg-destructive/10"
|
||||
>
|
||||
<LogOut className="mr-3 h-4 w-4" />
|
||||
退出登录
|
||||
@@ -222,9 +243,8 @@ export default function DashboardLayout({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<div className="lg:pl-64">
|
||||
<main className="min-h-screen py-6 px-4 sm:px-6 lg:px-8">
|
||||
<main className="min-h-screen px-4 py-6 sm:px-6 lg:px-8">
|
||||
<Breadcrumb />
|
||||
{children}
|
||||
</main>
|
||||
@@ -237,10 +257,15 @@ export const dashboardConfig = {
|
||||
mainNav: [],
|
||||
sidebarNav: [
|
||||
{
|
||||
title: "知识库",
|
||||
href: "/dashboard/knowledge",
|
||||
title: "文档知识库",
|
||||
href: "/dashboard/knowledge/document",
|
||||
icon: "database",
|
||||
},
|
||||
{
|
||||
title: "代码知识库",
|
||||
href: "/dashboard/knowledge/code",
|
||||
icon: "braces",
|
||||
},
|
||||
{
|
||||
title: "对话",
|
||||
href: "/dashboard/chat",
|
||||
|
||||
Reference in New Issue
Block a user