chore: 以本地为准,上传全部并替换 GitHub
This commit is contained in:
@@ -2,15 +2,15 @@
|
||||
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { LayoutDashboard, Database, Tags, Brain, Monitor } from "lucide-react"
|
||||
import { LayoutDashboard, Database, Tags, Bot, Package } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{ href: "/", label: "概览", icon: LayoutDashboard },
|
||||
{ href: "/data-governance", label: "数据治理", icon: Database },
|
||||
{ href: "/tag-portrait", label: "标签画像", icon: Tags },
|
||||
{ href: "/ai-insight", label: "AI洞察", icon: Brain },
|
||||
{ href: "/monitoring", label: "监控", icon: Monitor },
|
||||
{ href: "/data-ingestion", label: "数据", icon: Database },
|
||||
{ href: "/tag-portrait", label: "画像", icon: Tags },
|
||||
{ href: "/ai-agent", label: "AI", icon: Bot },
|
||||
{ href: "/data-market", label: "市场", icon: Package },
|
||||
] as const
|
||||
|
||||
export default function BottomNav() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { X, LayoutDashboard, Database, Tags, LineChart, Brain, Package, Monitor, ChevronRight } from "lucide-react"
|
||||
import { X, LayoutDashboard, Database, Tags, Bot, Package, ChevronRight } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
@@ -11,13 +11,11 @@ interface MobileSidebarProps {
|
||||
}
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{ href: "/", label: "概览", icon: LayoutDashboard },
|
||||
{ href: "/data-governance", label: "数据治理", icon: Database },
|
||||
{ href: "/tag-portrait", label: "标签画像", icon: Tags },
|
||||
{ href: "/value-model", label: "价值模型", icon: LineChart },
|
||||
{ href: "/ai-insight", label: "AI洞察", icon: Brain },
|
||||
{ href: "/data-asset", label: "数据资产", icon: Package },
|
||||
{ href: "/monitoring", label: "系统监控", icon: Monitor },
|
||||
{ href: "/", label: "数据概览", icon: LayoutDashboard, desc: "AI对话 · 数据仪表板" },
|
||||
{ href: "/data-ingestion", label: "数据接入", icon: Database, desc: "数据源 · 清洗 · 调度" },
|
||||
{ href: "/tag-portrait", label: "标签画像", icon: Tags, desc: "标签 · 画像 · 流量池" },
|
||||
{ href: "/ai-agent", label: "AI Agent", icon: Bot, desc: "智能对话 · 渠道配置" },
|
||||
{ href: "/data-market", label: "数据市场", icon: Package, desc: "API · 流量包" },
|
||||
]
|
||||
|
||||
export default function MobileSidebar({ isOpen, onClose }: MobileSidebarProps) {
|
||||
@@ -40,7 +38,7 @@ export default function MobileSidebar({ isOpen, onClose }: MobileSidebarProps) {
|
||||
<div className="flex items-center justify-between p-4 border-b">
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-gray-900">神射手</h2>
|
||||
<p className="text-xs text-gray-500">私域银行数据中台</p>
|
||||
<p className="text-xs text-gray-500">用户资产数字化平台</p>
|
||||
</div>
|
||||
<button onClick={onClose} aria-label="Close menu" className="rounded p-1 hover:bg-gray-100">
|
||||
<X className="h-5 w-5" />
|
||||
|
||||
@@ -29,18 +29,19 @@ import {
|
||||
Webhook,
|
||||
Activity,
|
||||
ScrollText,
|
||||
Globe,
|
||||
} from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useState } from "react"
|
||||
|
||||
// 按照5个HTML文档重构的导航结构
|
||||
// 五大核心模块导航结构(不可删除)
|
||||
const NAV_ITEMS = [
|
||||
// 第一部分:数据概览
|
||||
{
|
||||
href: "/",
|
||||
label: "数据概览",
|
||||
icon: LayoutDashboard,
|
||||
description: "用户洞察仪表板"
|
||||
description: "AI对话 · 数据仪表板"
|
||||
},
|
||||
// 第二部分:数据接入
|
||||
{
|
||||
@@ -49,10 +50,10 @@ const NAV_ITEMS = [
|
||||
icon: Database,
|
||||
children: [
|
||||
{ href: "/data-ingestion/sources", label: "数据源管理", icon: Database },
|
||||
{ href: "/data-ingestion/ai-engine", label: "AI标签引擎", icon: Brain },
|
||||
{ href: "/data-ingestion/cleaning", label: "清洗规则", icon: Zap },
|
||||
{ href: "/data-ingestion/tasks", label: "任务调度", icon: Calendar },
|
||||
{ href: "/data-ingestion/lineage", label: "数据血缘", icon: GitBranch },
|
||||
{ href: "/data-ingestion/quality", label: "质量监控", icon: Shield },
|
||||
],
|
||||
},
|
||||
// 第三部分:标签画像
|
||||
@@ -61,46 +62,42 @@ const NAV_ITEMS = [
|
||||
label: "标签画像",
|
||||
icon: Tags,
|
||||
children: [
|
||||
{ href: "/tag-portrait/tags", label: "标签体系", icon: Tags },
|
||||
{ href: "/tag-portrait/tags", label: "标签管理", icon: Tags },
|
||||
{ href: "/tag-portrait/portrait", label: "用户画像", icon: Users },
|
||||
{ href: "/tag-portrait/crowd", label: "人群圈选", icon: Target },
|
||||
{ href: "/tag-portrait/crowd", label: "流量池", icon: Target },
|
||||
],
|
||||
},
|
||||
// 第四部分:AI Agent智能系统
|
||||
// 第四部分:AI Agent(对接飞书/企微等外部平台)
|
||||
{
|
||||
href: "/ai-agent",
|
||||
label: "AI Agent",
|
||||
icon: Bot,
|
||||
children: [
|
||||
{ href: "/ai-agent/chat", label: "智能对话", icon: MessageSquare },
|
||||
{ href: "/ai-agent/channels", label: "渠道配置", icon: Webhook },
|
||||
{ href: "/ai-agent/smart-tag", label: "AI打标", icon: Sparkles },
|
||||
{ href: "/ai-agent/data-cleaning", label: "AI清洗", icon: Zap },
|
||||
{ href: "/ai-agent/nlq", label: "自然语言查询", icon: Search },
|
||||
{ href: "/ai-agent/report", label: "智能报告", icon: FileText },
|
||||
],
|
||||
},
|
||||
// 第五部分:数据输出
|
||||
// 第五部分:数据市场
|
||||
{
|
||||
href: "/data-output",
|
||||
label: "数据输出",
|
||||
icon: FileOutput,
|
||||
href: "/data-market",
|
||||
label: "数据市场",
|
||||
icon: Package,
|
||||
children: [
|
||||
{ href: "/data-output/packages", label: "流量包", icon: Package },
|
||||
{ href: "/data-output/api-market", label: "API市场", icon: Server },
|
||||
{ href: "/data-output/subscription", label: "数据订阅", icon: Webhook },
|
||||
{ href: "/data-market/packages", label: "流量包", icon: Package },
|
||||
{ href: "/data-market/api", label: "API服务", icon: Server },
|
||||
{ href: "/data-market/open-api", label: "开放接口", icon: Globe },
|
||||
],
|
||||
},
|
||||
// 系统监控(独立模块)
|
||||
] as const
|
||||
|
||||
// 底部工具菜单(系统监控等)
|
||||
const BOTTOM_NAV_ITEMS = [
|
||||
{
|
||||
href: "/system",
|
||||
href: "/monitoring/health",
|
||||
label: "系统监控",
|
||||
icon: Monitor,
|
||||
children: [
|
||||
{ href: "/system/health", label: "系统健康", icon: Activity },
|
||||
{ href: "/system/alerts", label: "告警中心", icon: Bell },
|
||||
{ href: "/system/logs", label: "操作日志", icon: ScrollText },
|
||||
{ href: "/system/metrics", label: "业务指标", icon: BarChart3 },
|
||||
],
|
||||
},
|
||||
] as const
|
||||
|
||||
@@ -110,7 +107,8 @@ function NavItemComponent({ item, level = 0 }: { item: NavItem; level?: number }
|
||||
const pathname = usePathname()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const hasChildren = "children" in item && item.children && item.children.length > 0
|
||||
const isActive = pathname === item.href || (item.href !== "/" && pathname.startsWith(item.href))
|
||||
const isExactActive = pathname === item.href
|
||||
const isActive = isExactActive || (item.href !== "/" && pathname.startsWith(item.href))
|
||||
|
||||
// Auto expand if child is active
|
||||
const childActive =
|
||||
@@ -120,21 +118,38 @@ function NavItemComponent({ item, level = 0 }: { item: NavItem; level?: number }
|
||||
<li>
|
||||
{hasChildren ? (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className={cn(
|
||||
"w-full flex items-center justify-between gap-3 rounded-xl px-4 py-3 text-sm font-medium transition-all duration-200",
|
||||
isActive || childActive
|
||||
{/* 父级菜单:左侧可点击跳转,右侧按钮展开子菜单 */}
|
||||
<div className={cn(
|
||||
"flex items-center rounded-xl transition-all duration-200",
|
||||
isExactActive
|
||||
? "bg-gradient-to-r from-blue-500 to-purple-500 text-white shadow-md"
|
||||
: isActive || childActive
|
||||
? "bg-blue-50 text-blue-600"
|
||||
: "text-gray-600 hover:bg-gray-100 hover:text-gray-900",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
: "text-gray-600 hover:bg-gray-100",
|
||||
)}>
|
||||
<Link
|
||||
href={item.href}
|
||||
className="flex-1 flex items-center gap-3 px-4 py-3 text-sm font-medium"
|
||||
>
|
||||
<item.icon className="h-5 w-5" />
|
||||
<span>{item.label}</span>
|
||||
</div>
|
||||
{isOpen || childActive ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
||||
</button>
|
||||
</Link>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setIsOpen(!isOpen)
|
||||
}}
|
||||
className={cn(
|
||||
"px-3 py-3 rounded-r-xl transition-colors",
|
||||
isExactActive
|
||||
? "hover:bg-white/10"
|
||||
: "hover:bg-gray-200"
|
||||
)}
|
||||
aria-label={isOpen ? "收起子菜单" : "展开子菜单"}
|
||||
>
|
||||
{isOpen || childActive ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
||||
</button>
|
||||
</div>
|
||||
{(isOpen || childActive) && (
|
||||
<ul className="mt-1 ml-4 space-y-1 border-l-2 border-gray-100 pl-4">
|
||||
{item.children?.map((child) => {
|
||||
@@ -183,7 +198,7 @@ export default function Sidebar() {
|
||||
<aside className="hidden md:flex flex-col w-64 shrink-0 border-r bg-white/80 backdrop-blur-md h-screen sticky top-0">
|
||||
<div className="p-6">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-1">神射手</h2>
|
||||
<p className="text-sm text-gray-600">私域银行数据中台</p>
|
||||
<p className="text-sm text-gray-600">用户资产数字化平台</p>
|
||||
</div>
|
||||
<nav className="flex-1 px-4 pb-4 overflow-y-auto">
|
||||
<ul className="space-y-1">
|
||||
|
||||
@@ -7,104 +7,54 @@ import {
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
Legend,
|
||||
ResponsiveContainer,
|
||||
BarChart as RechartsBarChart,
|
||||
Bar,
|
||||
PieChart as RechartsPieChart,
|
||||
Pie,
|
||||
Cell,
|
||||
} from "recharts"
|
||||
import { BarChart as RechartsBarChart, Bar } from "recharts"
|
||||
|
||||
interface ChartProps {
|
||||
data: any
|
||||
height?: number
|
||||
}
|
||||
const lineData = [
|
||||
{ name: "周一", 新增微信号: 12 },
|
||||
{ name: "周二", 新增微信号: 19 },
|
||||
{ name: "周三", 新增微信号: 3 },
|
||||
{ name: "周四", 新增微信号: 5 },
|
||||
{ name: "周五", 新增微信号: 2 },
|
||||
{ name: "周六", 新增微信号: 3 },
|
||||
{ name: "周日", 新增微信号: 10 },
|
||||
]
|
||||
|
||||
export function LineChart({ data, height = 300 }: ChartProps) {
|
||||
const barData = [
|
||||
{ name: "周一", 新增好友: 120 },
|
||||
{ name: "周二", 新增好友: 190 },
|
||||
{ name: "周三", 新增好友: 30 },
|
||||
{ name: "周四", 新增好友: 50 },
|
||||
{ name: "周五", 新增好友: 20 },
|
||||
{ name: "周六", 新增好友: 30 },
|
||||
{ name: "周日", 新增好友: 100 },
|
||||
]
|
||||
|
||||
export function LineChart() {
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={height}>
|
||||
<RechartsLineChart
|
||||
data={data.labels.map((label, i) => {
|
||||
const dataPoint = { name: label }
|
||||
data.datasets.forEach((dataset, j) => {
|
||||
dataPoint[dataset.label] = dataset.data[i]
|
||||
})
|
||||
return dataPoint
|
||||
})}
|
||||
>
|
||||
<ResponsiveContainer width="100%" height={180}>
|
||||
<RechartsLineChart data={lineData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
{data.datasets.map((dataset, i) => (
|
||||
<Line
|
||||
key={i}
|
||||
type="monotone"
|
||||
dataKey={dataset.label}
|
||||
stroke={dataset.borderColor}
|
||||
fill={dataset.backgroundColor}
|
||||
activeDot={{ r: 8 }}
|
||||
/>
|
||||
))}
|
||||
<Line type="monotone" dataKey="新增微信号" stroke="#8884d8" />
|
||||
</RechartsLineChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export function BarChart({ data, height = 300 }: ChartProps) {
|
||||
export function BarChart() {
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={height}>
|
||||
<RechartsBarChart
|
||||
data={data.labels.map((label, i) => {
|
||||
const dataPoint = { name: label }
|
||||
data.datasets.forEach((dataset, j) => {
|
||||
dataPoint[dataset.label] = dataset.data[i]
|
||||
})
|
||||
return dataPoint
|
||||
})}
|
||||
>
|
||||
<ResponsiveContainer width="100%" height={180}>
|
||||
<RechartsBarChart data={barData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
{data.datasets.map((dataset, i) => (
|
||||
<Bar key={i} dataKey={dataset.label} fill={dataset.backgroundColor || "#8884d8"} />
|
||||
))}
|
||||
<Bar dataKey="新增好友" fill="#82ca9d" />
|
||||
</RechartsBarChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export function PieChart({ data, height = 300 }: ChartProps) {
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={height}>
|
||||
<RechartsPieChart>
|
||||
<Pie
|
||||
data={data.labels.map((label, i) => ({
|
||||
name: label,
|
||||
value: data.datasets[0].data[i],
|
||||
}))}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
labelLine={false}
|
||||
outerRadius={80}
|
||||
fill="#8884d8"
|
||||
dataKey="value"
|
||||
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
|
||||
>
|
||||
{data.labels.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-${index}`}
|
||||
fill={data.datasets[0].backgroundColor[index] || `#${Math.floor(Math.random() * 16777215).toString(16)}`}
|
||||
/>
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</RechartsPieChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user