调整dashboard项目结构
This commit is contained in:
+5
-5
@@ -12,10 +12,10 @@ import {
|
||||
type DashboardOverview,
|
||||
type DashboardRange,
|
||||
} from "@/lib/api/dashboard"
|
||||
import { SummaryCards } from "./_components/summary-cards"
|
||||
import { TrendPanel } from "./_components/trend-panel"
|
||||
import { TeamLoadPanel } from "./_components/team-load-panel"
|
||||
import { AlertList } from "./_components/alert-list"
|
||||
import { SummaryCards } from "./summary-cards"
|
||||
import { TrendPanel } from "./trend-panel"
|
||||
import { TeamLoadPanel } from "./team-load-panel"
|
||||
import { AlertList } from "./alert-list"
|
||||
|
||||
const rangeOptions: Array<{ value: DashboardRange; label: string }> = [
|
||||
{ value: "today", label: "今天" },
|
||||
@@ -39,7 +39,7 @@ function LoadingCards() {
|
||||
)
|
||||
}
|
||||
|
||||
export default function DashboardPage() {
|
||||
export function DashboardHome() {
|
||||
const [range, setRange] = useState<DashboardRange>("7d")
|
||||
const [data, setData] = useState<DashboardOverview | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -0,0 +1,5 @@
|
||||
import { DashboardHome } from "./_components/dashboard-home"
|
||||
|
||||
export default function DashboardHomePage() {
|
||||
return <DashboardHome />
|
||||
}
|
||||
+1
-1
@@ -236,7 +236,7 @@ export default function TicketRiskPage() {
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Link href="/tickets">
|
||||
<Link href="/dashboard/tickets">
|
||||
<Button variant="outline">前往工单工作台</Button>
|
||||
</Link>
|
||||
<Button variant="outline" onClick={() => void loadData()} disabled={loading}>
|
||||
+1
-1
@@ -224,7 +224,7 @@ export function TicketStatusDialog({
|
||||
<div className="mt-2 rounded-lg border border-amber-200 bg-amber-50/70 p-3 text-xs text-amber-900">
|
||||
当前没有可用解决码,解决结果无法标准化统计。
|
||||
<Link
|
||||
href="/ticket-resolution-codes"
|
||||
href="/dashboard/ticket-resolution-codes"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ml-1 font-medium underline underline-offset-4"
|
||||
+2
-2
@@ -810,7 +810,7 @@ export default function TicketDetailPage() {
|
||||
当前工单未生成 SLA 记录,请检查工单 SLA
|
||||
配置;如果系统仍在使用默认策略,也需要确认配置是否已补齐。
|
||||
<Link
|
||||
href="/ticket-priorities"
|
||||
href="/dashboard/ticket-priorities"
|
||||
className="ml-1 font-medium underline underline-offset-4"
|
||||
>
|
||||
前往配置优先级
|
||||
@@ -912,7 +912,7 @@ export default function TicketDetailPage() {
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={() => router.push("/conversations")}
|
||||
onClick={() => router.push("/dashboard/conversations")}
|
||||
>
|
||||
<RotateCcwIcon className="size-4" />
|
||||
前往会话工作台
|
||||
@@ -27,7 +27,7 @@ function WxWorkLoginCallbackContent() {
|
||||
|
||||
const ticket = searchParams.get("ticket")?.trim() ?? ""
|
||||
const next = searchParams.get("next")
|
||||
const nextPath = next && next.startsWith("/") ? next : "/"
|
||||
const nextPath = next && next.startsWith("/") ? next : "/dashboard"
|
||||
|
||||
if (!ticket) {
|
||||
toast.error("企业微信登录票据不存在")
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import Link from "next/link"
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="flex min-h-svh items-center justify-center bg-[linear-gradient(145deg,#fff7ed_0%,#ffffff_38%,#ecfeff_100%)] px-6 py-16">
|
||||
<div className="w-full max-w-3xl rounded-[32px] border border-white/70 bg-white/90 p-10 shadow-[0_24px_80px_rgba(15,23,42,0.08)] backdrop-blur">
|
||||
<div className="inline-flex rounded-full border border-amber-200 bg-amber-50 px-3 py-1 text-xs font-medium tracking-[0.18em] text-amber-900 uppercase">
|
||||
Landing Page
|
||||
</div>
|
||||
<h1 className="mt-6 text-4xl font-semibold tracking-tight text-foreground">TODO</h1>
|
||||
<p className="mt-4 max-w-2xl text-sm leading-6 text-muted-foreground">
|
||||
这里先放一个简单的首页占位,后续可以再补充正式内容与导航信息。
|
||||
</p>
|
||||
<div className="mt-8 flex flex-wrap gap-3">
|
||||
<Link href="/dashboard">
|
||||
进入控制台
|
||||
</Link>
|
||||
<Link href="/login">
|
||||
登录后台
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export function AppSidebar({ ...props }: ComponentProps<typeof Sidebar>) {
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
className="data-[slot=sidebar-menu-button]:p-1.5!"
|
||||
render={<Link href="/" />}
|
||||
render={<Link href="/dashboard" />}
|
||||
>
|
||||
<BotMessageSquareIcon className="size-5!" />
|
||||
<span className="text-base font-semibold">贝壳AGENT</span>
|
||||
|
||||
@@ -33,6 +33,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const router = useRouter()
|
||||
const [session, setSession] = useState<AuthSession | null>(null)
|
||||
const [ready, setReady] = useState(false)
|
||||
const requiresAuth = pathname?.startsWith("/dashboard") ?? false
|
||||
|
||||
const refreshProfile = useCallback(async () => {
|
||||
const stored = readSession()
|
||||
@@ -55,7 +56,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
} catch {
|
||||
clearSession()
|
||||
setSession(null)
|
||||
if (pathname && !pathname.startsWith("/login")) {
|
||||
if (requiresAuth) {
|
||||
startTransition(() => {
|
||||
router.replace("/login")
|
||||
})
|
||||
@@ -63,7 +64,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
} finally {
|
||||
setReady(true)
|
||||
}
|
||||
}, [pathname, router])
|
||||
}, [requiresAuth, router])
|
||||
|
||||
async function signOut() {
|
||||
const current = readSession()
|
||||
@@ -83,12 +84,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
|
||||
setReady(true)
|
||||
if (pathname && !pathname.startsWith("/login")) {
|
||||
if (requiresAuth) {
|
||||
startTransition(() => {
|
||||
router.replace("/login")
|
||||
})
|
||||
}
|
||||
}, [pathname, refreshProfile, router])
|
||||
}, [requiresAuth, refreshProfile, router])
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ session, ready, refreshProfile, signOut }}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useMemo, useState } from "react"
|
||||
import { ChevronsUpDownIcon, PlusIcon } from "lucide-react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { EditDialog as CompanyEditDialog } from "@/app/(dashboard)/companies/_components/edit"
|
||||
import { EditDialog as CompanyEditDialog } from "@/app/dashboard/companies/_components/edit"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
|
||||
@@ -36,7 +36,7 @@ export function LoginForm({
|
||||
const nextPath = searchParams.get("next")
|
||||
const wxworkError = searchParams.get("wxworkError")
|
||||
const redirectPath =
|
||||
nextPath && nextPath.startsWith("/") ? nextPath : "/"
|
||||
nextPath && nextPath.startsWith("/") ? nextPath : "/dashboard"
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
|
||||
@@ -98,42 +98,42 @@ export const dashboardNavSections: DashboardNavSectionConfig[] = [
|
||||
items: [
|
||||
{
|
||||
title: "总览",
|
||||
url: "/",
|
||||
url: "/dashboard",
|
||||
icon: <LayoutDashboardIcon />,
|
||||
},
|
||||
{
|
||||
title: "会话",
|
||||
url: "/conversations",
|
||||
url: "/dashboard/conversations",
|
||||
icon: <BotMessageSquareIcon />,
|
||||
requiredPermission: "conversation.view",
|
||||
},
|
||||
{
|
||||
title: "工单",
|
||||
url: "/tickets",
|
||||
url: "/dashboard/tickets",
|
||||
icon: <FileTextIcon />,
|
||||
requiredPermission: "ticket.view",
|
||||
},
|
||||
{
|
||||
title: "会话监控",
|
||||
url: "/conversation-monitor",
|
||||
url: "/dashboard/conversation-monitor",
|
||||
icon: <BotMessageSquareIcon />,
|
||||
requiredPermission: "conversation.view",
|
||||
},
|
||||
{
|
||||
title: "SLA风险",
|
||||
url: "/ticket-risk",
|
||||
url: "/dashboard/ticket-risk",
|
||||
icon: <ChartColumnIncreasingIcon />,
|
||||
requiredPermission: "ticket.view",
|
||||
},
|
||||
{
|
||||
title: "客户管理",
|
||||
url: "/customers",
|
||||
url: "/dashboard/customers",
|
||||
icon: <UsersIcon />,
|
||||
requiredPermission: "customer.view",
|
||||
},
|
||||
{
|
||||
title: "公司管理",
|
||||
url: "/companies",
|
||||
url: "/dashboard/companies",
|
||||
icon: <Building2Icon />,
|
||||
requiredPermission: "company.view",
|
||||
},
|
||||
@@ -144,43 +144,43 @@ export const dashboardNavSections: DashboardNavSectionConfig[] = [
|
||||
items: [
|
||||
{
|
||||
title: "分类标签",
|
||||
url: "/tags",
|
||||
url: "/dashboard/tags",
|
||||
icon: <TagsIcon />,
|
||||
requiredPermission: "tag.view",
|
||||
},
|
||||
{
|
||||
title: "快捷回复",
|
||||
url: "/quick-replies",
|
||||
url: "/dashboard/quick-replies",
|
||||
icon: <MessageSquareMoreIcon />,
|
||||
requiredPermission: "quickReply.view",
|
||||
},
|
||||
{
|
||||
title: "工单优先级",
|
||||
url: "/ticket-priorities",
|
||||
url: "/dashboard/ticket-priorities",
|
||||
icon: <Settings2Icon />,
|
||||
requiredPermission: "ticketPriorityConfig.view",
|
||||
},
|
||||
{
|
||||
title: "工单解决码",
|
||||
url: "/ticket-resolution-codes",
|
||||
url: "/dashboard/ticket-resolution-codes",
|
||||
icon: <KeyRoundIcon />,
|
||||
requiredPermission: "ticketResolutionCode.view",
|
||||
},
|
||||
{
|
||||
title: "客服档案",
|
||||
url: "/agents",
|
||||
url: "/dashboard/agents",
|
||||
icon: <UserCogIcon />,
|
||||
requiredPermission: "agent.view",
|
||||
},
|
||||
{
|
||||
title: "客服组排班",
|
||||
url: "/agent-team-schedules",
|
||||
url: "/dashboard/agent-team-schedules",
|
||||
icon: <CalendarClockIcon />,
|
||||
requiredPermission: "agentTeamSchedule.view",
|
||||
},
|
||||
{
|
||||
title: "接入渠道",
|
||||
url: "/channels",
|
||||
url: "/dashboard/channels",
|
||||
icon: <GlobeIcon />,
|
||||
requiredPermission: "channel.view",
|
||||
},
|
||||
@@ -191,37 +191,37 @@ export const dashboardNavSections: DashboardNavSectionConfig[] = [
|
||||
items: [
|
||||
{
|
||||
title: "知识库",
|
||||
url: "/knowledge",
|
||||
url: "/dashboard/knowledge",
|
||||
icon: <FileTextIcon />,
|
||||
requiredPermission: "knowledgeBase.view",
|
||||
},
|
||||
{
|
||||
title: "AI配置",
|
||||
url: "/ai-configs",
|
||||
url: "/dashboard/ai-configs",
|
||||
icon: <BrainCircuitIcon />,
|
||||
requiredPermission: "aiConfig.view",
|
||||
},
|
||||
{
|
||||
title: "AI Agent",
|
||||
url: "/ai-agents",
|
||||
url: "/dashboard/ai-agents",
|
||||
icon: <MessageSquareMoreIcon />,
|
||||
requiredPermission: "aiAgent.view",
|
||||
},
|
||||
{
|
||||
title: "Skills",
|
||||
url: "/skill-definition",
|
||||
url: "/dashboard/skill-definition",
|
||||
icon: <MessageSquareCodeIcon />,
|
||||
requiredPermission: "skillDefinition.view",
|
||||
},
|
||||
{
|
||||
title: "MCP调试",
|
||||
url: "/mcp",
|
||||
url: "/dashboard/mcp",
|
||||
icon: <MessageSquareCodeIcon />,
|
||||
requiredPermission: "mcp.view",
|
||||
},
|
||||
{
|
||||
title: "Agent日志",
|
||||
url: "/agent-run-logs",
|
||||
url: "/dashboard/agent-run-logs",
|
||||
icon: <ActivitySquareIcon />,
|
||||
requiredPermission: "conversation.view",
|
||||
},
|
||||
@@ -232,19 +232,19 @@ export const dashboardNavSections: DashboardNavSectionConfig[] = [
|
||||
items: [
|
||||
{
|
||||
title: "用户管理",
|
||||
url: "/users",
|
||||
url: "/dashboard/users",
|
||||
icon: <UsersIcon />,
|
||||
requiredPermission: "user.view",
|
||||
},
|
||||
{
|
||||
title: "角色管理",
|
||||
url: "/roles",
|
||||
url: "/dashboard/roles",
|
||||
icon: <ShieldCheckIcon />,
|
||||
requiredPermission: "role.view",
|
||||
},
|
||||
{
|
||||
title: "权限管理",
|
||||
url: "/permissions",
|
||||
url: "/dashboard/permissions",
|
||||
icon: <KeyRoundIcon />,
|
||||
requiredPermission: "permission.view",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user