feat(web): 更换页面框架为pro-layout

This commit is contained in:
v-zhangjc9
2025-05-12 10:42:59 +08:00
parent aa93b52dd9
commit 1e7b195f9f
17 changed files with 772 additions and 222 deletions

View File

@@ -3,73 +3,8 @@ import {createHashRouter, RouterProvider} from 'react-router'
import './components/Registry.ts'
import App from './pages/App.tsx'
import Cloud from './pages/Cloud.tsx'
import Conversation from './pages/Conversation.tsx'
import Home from './pages/Home.tsx'
import Overview from './pages/Overview.tsx'
import Queue from './pages/Queue.tsx'
import Table from './pages/Table.tsx'
import Task from './pages/Task.tsx'
import Tool from './pages/Tool.tsx'
import Version from './pages/Version.tsx'
import Yarn from './pages/Yarn.tsx'
import YarnCluster from './pages/YarnCluster.tsx'
const routes = createHashRouter([
{
path: '/',
Component: App,
children: [
{
Component: Home,
children: [
{
index: true,
Component: Overview,
},
{
path: '/home/table',
Component: Table,
},
{
path: '/home/queue',
Component: Queue,
},
{
path: '/home/version',
Component: Version,
},
{
path: '/home/yarn/:clusters/:queue/:search?',
Component: Yarn,
},
{
path: '/home/cloud',
Component: Cloud,
},
{
path: '/home/yarn_cluster',
Component: YarnCluster,
},
{
path: '/home/tool',
Component: Tool,
},
{
path: '/home/task',
Component: Task,
},
],
},
{
path: 'conversation',
Component: Conversation,
},
],
},
])
import {routes} from './route.tsx'
createRoot(document.getElementById('root')!).render(
<RouterProvider router={routes}/>,
<RouterProvider router={createHashRouter(routes)}/>,
)

View File

@@ -0,0 +1,18 @@
import {amisRender} from '../util/amis.ts'
function Ai() {
return (
<div className="ai">
{amisRender(
{
type: 'wrapper',
body: [
'逗你的,什么都没做,哎嘿!',
],
},
)}
</div>
)
}
export default Ai

View File

@@ -1,54 +1,50 @@
import {Layout, Menu} from 'antd'
import type {ItemType, MenuItemType} from 'antd/es/menu/interface'
import {contain, isEqual} from 'licia'
import React, {useEffect, useState} from 'react'
import {NavLink, Outlet, useLocation} from 'react-router'
const {Header, Content} = Layout
const headerNav: Array<MenuItemType> = [
{key: '/', label: '首页'},
{key: '/conversation', label: 'AI'},
]
import {ProLayout} from '@ant-design/pro-components'
import React, {useEffect} from 'react'
import {Outlet, useLocation, useNavigate} from 'react-router'
import {menus} from '../route.tsx'
const App: React.FC = () => {
const [_, setCurrentMenu] = useState<ItemType>()
const [selectedKeys, setSelectedKeys] = useState<Array<string>>([])
const navigate = useNavigate()
const location = useLocation()
useEffect(() => {
if (isEqual('/', location.pathname)) {
setSelectedKeys([location.pathname])
} else {
setSelectedKeys([headerNav.filter(nav => !isEqual(nav?.key, '/')).find(nav => contain(location.pathname, nav?.key))?.key as string ?? '/'])
}
setCurrentMenu(headerNav.find(nav => isEqual(nav?.key, location.pathname)))
console.log(location.pathname)
}, [location])
return (
<Layout className="app h-full">
<Header className="header flex items-center p-5">
<div className="title font-sans text-white flex flex-col mr-10">
<div className="main-title text-xl font-extrabold leading-normal">Hudi </div>
<div className="sub-title text-gray-300 font-bold leading-normal">Hudi </div>
<ProLayout
token={{
header: {
colorBgHeader: '#292f33',
colorHeaderTitle: '#ffffff',
colorTextMenu: '#dfdfdf',
colorTextMenuSecondary: '#dfdfdf',
colorTextMenuSelected: '#ffffff',
colorTextMenuActive: '#ffffff',
colorBgMenuItemSelected: '#22272b',
colorTextRightActionsItem: '#dfdfdf',
},
}}
logo={<img src="/icon.png" alt="logo"/>}
title="Hudi 服务总台"
route={menus}
location={{pathname: location.pathname}}
menu={{type: 'sub'}}
menuItemRender={(item, dom) => (
<div
onClick={() => {
navigate(item.path ?? '/')
}}
>
{dom}
</div>
<Menu
className="header-nav"
theme="dark"
mode="horizontal"
selectedKeys={selectedKeys}
items={headerNav.map(nav => ({
key: nav.key,
label: <NavLink className="font-bold" to={nav.key as string}>{nav.label}</NavLink>,
}))}
style={{minWidth: 0, flex: 'auto'}}
/>
</Header>
<Layout>
<Content className="content">
<Outlet/>
</Content>
</Layout>
</Layout>
)}
fixSiderbar={true}
layout="mix"
splitMenus={true}
style={{height: '100vh'}}
contentStyle={{backgroundColor: 'white', padding: '10px 10px 10px 20px'}}
>
<Outlet/>
</ProLayout>
)
}

