@zhin.js/console 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +4 -4
- package/client/components.json +17 -0
- package/client/index.html +1 -1
- package/client/src/components/PluginConfigForm/BasicFieldRenderers.tsx +89 -180
- package/client/src/components/PluginConfigForm/CollectionFieldRenderers.tsx +97 -200
- package/client/src/components/PluginConfigForm/CompositeFieldRenderers.tsx +31 -70
- package/client/src/components/PluginConfigForm/FieldRenderer.tsx +27 -77
- package/client/src/components/PluginConfigForm/NestedFieldRenderer.tsx +33 -53
- package/client/src/components/PluginConfigForm/index.tsx +71 -173
- package/client/src/components/ui/accordion.tsx +54 -0
- package/client/src/components/ui/alert.tsx +62 -0
- package/client/src/components/ui/avatar.tsx +41 -0
- package/client/src/components/ui/badge.tsx +32 -0
- package/client/src/components/ui/button.tsx +50 -0
- package/client/src/components/ui/card.tsx +50 -0
- package/client/src/components/ui/checkbox.tsx +25 -0
- package/client/src/components/ui/dialog.tsx +87 -0
- package/client/src/components/ui/dropdown-menu.tsx +97 -0
- package/client/src/components/ui/input.tsx +21 -0
- package/client/src/components/ui/scroll-area.tsx +43 -0
- package/client/src/components/ui/select.tsx +127 -0
- package/client/src/components/ui/separator.tsx +23 -0
- package/client/src/components/ui/skeleton.tsx +12 -0
- package/client/src/components/ui/switch.tsx +26 -0
- package/client/src/components/ui/tabs.tsx +52 -0
- package/client/src/components/ui/textarea.tsx +20 -0
- package/client/src/components/ui/tooltip.tsx +27 -0
- package/client/src/layouts/dashboard.tsx +91 -221
- package/client/src/main.tsx +38 -42
- package/client/src/pages/dashboard-bots.tsx +91 -137
- package/client/src/pages/dashboard-home.tsx +133 -204
- package/client/src/pages/dashboard-logs.tsx +125 -196
- package/client/src/pages/dashboard-plugin-detail.tsx +261 -329
- package/client/src/pages/dashboard-plugins.tsx +108 -105
- package/client/src/style.css +156 -865
- package/client/src/theme/index.ts +60 -35
- package/client/tailwind.config.js +78 -69
- package/dist/client.js +1 -1
- package/dist/cva.js +47 -0
- package/dist/index.html +1 -1
- package/dist/index.js +6 -6
- package/dist/react-router.js +7121 -5585
- package/dist/react.js +192 -149
- package/dist/style.css +2 -2
- package/lib/bin.js +2 -2
- package/lib/build.js +2 -2
- package/lib/index.d.ts +0 -3
- package/lib/index.js +160 -205
- package/lib/transform.d.ts +26 -0
- package/lib/transform.js +78 -0
- package/lib/websocket.d.ts +0 -1
- package/package.json +9 -8
- package/dist/radix-ui-themes.js +0 -9305
- package/lib/dev.d.ts +0 -18
- package/lib/dev.js +0 -87
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import { Outlet, Link, useSelector, useDispatch, toggleSidebar, setActiveMenu
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import * as Themes from '@radix-ui/themes'
|
|
5
|
-
import {Menu, Search,Bell,User,Users,BarChart3,HelpCircle,LogOut} from 'lucide-react'
|
|
1
|
+
import { Outlet, Link, useSelector, useDispatch, toggleSidebar, setActiveMenu } from "@zhin.js/client"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
|
+
import { Menu, Search } from 'lucide-react'
|
|
6
4
|
import { cn } from "@zhin.js/client"
|
|
7
5
|
import { ThemeToggle } from "../components/ThemeToggle"
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { Button } from "../components/ui/button"
|
|
7
|
+
import { Input } from "../components/ui/input"
|
|
8
|
+
import { ScrollArea } from "../components/ui/scroll-area"
|
|
9
|
+
import { Avatar, AvatarImage, AvatarFallback } from "../components/ui/avatar"
|
|
10
10
|
|
|
11
11
|
export default function DashboardLayout() {
|
|
12
12
|
const dispatch = useDispatch()
|
|
13
|
-
const ws = useWebSocket()
|
|
14
13
|
const sidebarOpen = useSelector(state => state.ui.sidebarOpen)
|
|
15
14
|
const activeMenu = useSelector(state => state.ui.activeMenu)
|
|
16
15
|
const routes = useSelector(state => state.route.routes)
|
|
17
16
|
|
|
18
17
|
const menuItems = useMemo(() => {
|
|
19
|
-
// 找到 dashboard 路由
|
|
20
18
|
const dashboardRoute = routes.find(route => route.key === 'dashboard-layout')
|
|
21
19
|
if (!dashboardRoute || !dashboardRoute.children) {
|
|
22
20
|
return []
|
|
@@ -33,226 +31,98 @@ export default function DashboardLayout() {
|
|
|
33
31
|
}, [routes])
|
|
34
32
|
|
|
35
33
|
return (
|
|
36
|
-
<
|
|
37
|
-
{/*
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
sidebarOpen ? "gap-3" : "justify-center"
|
|
52
|
-
)}
|
|
53
|
-
>
|
|
54
|
-
<Flex
|
|
55
|
-
align="center"
|
|
56
|
-
justify="center"
|
|
57
|
-
className="w-11 min-w-11 h-11 rounded-xl shadow-md bg-gradient-to-br from-blue-500 to-purple-600"
|
|
58
|
-
>
|
|
59
|
-
<Text size="5" weight="bold" className="text-white">
|
|
60
|
-
Z
|
|
61
|
-
</Text>
|
|
62
|
-
</Flex>
|
|
34
|
+
<div className="flex h-screen bg-background">
|
|
35
|
+
{/* Sidebar */}
|
|
36
|
+
<div className={cn(
|
|
37
|
+
"flex flex-col border-r bg-sidebar transition-all duration-300",
|
|
38
|
+
sidebarOpen ? "w-64" : "w-16"
|
|
39
|
+
)}>
|
|
40
|
+
{/* Logo */}
|
|
41
|
+
<div className="p-4 border-b">
|
|
42
|
+
<div className={cn(
|
|
43
|
+
"flex items-center transition-all duration-300",
|
|
44
|
+
sidebarOpen ? "gap-3" : "justify-center"
|
|
45
|
+
)}>
|
|
46
|
+
<div className="flex items-center justify-center w-9 h-9 min-w-9 rounded-lg bg-foreground text-background font-bold text-lg">
|
|
47
|
+
Z
|
|
48
|
+
</div>
|
|
63
49
|
{sidebarOpen && (
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<Text size="1" color="gray">管理控制台</Text>
|
|
69
|
-
</Flex>
|
|
50
|
+
<div className="flex flex-col">
|
|
51
|
+
<span className="text-base font-semibold">Zhin.js</span>
|
|
52
|
+
<span className="text-xs text-muted-foreground">管理控制台</span>
|
|
53
|
+
</div>
|
|
70
54
|
)}
|
|
71
|
-
</
|
|
72
|
-
</
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
73
57
|
|
|
74
|
-
{/*
|
|
75
|
-
<ScrollArea className="flex-1"
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</Link>
|
|
97
|
-
)
|
|
98
|
-
})}
|
|
99
|
-
</Flex>
|
|
100
|
-
</Box>
|
|
58
|
+
{/* Menu */}
|
|
59
|
+
<ScrollArea className="flex-1">
|
|
60
|
+
<div className="p-2 space-y-1">
|
|
61
|
+
{menuItems.map((item) => {
|
|
62
|
+
const isActive = activeMenu === item.key
|
|
63
|
+
return (
|
|
64
|
+
<Link
|
|
65
|
+
key={item.key}
|
|
66
|
+
to={item.href}
|
|
67
|
+
onClick={() => dispatch(setActiveMenu(item.key))}
|
|
68
|
+
className={cn(
|
|
69
|
+
"menu-item",
|
|
70
|
+
isActive && "active",
|
|
71
|
+
!sidebarOpen && "justify-center px-2"
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
74
|
+
<span className="shrink-0">{item.icon}</span>
|
|
75
|
+
{sidebarOpen && <span className="truncate">{item.title}</span>}
|
|
76
|
+
</Link>
|
|
77
|
+
)
|
|
78
|
+
})}
|
|
79
|
+
</div>
|
|
101
80
|
</ScrollArea>
|
|
81
|
+
</div>
|
|
102
82
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
管理员
|
|
122
|
-
</Text>
|
|
123
|
-
<Text size="1" color="gray" className="truncate">
|
|
124
|
-
admin@zhin.com
|
|
125
|
-
</Text>
|
|
126
|
-
</Flex>
|
|
127
|
-
)}
|
|
128
|
-
</Flex>
|
|
129
|
-
</Flex>
|
|
130
|
-
</Flex>
|
|
131
|
-
|
|
132
|
-
{/* 主内容区域 */}
|
|
133
|
-
<Flex direction="column" className="flex-1 overflow-hidden">
|
|
134
|
-
{/* 顶部导航栏 */}
|
|
135
|
-
<Box className="glass border-b border-gray-200/50 dark:border-gray-700/50 shadow-sm">
|
|
136
|
-
<Flex justify="between" align="center" px="4" className="h-16">
|
|
137
|
-
{/* 左侧 */}
|
|
138
|
-
<Flex align="center" gap="3">
|
|
139
|
-
<IconButton
|
|
140
|
-
variant="ghost"
|
|
141
|
-
size="2"
|
|
142
|
-
onClick={() => dispatch(toggleSidebar())}
|
|
143
|
-
className="hover-lift rounded-xl"
|
|
144
|
-
>
|
|
145
|
-
<Menu className="w-5 h-5" />
|
|
146
|
-
</IconButton>
|
|
147
|
-
<Flex direction="column" gap="0">
|
|
148
|
-
<Heading size="3" className="text-gray-900 dark:text-gray-100">控制台</Heading>
|
|
149
|
-
<Text size="1" color="gray">欢迎回来!</Text>
|
|
150
|
-
</Flex>
|
|
151
|
-
</Flex>
|
|
152
|
-
|
|
153
|
-
{/* 中间搜索栏 */}
|
|
154
|
-
<Flex className="hidden md:flex flex-1 max-w-xl mx-6">
|
|
155
|
-
<Box className="relative">
|
|
156
|
-
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 dark:text-gray-500" />
|
|
157
|
-
<TextField.Root
|
|
158
|
-
placeholder="搜索功能、用户、设置..."
|
|
159
|
-
size="2"
|
|
160
|
-
className="w-full pl-10"
|
|
161
|
-
/>
|
|
162
|
-
</Box>
|
|
163
|
-
</Flex>
|
|
164
|
-
|
|
165
|
-
{/* 右侧操作区 */}
|
|
166
|
-
<Flex align="center" gap="2">
|
|
167
|
-
{/* 主题切换 */}
|
|
168
|
-
<ThemeToggle />
|
|
83
|
+
{/* Main content area */}
|
|
84
|
+
<div className="flex flex-col flex-1 overflow-hidden">
|
|
85
|
+
{/* Top bar */}
|
|
86
|
+
<header className="flex items-center justify-between h-14 px-4 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
87
|
+
{/* Left */}
|
|
88
|
+
<div className="flex items-center gap-3">
|
|
89
|
+
<Button
|
|
90
|
+
variant="ghost"
|
|
91
|
+
size="icon"
|
|
92
|
+
onClick={() => dispatch(toggleSidebar())}
|
|
93
|
+
>
|
|
94
|
+
<Menu className="h-5 w-5" />
|
|
95
|
+
</Button>
|
|
96
|
+
<div className="flex flex-col">
|
|
97
|
+
<h2 className="text-sm font-semibold">控制台</h2>
|
|
98
|
+
<span className="text-xs text-muted-foreground">欢迎回来</span>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
169
101
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
color="red"
|
|
181
|
-
variant="solid"
|
|
182
|
-
size="1"
|
|
183
|
-
className="absolute -top-1 -right-1 min-w-5 h-5 flex items-center justify-center p-0"
|
|
184
|
-
>
|
|
185
|
-
3
|
|
186
|
-
</Badge>
|
|
187
|
-
</Box>
|
|
102
|
+
{/* Center search */}
|
|
103
|
+
<div className="hidden md:flex flex-1 max-w-md mx-6">
|
|
104
|
+
<div className="relative w-full">
|
|
105
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
106
|
+
<Input
|
|
107
|
+
placeholder="搜索功能、插件、设置..."
|
|
108
|
+
className="pl-9 bg-muted/50"
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
188
112
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
gap="2"
|
|
195
|
-
px="2"
|
|
196
|
-
py="1"
|
|
197
|
-
className="cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition-all duration-200 rounded-xl"
|
|
198
|
-
>
|
|
199
|
-
<Avatar.Root className="w-8 h-8 border-2 border-blue-500/20 dark:border-blue-400/30">
|
|
200
|
-
<Avatar.Image src="https://i.pravatar.cc/150?u=admin" alt="管理员" />
|
|
201
|
-
<Avatar.Fallback>管</Avatar.Fallback>
|
|
202
|
-
</Avatar.Root>
|
|
203
|
-
<Flex direction="column" gap="0" className="hidden lg:flex">
|
|
204
|
-
<Text size="2" weight="medium" className="text-gray-900 dark:text-gray-100">
|
|
205
|
-
管理员
|
|
206
|
-
</Text>
|
|
207
|
-
<Text size="1" color="gray">
|
|
208
|
-
admin@zhin.com
|
|
209
|
-
</Text>
|
|
210
|
-
</Flex>
|
|
211
|
-
</Flex>
|
|
212
|
-
</DropdownMenu.Trigger>
|
|
213
|
-
<DropdownMenu.Content align="end" className="min-w-56">
|
|
214
|
-
<Box p="3" className="border-b border-gray-200 dark:border-gray-700">
|
|
215
|
-
<Text size="2" weight="bold" className="block">
|
|
216
|
-
登录为
|
|
217
|
-
</Text>
|
|
218
|
-
<Text size="1" color="gray" className="block">
|
|
219
|
-
admin@zhin.com
|
|
220
|
-
</Text>
|
|
221
|
-
</Box>
|
|
222
|
-
<DropdownMenu.Item>
|
|
223
|
-
<User className="mr-2 h-4 w-4" />
|
|
224
|
-
我的设置
|
|
225
|
-
</DropdownMenu.Item>
|
|
226
|
-
<DropdownMenu.Item>
|
|
227
|
-
<Users className="mr-2 h-4 w-4" />
|
|
228
|
-
团队设置
|
|
229
|
-
</DropdownMenu.Item>
|
|
230
|
-
<DropdownMenu.Item>
|
|
231
|
-
<BarChart3 className="mr-2 h-4 w-4" />
|
|
232
|
-
数据分析
|
|
233
|
-
</DropdownMenu.Item>
|
|
234
|
-
<DropdownMenu.Item>
|
|
235
|
-
<HelpCircle className="mr-2 h-4 w-4" />
|
|
236
|
-
帮助与反馈
|
|
237
|
-
</DropdownMenu.Item>
|
|
238
|
-
<DropdownMenu.Separator />
|
|
239
|
-
<DropdownMenu.Item color="red">
|
|
240
|
-
<LogOut className="mr-2 h-4 w-4" />
|
|
241
|
-
退出登录
|
|
242
|
-
</DropdownMenu.Item>
|
|
243
|
-
</DropdownMenu.Content>
|
|
244
|
-
</DropdownMenu.Root>
|
|
245
|
-
</Flex>
|
|
246
|
-
</Flex>
|
|
247
|
-
</Box>
|
|
113
|
+
{/* Right actions */}
|
|
114
|
+
<div className="flex items-center gap-1">
|
|
115
|
+
<ThemeToggle />
|
|
116
|
+
</div>
|
|
117
|
+
</header>
|
|
248
118
|
|
|
249
|
-
{/*
|
|
250
|
-
<
|
|
251
|
-
<
|
|
119
|
+
{/* Page content */}
|
|
120
|
+
<main className="flex-1 overflow-auto">
|
|
121
|
+
<div className="max-w-7xl mx-auto p-6">
|
|
252
122
|
<Outlet />
|
|
253
|
-
</
|
|
254
|
-
</
|
|
255
|
-
</
|
|
256
|
-
</
|
|
123
|
+
</div>
|
|
124
|
+
</main>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
257
127
|
)
|
|
258
128
|
}
|
package/client/src/main.tsx
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
import { StrictMode, useEffect, useState } from 'react'
|
|
2
2
|
import { createRoot } from 'react-dom/client'
|
|
3
3
|
import { Provider as ReduxProvider } from 'react-redux'
|
|
4
|
-
import {Home, Package, Bot, FileText} from 'lucide-react'
|
|
5
|
-
import { store, DynamicRouter, persistor, addPage, useSelector } from '@zhin.js/client'
|
|
4
|
+
import { Home, Package, Bot, FileText } from 'lucide-react'
|
|
5
|
+
import { store, DynamicRouter, persistor, addPage, useSelector, useWebSocket } from '@zhin.js/client'
|
|
6
6
|
import DashboardLayout from './layouts/dashboard'
|
|
7
7
|
import DashboardHome from './pages/dashboard-home'
|
|
8
8
|
import DashboardPlugins from './pages/dashboard-plugins'
|
|
9
9
|
import DashboardPluginDetail from './pages/dashboard-plugin-detail'
|
|
10
10
|
import DashboardBots from './pages/dashboard-bots'
|
|
11
11
|
import DashboardLogs from './pages/dashboard-logs'
|
|
12
|
-
import { Theme } from '@radix-ui/themes';
|
|
13
|
-
import '@radix-ui/themes/styles.css'
|
|
14
12
|
import './style.css'
|
|
15
13
|
import { PersistGate } from 'redux-persist/integration/react'
|
|
16
14
|
import { initializeTheme } from './theme'
|
|
15
|
+
import { TooltipProvider } from './components/ui/tooltip'
|
|
17
16
|
|
|
18
17
|
// Initialize theme on app load
|
|
19
18
|
initializeTheme()
|
|
20
19
|
|
|
21
|
-
//
|
|
20
|
+
// Route initializer component
|
|
22
21
|
function RouteInitializer() {
|
|
22
|
+
useWebSocket()
|
|
23
|
+
|
|
23
24
|
const entries = useSelector(state => state.script.entries)
|
|
24
25
|
const loadedScripts = useSelector(state => state.script.loadedScripts)
|
|
26
|
+
const synced = useSelector(state => state.script.synced)
|
|
25
27
|
const [initialized, setInitialized] = useState(false)
|
|
26
28
|
|
|
27
29
|
useEffect(() => {
|
|
28
|
-
// 路由配置 - 使用 Component 属性而不是 element
|
|
29
30
|
const routes = [
|
|
30
31
|
{
|
|
31
32
|
key: 'dashboard-layout',
|
|
32
33
|
path: '/',
|
|
33
34
|
title: 'Dashboard',
|
|
34
|
-
element: <DashboardLayout/>,
|
|
35
|
+
element: <DashboardLayout />,
|
|
35
36
|
redirect: '/dashboard',
|
|
36
37
|
meta: { order: 0 },
|
|
37
38
|
children: [
|
|
@@ -40,63 +41,58 @@ function RouteInitializer() {
|
|
|
40
41
|
index: true,
|
|
41
42
|
path: '',
|
|
42
43
|
title: '系统概览',
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
icon: <Home className="w-4 h-4" />,
|
|
45
|
+
element: <DashboardHome />,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'dashboard-plugins',
|
|
49
|
+
path: '/plugins',
|
|
50
|
+
title: '插件管理',
|
|
51
|
+
icon: <Package className="w-4 h-4" />,
|
|
52
|
+
element: <DashboardPlugins />,
|
|
53
|
+
meta: { order: 2 }
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: 'dashboard-plugin-detail',
|
|
57
|
+
title: '插件详情',
|
|
58
|
+
path: '/plugins/:name',
|
|
59
|
+
element: <DashboardPluginDetail />,
|
|
60
|
+
meta: { hideInMenu: true }
|
|
46
61
|
},
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
key: 'dashboard-plugins',
|
|
50
|
-
path: '/plugins',
|
|
51
|
-
title: '插件管理',
|
|
52
|
-
icon: <Package className="w-5 h-5" />,
|
|
53
|
-
element: <DashboardPlugins/>,
|
|
54
|
-
meta: { order: 2 }
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
key: 'dashboard-plugin-detail',
|
|
58
|
-
title: '插件详情',
|
|
59
|
-
path: '/plugins/:name',
|
|
60
|
-
element: <DashboardPluginDetail/>,
|
|
61
|
-
meta: { hideInMenu: true }
|
|
62
|
-
},
|
|
63
62
|
{
|
|
64
63
|
key: 'dashboard-bots',
|
|
65
64
|
path: '/bots',
|
|
66
65
|
title: '机器人',
|
|
67
|
-
icon: <Bot className="w-
|
|
68
|
-
element: <DashboardBots/>,
|
|
66
|
+
icon: <Bot className="w-4 h-4" />,
|
|
67
|
+
element: <DashboardBots />,
|
|
69
68
|
meta: { order: 3 }
|
|
70
69
|
},
|
|
71
70
|
{
|
|
72
71
|
key: 'dashboard-logs',
|
|
73
72
|
path: '/logs',
|
|
74
73
|
title: '系统日志',
|
|
75
|
-
icon: <FileText className="w-
|
|
76
|
-
element: <DashboardLogs/>,
|
|
74
|
+
icon: <FileText className="w-4 h-4" />,
|
|
75
|
+
element: <DashboardLogs />,
|
|
77
76
|
meta: { order: 4 }
|
|
78
77
|
}
|
|
79
78
|
]
|
|
80
79
|
}
|
|
81
80
|
]
|
|
82
|
-
|
|
83
|
-
// 添加静态路由
|
|
81
|
+
|
|
84
82
|
routes.forEach(route => {
|
|
85
83
|
addPage(route)
|
|
86
84
|
})
|
|
87
85
|
setInitialized(true)
|
|
88
86
|
}, [])
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
const allScriptsLoaded = entries.length === 0 || entries.length === loadedScripts.length
|
|
88
|
+
const allScriptsLoaded = synced && (entries.length === 0 || entries.length === loadedScripts.length)
|
|
92
89
|
|
|
93
|
-
// 等待静态路由和动态脚本都加载完成
|
|
94
90
|
if (!initialized || !allScriptsLoaded) {
|
|
95
91
|
return (
|
|
96
|
-
<div className="flex items-center justify-center h-screen">
|
|
92
|
+
<div className="flex items-center justify-center h-screen bg-background">
|
|
97
93
|
<div className="text-center">
|
|
98
|
-
<div className="inline-block animate-spin rounded-full h-8 w-8 border-
|
|
99
|
-
<p className="mt-
|
|
94
|
+
<div className="inline-block animate-spin rounded-full h-8 w-8 border-2 border-muted-foreground border-t-foreground"></div>
|
|
95
|
+
<p className="mt-3 text-sm text-muted-foreground">
|
|
100
96
|
加载中... ({loadedScripts.length}/{entries.length})
|
|
101
97
|
</p>
|
|
102
98
|
</div>
|
|
@@ -108,15 +104,15 @@ function RouteInitializer() {
|
|
|
108
104
|
}
|
|
109
105
|
|
|
110
106
|
createRoot(
|
|
111
|
-
document.getElementById('root')
|
|
107
|
+
document.getElementById('root')!,
|
|
112
108
|
).render(
|
|
113
109
|
<StrictMode>
|
|
114
|
-
<
|
|
110
|
+
<TooltipProvider>
|
|
115
111
|
<PersistGate loading={null} persistor={persistor}>
|
|
116
112
|
<ReduxProvider store={store}>
|
|
117
113
|
<RouteInitializer />
|
|
118
114
|
</ReduxProvider>
|
|
119
115
|
</PersistGate>
|
|
120
|
-
</
|
|
116
|
+
</TooltipProvider>
|
|
121
117
|
</StrictMode>,
|
|
122
|
-
)
|
|
118
|
+
)
|