View File

@@ -1,83 +0,0 @@
import {
CheckSquareOutlined,
CloudOutlined,
ClusterOutlined,
CompressOutlined,
InfoCircleOutlined,
SunOutlined,
SyncOutlined,
TableOutlined,
ToolOutlined,
} from '@ant-design/icons'
import {Layout, Menu, theme} from 'antd'
import type {ItemType} from 'antd/es/menu/interface'
import {isNil} from 'licia'
import React from 'react'
import {NavLink, Outlet} from 'react-router'
import {commonInfo} from '../util/amis.ts'
const {Sider, Content} = Layout
const generateNavItem: any = (key: string, label: string, icon?: any) => {
let nav: any = {
key: key,
label: <NavLink to={key}>{label}</NavLink>,
}
if (!isNil(icon)) {
nav['icon'] = icon
}
return nav
}
const siderNav: ItemType[] = [
generateNavItem('/', '概览', <InfoCircleOutlined/>),
generateNavItem('/home/table', '表任务', <TableOutlined/>),
generateNavItem('/home/queue', '压缩队列', <CompressOutlined/>),
generateNavItem('/home/version', '跨天', <SunOutlined/>),
generateNavItem(`/home/yarn/${commonInfo.clusters.sync_names()}/root/Sync`, '同步集群', <SyncOutlined/>),
generateNavItem(
`/home/yarn/${commonInfo.clusters.compaction_names()}/default/Compaction`,
'压缩集群',
<SyncOutlined/>,
),
generateNavItem('/home/cloud', '服务', <CloudOutlined/>),
{
label: '集群',
icon: <ClusterOutlined/>,
children: [
generateNavItem('/home/yarn_cluster', '总览', <InfoCircleOutlined/>),
...Object.keys(commonInfo.clusters.compaction).map(name => generateNavItem(
// @ts-ignore
`/home/yarn/${name}/${commonInfo.clusters.compaction[name]}`,
`${name} 集群`,
<ClusterOutlined/>,
)),
],
},
generateNavItem('/home/tool', '工具', <ToolOutlined/>),
generateNavItem('/home/task', '任务', <CheckSquareOutlined/>),
]
const Home: React.FC = () => {
const {
token: {
colorBgContainer,
},
} = theme.useToken()
return (
<Layout className="home min-h-full">
<Sider width={170} style={{backgroundColor: colorBgContainer}}>
<Menu
mode="inline"
defaultSelectedKeys={['/']}
items={siderNav}
/>
</Sider>
<Content className="p-3">
<Outlet/>
</Content>
</Layout>
)
}
export default Home

View File

@@ -1,4 +1,4 @@
import {amisRender} from '../util/amis.ts'
import {amisRender} from '../../util/amis.ts'
function Conversation() {
return (

View File

@@ -6,7 +6,7 @@ import {
serviceLogByAppName,
serviceLogByAppNameAndHost,
time,
} from '../util/amis.ts'
} from '../../util/amis.ts'
const cloudCrud = (title: string, path: string) => {
return {

View File

@@ -6,7 +6,7 @@ import {
paginationCommonOptions,
time,
yarnQueueCrud,
} from '../util/amis.ts'
} from '../../util/amis.ts'
const queueCrud = (name: string) => {
return {

View File

@@ -14,7 +14,7 @@ import {
tableMetaDialog,
tableRunningStateMapping,
timeAndFrom,
} from '../util/amis.ts'
} from '../../util/amis.ts'
function Table() {
return (

View File

@@ -1,5 +1,5 @@
import React from 'react'
import {amisRender, commonInfo, paginationCommonOptions, serviceLogByAppName, yarnCrudColumns} from '../util/amis.ts'
import {amisRender, commonInfo, paginationCommonOptions, serviceLogByAppName, yarnCrudColumns} from '../../util/amis.ts'
const Task: React.FC = () => {
return (

View File

@@ -10,7 +10,7 @@ import {
paginationCommonOptions,
readOnlyDialogOptions,
timelineColumns,
} from '../util/amis.ts'
} from '../../util/amis.ts'
const Tool: React.FC = () => {
return (

View File

@@ -10,7 +10,7 @@ import {
paginationCommonOptions,
tableMetaDialog,
versionUpdateStateMapping,
} from '../util/amis.ts'
} from '../../util/amis.ts'
function Version() {
return (

View File

@@ -7,7 +7,7 @@ import {
paginationCommonOptions,
yarnCrudColumns,
yarnQueueCrud,
} from '../util/amis.ts'
} from '../../util/amis.ts'
const Yarn: React.FC = () => {
const {clusters, queue, search} = useParams()

View File

@@ -1,5 +1,5 @@
import React from 'react'
import {amisRender, commonInfo, yarnQueueCrud} from '../util/amis.ts'
import {amisRender, commonInfo, yarnQueueCrud} from '../../util/amis.ts'
const YarnCluster: React.FC = () => {
return (

View File

@@ -0,0 +1,157 @@
import {
CheckSquareOutlined,
CloudOutlined,
ClusterOutlined,
CompressOutlined,
InfoCircleOutlined,
SunOutlined,
SyncOutlined,
TableOutlined,
ToolOutlined,
} from '@ant-design/icons'
import type {Route} from '@ant-design/pro-layout/es/typing'
import type {RouteObject} from 'react-router'
import Ai from './pages/Ai.tsx'
import App from './pages/App.tsx'
import Cloud from './pages/overview/Cloud.tsx'
import Overview from './pages/Overview.tsx'
import Queue from './pages/overview/Queue.tsx'
import Table from './pages/overview/Table.tsx'
import Task from './pages/overview/Task.tsx'
import Tool from './pages/overview/Tool.tsx'
import Version from './pages/overview/Version.tsx'
import Yarn from './pages/overview/Yarn.tsx'
import YarnCluster from './pages/overview/YarnCluster.tsx'
import {commonInfo} from './util/amis.ts'
export const routes: RouteObject[] = [
{
path: '/',
Component: App,
children: [
{
children: [
{
index: true,
Component: Overview,
},
{
path: 'table',
Component: Table,
},
{
path: 'queue',
Component: Queue,
},
{
path: 'version',
Component: Version,
},
{
path: 'yarn/:clusters/:queue/:search?',
Component: Yarn,
},
{
path: 'cloud',
Component: Cloud,
},
{
path: 'yarn_cluster',
Component: YarnCluster,
},
{
path: 'tool',
Component: Tool,
},
{
path: 'task',
Component: Task,
},
],
},
{
path: 'ai',
Component: Ai,
},
],
},
]
export const menus: Route = {
routes: [
{
path: '/',
name: '概览',
icon: <InfoCircleOutlined/>,
routes: [
{
path: '/',
name: '概览',
icon: <InfoCircleOutlined/>,
},
{
path: '/table',
name: '表任务',
icon: <TableOutlined/>,
},
{
path: '/queue',
name: '压缩队列',
icon: <CompressOutlined/>,
},
{
path: '/version',
name: '跨天',
icon: <SunOutlined/>,
},
{
path: `/yarn/${commonInfo.clusters.sync_names()}/root/Sync`,
name: '同步集群',
icon: <SyncOutlined/>,
},
{
path: `/yarn/${commonInfo.clusters.compaction_names()}/default/Compaction`,
name: '压缩集群',
icon: <SyncOutlined/>,
},
{
path: '/cloud',
name: '服务',
icon: <CloudOutlined/>,
},
{
path: '/yarn_cluster',
name: '集群',
icon: <ClusterOutlined/>,
routes: [
{
path: '/yarn_cluster',
name: '概览',
icon: <InfoCircleOutlined/>,
},
...Object.keys(commonInfo.clusters.compaction).map(name => ({
// @ts-ignore
path: `/yarn/${name}/${commonInfo.clusters.compaction[name]}`,
name: `${name} 集群`,
icon: <ClusterOutlined/>,
})),
],
},
{
path: '/tool',
name: '工具',
icon: <ToolOutlined/>,
},
{
path: '/task',
name: '任务',
icon: <CheckSquareOutlined/>,
},
],
},
{
path: '/ai',
name: 'AI',
}
],
}