@zhin.js/client 1.0.4 → 1.0.6
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/README.md +23 -27
- package/{src → client}/index.ts +0 -1
- package/{src → client}/store/reducers/route.ts +1 -1
- package/{src → client}/store/reducers/script.ts +1 -1
- package/{src → client}/store/reducers/ui.ts +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -0
- package/dist/router/index.d.ts +25 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +49 -0
- package/dist/router/index.js.map +1 -0
- package/dist/store/index.d.ts +19 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +67 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/reducers/config.d.ts +54 -0
- package/dist/store/reducers/config.d.ts.map +1 -0
- package/dist/store/reducers/config.js +78 -0
- package/dist/store/reducers/config.js.map +1 -0
- package/dist/store/reducers/index.d.ts +13 -0
- package/dist/store/reducers/index.d.ts.map +1 -0
- package/dist/store/reducers/index.js +11 -0
- package/dist/store/reducers/index.js.map +1 -0
- package/dist/store/reducers/route.d.ts +26 -0
- package/dist/store/reducers/route.d.ts.map +1 -0
- package/dist/store/reducers/route.js +85 -0
- package/dist/store/reducers/route.js.map +1 -0
- package/dist/store/reducers/script.d.ts +11 -0
- package/dist/store/reducers/script.d.ts.map +1 -0
- package/dist/store/reducers/script.js +74 -0
- package/dist/store/reducers/script.js.map +1 -0
- package/dist/store/reducers/ui.d.ts +8 -0
- package/dist/store/reducers/ui.d.ts.map +1 -0
- package/dist/store/reducers/ui.js +23 -0
- package/dist/store/reducers/ui.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/websocket/hooks.d.ts +55 -0
- package/dist/websocket/hooks.d.ts.map +1 -0
- package/dist/websocket/hooks.js +225 -0
- package/dist/websocket/hooks.js.map +1 -0
- package/dist/websocket/index.d.ts +13 -0
- package/dist/websocket/index.d.ts.map +1 -0
- package/dist/websocket/index.js +31 -0
- package/dist/websocket/index.js.map +1 -0
- package/dist/websocket/instance.d.ts +18 -0
- package/dist/websocket/instance.d.ts.map +1 -0
- package/dist/websocket/instance.js +39 -0
- package/dist/websocket/instance.js.map +1 -0
- package/dist/websocket/manager.d.ts +110 -0
- package/dist/websocket/manager.d.ts.map +1 -0
- package/dist/websocket/manager.js +341 -0
- package/dist/websocket/manager.js.map +1 -0
- package/dist/websocket/messageHandler.d.ts +48 -0
- package/dist/websocket/messageHandler.d.ts.map +1 -0
- package/dist/websocket/messageHandler.js +140 -0
- package/dist/websocket/messageHandler.js.map +1 -0
- package/dist/websocket/types.d.ts +125 -0
- package/dist/websocket/types.d.ts.map +1 -0
- package/dist/websocket/types.js +43 -0
- package/dist/websocket/types.js.map +1 -0
- package/package.json +12 -18
- package/app/index.html +0 -13
- package/app/postcss.config.js +0 -5
- package/app/src/components/PluginConfigForm/BasicFieldRenderers.tsx +0 -253
- package/app/src/components/PluginConfigForm/CollectionFieldRenderers.tsx +0 -261
- package/app/src/components/PluginConfigForm/CompositeFieldRenderers.tsx +0 -105
- package/app/src/components/PluginConfigForm/FieldRenderer.tsx +0 -110
- package/app/src/components/PluginConfigForm/NestedFieldRenderer.tsx +0 -95
- package/app/src/components/PluginConfigForm/index.tsx +0 -237
- package/app/src/components/PluginConfigForm/types.ts +0 -46
- package/app/src/components/ThemeToggle.tsx +0 -21
- package/app/src/hooks/useTheme.ts +0 -17
- package/app/src/layouts/dashboard.tsx +0 -259
- package/app/src/main.tsx +0 -121
- package/app/src/pages/dashboard-bots.tsx +0 -198
- package/app/src/pages/dashboard-home.tsx +0 -301
- package/app/src/pages/dashboard-logs.tsx +0 -298
- package/app/src/pages/dashboard-plugin-detail.tsx +0 -360
- package/app/src/pages/dashboard-plugins.tsx +0 -166
- package/app/src/style.css +0 -1105
- package/app/src/theme/index.ts +0 -92
- package/app/tailwind.config.js +0 -70
- package/app/tsconfig.json +0 -16
- /package/{src → client}/router/index.tsx +0 -0
- /package/{src → client}/store/index.ts +0 -0
- /package/{src → client}/store/reducers/config.ts +0 -0
- /package/{src → client}/store/reducers/index.ts +0 -0
- /package/{src → client}/types.ts +0 -0
- /package/{src → client}/websocket/hooks.ts +0 -0
- /package/{src → client}/websocket/index.ts +0 -0
- /package/{src → client}/websocket/instance.ts +0 -0
- /package/{src → client}/websocket/manager.ts +0 -0
- /package/{src → client}/websocket/messageHandler.ts +0 -0
- /package/{src → client}/websocket/types.ts +0 -0
package/app/src/main.tsx
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { StrictMode, useEffect, useState } from 'react'
|
|
2
|
-
import { createRoot } from 'react-dom/client'
|
|
3
|
-
import { Provider as ReduxProvider } from 'react-redux'
|
|
4
|
-
import { store, DynamicRouter, persistor, addPage, useSelector, Icons } from '@zhin.js/client'
|
|
5
|
-
import DashboardLayout from './layouts/dashboard'
|
|
6
|
-
import DashboardHome from './pages/dashboard-home'
|
|
7
|
-
import DashboardPlugins from './pages/dashboard-plugins'
|
|
8
|
-
import DashboardPluginDetail from './pages/dashboard-plugin-detail'
|
|
9
|
-
import DashboardBots from './pages/dashboard-bots'
|
|
10
|
-
import DashboardLogs from './pages/dashboard-logs'
|
|
11
|
-
import { Theme } from '@radix-ui/themes';
|
|
12
|
-
import '@radix-ui/themes/styles.css'
|
|
13
|
-
import './style.css'
|
|
14
|
-
import { PersistGate } from 'redux-persist/integration/react'
|
|
15
|
-
import { initializeTheme } from './theme'
|
|
16
|
-
|
|
17
|
-
// Initialize theme on app load
|
|
18
|
-
initializeTheme()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// 路由配置
|
|
22
|
-
const routes = [
|
|
23
|
-
{
|
|
24
|
-
key: 'dashboard-layout',
|
|
25
|
-
path: '/',
|
|
26
|
-
title: 'Dashboard',
|
|
27
|
-
element: <DashboardLayout />,
|
|
28
|
-
redirect: '/dashboard',
|
|
29
|
-
meta: { order: 0 },
|
|
30
|
-
children: [
|
|
31
|
-
{
|
|
32
|
-
key: 'dashboard-home',
|
|
33
|
-
index: true,
|
|
34
|
-
path: '',
|
|
35
|
-
title: '系统概览',
|
|
36
|
-
icon: <Icons.Home className="w-5 h-5" />,
|
|
37
|
-
element: <DashboardHome />,
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
key: 'dashboard-plugins',
|
|
42
|
-
path: '/plugins',
|
|
43
|
-
title: '插件管理',
|
|
44
|
-
icon: <Icons.Package className="w-5 h-5" />,
|
|
45
|
-
element: <DashboardPlugins />,
|
|
46
|
-
meta: { order: 2 }
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
key: 'dashboard-plugin-detail',
|
|
50
|
-
title: '插件详情',
|
|
51
|
-
path: '/plugins/:name',
|
|
52
|
-
element: <DashboardPluginDetail />,
|
|
53
|
-
meta: { hideInMenu: true }
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
key: 'dashboard-bots',
|
|
57
|
-
path: '/bots',
|
|
58
|
-
title: '机器人',
|
|
59
|
-
icon: <Icons.Bot className="w-5 h-5" />,
|
|
60
|
-
element: <DashboardBots />,
|
|
61
|
-
meta: { order: 3 }
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
key: 'dashboard-logs',
|
|
65
|
-
path: '/logs',
|
|
66
|
-
title: '系统日志',
|
|
67
|
-
icon: <Icons.FileText className="w-5 h-5" />,
|
|
68
|
-
element: <DashboardLogs />,
|
|
69
|
-
meta: { order: 4 }
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
// 路由初始化组件
|
|
76
|
-
function RouteInitializer() {
|
|
77
|
-
const entries = useSelector(state => state.script.entries)
|
|
78
|
-
const loadedScripts = useSelector(state => state.script.loadedScripts)
|
|
79
|
-
const [staticRoutesLoaded, setStaticRoutesLoaded] = useState(false)
|
|
80
|
-
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
// 添加静态路由
|
|
83
|
-
routes.forEach(route => {
|
|
84
|
-
addPage(route)
|
|
85
|
-
})
|
|
86
|
-
setStaticRoutesLoaded(true)
|
|
87
|
-
}, [])
|
|
88
|
-
|
|
89
|
-
// 检查是否所有脚本都已加载
|
|
90
|
-
const allScriptsLoaded = entries.length === 0 || entries.length === loadedScripts.length
|
|
91
|
-
|
|
92
|
-
// 等待静态路由和动态脚本都加载完成
|
|
93
|
-
if (!staticRoutesLoaded || !allScriptsLoaded) {
|
|
94
|
-
return (
|
|
95
|
-
<div className="flex items-center justify-center h-screen">
|
|
96
|
-
<div className="text-center">
|
|
97
|
-
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
|
|
98
|
-
<p className="mt-2 text-gray-600">
|
|
99
|
-
加载中... ({loadedScripts.length}/{entries.length})
|
|
100
|
-
</p>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return <DynamicRouter />
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
createRoot(
|
|
110
|
-
document.getElementById('root'),
|
|
111
|
-
).render(
|
|
112
|
-
<StrictMode>
|
|
113
|
-
<Theme accentColor="blue" grayColor="slate" radius="large" scaling="100%">
|
|
114
|
-
<PersistGate loading={null} persistor={persistor}>
|
|
115
|
-
<ReduxProvider store={store}>
|
|
116
|
-
<RouteInitializer />
|
|
117
|
-
</ReduxProvider>
|
|
118
|
-
</PersistGate>
|
|
119
|
-
</Theme>
|
|
120
|
-
</StrictMode>,
|
|
121
|
-
)
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
import { Bot, AlertCircle, Wifi, WifiOff, Activity, Package, Zap } from 'lucide-react'
|
|
3
|
-
import {Flex,Box,Spinner,Text,Callout,Heading,Badge,Separator,Grid,Card} from '@radix-ui/themes'
|
|
4
|
-
|
|
5
|
-
interface BotInfo {
|
|
6
|
-
name: string
|
|
7
|
-
adapter: string
|
|
8
|
-
connected: boolean
|
|
9
|
-
status: 'online' | 'offline'
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default function DashboardBots() {
|
|
13
|
-
const [bots, setBots] = useState<BotInfo[]>([])
|
|
14
|
-
const [loading, setLoading] = useState(true)
|
|
15
|
-
const [error, setError] = useState<string | null>(null)
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
fetchBots()
|
|
19
|
-
const interval = setInterval(fetchBots, 5000)
|
|
20
|
-
return () => clearInterval(interval)
|
|
21
|
-
}, [])
|
|
22
|
-
|
|
23
|
-
const fetchBots = async () => {
|
|
24
|
-
try {
|
|
25
|
-
const res = await fetch('/api/bots', { credentials: 'include' })
|
|
26
|
-
if (!res.ok) throw new Error('API 请求失败')
|
|
27
|
-
|
|
28
|
-
const data = await res.json()
|
|
29
|
-
if (data.success) {
|
|
30
|
-
setBots(data.data)
|
|
31
|
-
setError(null)
|
|
32
|
-
} else {
|
|
33
|
-
throw new Error('数据格式错误')
|
|
34
|
-
}
|
|
35
|
-
} catch (err) {
|
|
36
|
-
setError((err as Error).message)
|
|
37
|
-
} finally {
|
|
38
|
-
setLoading(false)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (loading) {
|
|
43
|
-
return (
|
|
44
|
-
<Flex align="center" justify="center" style={{ height: '100%' }}>
|
|
45
|
-
<Box>
|
|
46
|
-
<Spinner size="3" />
|
|
47
|
-
<Text size="2" color="gray" style={{ marginTop: '8px' }}>加载中...</Text>
|
|
48
|
-
</Box>
|
|
49
|
-
</Flex>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (error) {
|
|
54
|
-
return (
|
|
55
|
-
<Flex align="center" justify="center" style={{ height: '100%' }}>
|
|
56
|
-
<Callout.Root color="red">
|
|
57
|
-
<Callout.Icon>
|
|
58
|
-
<AlertCircle />
|
|
59
|
-
</Callout.Icon>
|
|
60
|
-
<Callout.Text>
|
|
61
|
-
加载失败: {error}
|
|
62
|
-
</Callout.Text>
|
|
63
|
-
</Callout.Root>
|
|
64
|
-
</Flex>
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<Box>
|
|
70
|
-
{/* 页面标题 */}
|
|
71
|
-
<Flex direction="column" gap="2" mb="6">
|
|
72
|
-
<Heading size="8">机器人管理</Heading>
|
|
73
|
-
<Flex align="center" gap="2">
|
|
74
|
-
<Text color="gray">共 {bots.length} 个机器人,</Text>
|
|
75
|
-
<Badge color="green">{bots.filter(b => b.connected).length}</Badge>
|
|
76
|
-
<Text color="gray">个在线</Text>
|
|
77
|
-
</Flex>
|
|
78
|
-
</Flex>
|
|
79
|
-
|
|
80
|
-
<Separator size="4" mb="6" />
|
|
81
|
-
|
|
82
|
-
{/* 机器人列表 */}
|
|
83
|
-
<Grid columns={{ initial: '1', sm: '2', lg: '3' }} gap="4">
|
|
84
|
-
{bots.map((bot, index) => (
|
|
85
|
-
<Card key={`${bot.adapter}-${bot.name}-${index}`}>
|
|
86
|
-
<Flex direction="column" gap="3">
|
|
87
|
-
{/* 头部 */}
|
|
88
|
-
<Flex justify="between" align="center">
|
|
89
|
-
<Flex align="center" gap="2">
|
|
90
|
-
<Box
|
|
91
|
-
style={{
|
|
92
|
-
padding: '8px',
|
|
93
|
-
borderRadius: '8px',
|
|
94
|
-
backgroundColor: bot.connected ? 'var(--green-3)' : 'var(--gray-3)'
|
|
95
|
-
}}
|
|
96
|
-
>
|
|
97
|
-
<Bot
|
|
98
|
-
size={20}
|
|
99
|
-
color={bot.connected ? 'var(--green-9)' : 'var(--gray-9)'}
|
|
100
|
-
/>
|
|
101
|
-
</Box>
|
|
102
|
-
<Text size="4" weight="bold">{bot.name}</Text>
|
|
103
|
-
</Flex>
|
|
104
|
-
|
|
105
|
-
<Box style={{ position: 'relative' }}>
|
|
106
|
-
<Badge color={bot.connected ? 'green' : 'gray'}>
|
|
107
|
-
<Flex align="center" gap="1">
|
|
108
|
-
{bot.connected ? (
|
|
109
|
-
<>
|
|
110
|
-
<Wifi size={12} />
|
|
111
|
-
在线
|
|
112
|
-
</>
|
|
113
|
-
) : (
|
|
114
|
-
<>
|
|
115
|
-
<WifiOff size={12} />
|
|
116
|
-
离线
|
|
117
|
-
</>
|
|
118
|
-
)}
|
|
119
|
-
</Flex>
|
|
120
|
-
</Badge>
|
|
121
|
-
{bot.connected && (
|
|
122
|
-
<Box
|
|
123
|
-
style={{
|
|
124
|
-
position: 'absolute',
|
|
125
|
-
top: '-4px',
|
|
126
|
-
right: '-4px',
|
|
127
|
-
width: '8px',
|
|
128
|
-
height: '8px',
|
|
129
|
-
borderRadius: '50%',
|
|
130
|
-
backgroundColor: 'var(--green-9)',
|
|
131
|
-
animation: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite'
|
|
132
|
-
}}
|
|
133
|
-
/>
|
|
134
|
-
)}
|
|
135
|
-
</Box>
|
|
136
|
-
</Flex>
|
|
137
|
-
|
|
138
|
-
{/* 适配器信息 */}
|
|
139
|
-
<Flex align="center" gap="2">
|
|
140
|
-
<Text size="2" color="gray">适配器:</Text>
|
|
141
|
-
<Badge variant="outline">{bot.adapter}</Badge>
|
|
142
|
-
</Flex>
|
|
143
|
-
|
|
144
|
-
<Separator size="4" />
|
|
145
|
-
|
|
146
|
-
{/* 详细信息 */}
|
|
147
|
-
<Flex direction="column" gap="2">
|
|
148
|
-
<Flex justify="between" align="center" p="2" style={{ borderRadius: '6px', backgroundColor: 'var(--gray-2)' }}>
|
|
149
|
-
<Flex align="center" gap="2">
|
|
150
|
-
<Activity
|
|
151
|
-
size={16}
|
|
152
|
-
color={bot.status === 'online' ? 'var(--green-9)' : 'var(--gray-9)'}
|
|
153
|
-
/>
|
|
154
|
-
<Text size="2" color="gray">运行状态</Text>
|
|
155
|
-
</Flex>
|
|
156
|
-
<Badge color={bot.status === 'online' ? 'green' : 'gray'}>
|
|
157
|
-
{bot.status === 'online' ? '运行中' : '已停止'}
|
|
158
|
-
</Badge>
|
|
159
|
-
</Flex>
|
|
160
|
-
|
|
161
|
-
<Flex justify="between" align="center" p="2" style={{ borderRadius: '6px', backgroundColor: 'var(--gray-2)' }}>
|
|
162
|
-
<Flex align="center" gap="2">
|
|
163
|
-
<Package size={16} color="var(--blue-9)" />
|
|
164
|
-
<Text size="2" color="gray">适配器类型</Text>
|
|
165
|
-
</Flex>
|
|
166
|
-
<Text size="2" weight="medium">{bot.adapter}</Text>
|
|
167
|
-
</Flex>
|
|
168
|
-
|
|
169
|
-
<Flex justify="between" align="center" p="2" style={{ borderRadius: '6px', backgroundColor: 'var(--gray-2)' }}>
|
|
170
|
-
<Flex align="center" gap="2">
|
|
171
|
-
<Zap size={16} color="var(--purple-9)" />
|
|
172
|
-
<Text size="2" color="gray">连接状态</Text>
|
|
173
|
-
</Flex>
|
|
174
|
-
<Text size="2" weight="medium" color={bot.connected ? 'green' : 'gray'}>
|
|
175
|
-
{bot.connected ? '已连接' : '未连接'}
|
|
176
|
-
</Text>
|
|
177
|
-
</Flex>
|
|
178
|
-
</Flex>
|
|
179
|
-
</Flex>
|
|
180
|
-
</Card>
|
|
181
|
-
))}
|
|
182
|
-
</Grid>
|
|
183
|
-
|
|
184
|
-
{/* 空状态 */}
|
|
185
|
-
{bots.length === 0 && (
|
|
186
|
-
<Card>
|
|
187
|
-
<Flex direction="column" align="center" gap="4" py="9">
|
|
188
|
-
<Bot size={64} color="var(--gray-6)" />
|
|
189
|
-
<Flex direction="column" align="center" gap="2">
|
|
190
|
-
<Heading size="4">暂无机器人</Heading>
|
|
191
|
-
<Text color="gray">请先配置并启动机器人</Text>
|
|
192
|
-
</Flex>
|
|
193
|
-
</Flex>
|
|
194
|
-
</Card>
|
|
195
|
-
)}
|
|
196
|
-
</Box>
|
|
197
|
-
)
|
|
198
|
-
}
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
import { useNavigate } from 'react-router'
|
|
3
|
-
import {Flex,Box,Spinner,Text,Callout,Heading,Badge,Grid,Card,Button} from '@radix-ui/themes'
|
|
4
|
-
import { Bot, AlertCircle, Activity, Package, Clock, Cpu, MemoryStick, FileText, TrendingUp } from 'lucide-react'
|
|
5
|
-
|
|
6
|
-
interface Stats {
|
|
7
|
-
plugins: { total: number; active: number }
|
|
8
|
-
bots: { total: number; online: number }
|
|
9
|
-
commands: number
|
|
10
|
-
components: number
|
|
11
|
-
uptime: number
|
|
12
|
-
memory: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface SystemStatus {
|
|
16
|
-
uptime: number
|
|
17
|
-
memory: {
|
|
18
|
-
rss: number
|
|
19
|
-
heapTotal: number
|
|
20
|
-
heapUsed: number
|
|
21
|
-
external: number
|
|
22
|
-
}
|
|
23
|
-
cpu: {
|
|
24
|
-
user: number
|
|
25
|
-
system: number
|
|
26
|
-
}
|
|
27
|
-
platform: string
|
|
28
|
-
nodeVersion: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default function DashboardHome() {
|
|
32
|
-
const navigate = useNavigate()
|
|
33
|
-
const [stats, setStats] = useState<Stats | null>(null)
|
|
34
|
-
const [systemStatus, setSystemStatus] = useState<SystemStatus | null>(null)
|
|
35
|
-
const [loading, setLoading] = useState(true)
|
|
36
|
-
const [error, setError] = useState<string | null>(null)
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
fetchData()
|
|
40
|
-
const interval = setInterval(fetchData, 5000)
|
|
41
|
-
return () => clearInterval(interval)
|
|
42
|
-
}, [])
|
|
43
|
-
|
|
44
|
-
const fetchData = async () => {
|
|
45
|
-
try {
|
|
46
|
-
const [statsRes, statusRes] = await Promise.all([
|
|
47
|
-
fetch('/api/stats', { credentials: 'include' }),
|
|
48
|
-
fetch('/api/system/status', { credentials: 'include' })
|
|
49
|
-
])
|
|
50
|
-
|
|
51
|
-
if (!statsRes.ok || !statusRes.ok) throw new Error('API 请求失败')
|
|
52
|
-
|
|
53
|
-
const statsData = await statsRes.json()
|
|
54
|
-
const statusData = await statusRes.json()
|
|
55
|
-
|
|
56
|
-
if (statsData.success && statusData.success) {
|
|
57
|
-
setStats(statsData.data)
|
|
58
|
-
setSystemStatus(statusData.data)
|
|
59
|
-
setError(null)
|
|
60
|
-
}
|
|
61
|
-
} catch (err) {
|
|
62
|
-
setError((err as Error).message)
|
|
63
|
-
} finally {
|
|
64
|
-
setLoading(false)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const formatUptime = (seconds: number) => {
|
|
69
|
-
const days = Math.floor(seconds / 86400)
|
|
70
|
-
const hours = Math.floor((seconds % 86400) / 3600)
|
|
71
|
-
const minutes = Math.floor((seconds % 3600) / 60)
|
|
72
|
-
return `${days}天 ${hours}小时 ${minutes}分钟`
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const formatMemory = (bytes: number) => {
|
|
76
|
-
return `${(bytes / 1024 / 1024).toFixed(2)} MB`
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (loading) {
|
|
80
|
-
return (
|
|
81
|
-
<Flex align="center" justify="center" style={{ height: '100%' }}>
|
|
82
|
-
<Box>
|
|
83
|
-
<Spinner size="3" />
|
|
84
|
-
<Text size="2" color="gray" style={{ marginTop: '8px' }}>加载中...</Text>
|
|
85
|
-
</Box>
|
|
86
|
-
</Flex>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (error) {
|
|
91
|
-
return (
|
|
92
|
-
<Flex align="center" justify="center" style={{ height: '100%' }}>
|
|
93
|
-
<Callout.Root color="red">
|
|
94
|
-
<Callout.Icon>
|
|
95
|
-
<AlertCircle />
|
|
96
|
-
</Callout.Icon>
|
|
97
|
-
<Callout.Text>
|
|
98
|
-
加载失败: {error}
|
|
99
|
-
</Callout.Text>
|
|
100
|
-
</Callout.Root>
|
|
101
|
-
</Flex>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<Box>
|
|
107
|
-
{/* 页面标题 */}
|
|
108
|
-
<Flex direction="column" gap="2" mb="6">
|
|
109
|
-
<Heading size="8">系统概览</Heading>
|
|
110
|
-
<Text color="gray">实时监控您的机器人框架运行状态</Text>
|
|
111
|
-
</Flex>
|
|
112
|
-
|
|
113
|
-
{/* 统计卡片 */}
|
|
114
|
-
<Grid columns={{ initial: '1', sm: '2', lg: '4' }} gap="4" mb="6">
|
|
115
|
-
<Card>
|
|
116
|
-
<Flex direction="column" gap="2">
|
|
117
|
-
<Flex justify="between" align="center">
|
|
118
|
-
<Text size="2" weight="medium" color="gray">插件总数</Text>
|
|
119
|
-
<Box p="2" style={{ borderRadius: '8px', backgroundColor: 'var(--purple-3)' }}>
|
|
120
|
-
<Package size={16} color="var(--purple-9)" />
|
|
121
|
-
</Box>
|
|
122
|
-
</Flex>
|
|
123
|
-
<Heading size="7">{stats?.plugins.total || 0}</Heading>
|
|
124
|
-
<Flex align="center" gap="1">
|
|
125
|
-
<Badge color="blue">{stats?.plugins.active || 0}</Badge>
|
|
126
|
-
<Text size="1" color="gray">个活跃</Text>
|
|
127
|
-
</Flex>
|
|
128
|
-
</Flex>
|
|
129
|
-
</Card>
|
|
130
|
-
|
|
131
|
-
<Card>
|
|
132
|
-
<Flex direction="column" gap="2">
|
|
133
|
-
<Flex justify="between" align="center">
|
|
134
|
-
<Text size="2" weight="medium" color="gray">机器人</Text>
|
|
135
|
-
<Bot size={16} color="var(--gray-9)" />
|
|
136
|
-
</Flex>
|
|
137
|
-
<Heading size="7">{stats?.bots.total || 0}</Heading>
|
|
138
|
-
<Text size="1" color="green">
|
|
139
|
-
{stats?.bots.online || 0} 个在线
|
|
140
|
-
</Text>
|
|
141
|
-
</Flex>
|
|
142
|
-
</Card>
|
|
143
|
-
|
|
144
|
-
<Card>
|
|
145
|
-
<Flex direction="column" gap="2">
|
|
146
|
-
<Flex justify="between" align="center">
|
|
147
|
-
<Text size="2" weight="medium" color="gray">命令数量</Text>
|
|
148
|
-
<Activity size={16} color="var(--gray-9)" />
|
|
149
|
-
</Flex>
|
|
150
|
-
<Heading size="7">{stats?.commands || 0}</Heading>
|
|
151
|
-
<Text size="1" color="gray">可用命令</Text>
|
|
152
|
-
</Flex>
|
|
153
|
-
</Card>
|
|
154
|
-
|
|
155
|
-
<Card>
|
|
156
|
-
<Flex direction="column" gap="2">
|
|
157
|
-
<Flex justify="between" align="center">
|
|
158
|
-
<Text size="2" weight="medium" color="gray">组件数量</Text>
|
|
159
|
-
<TrendingUp size={16} color="var(--gray-9)" />
|
|
160
|
-
</Flex>
|
|
161
|
-
<Heading size="7">{stats?.components || 0}</Heading>
|
|
162
|
-
<Text size="1" color="gray">已注册组件</Text>
|
|
163
|
-
</Flex>
|
|
164
|
-
</Card>
|
|
165
|
-
</Grid>
|
|
166
|
-
|
|
167
|
-
{/* 系统状态 */}
|
|
168
|
-
<Grid columns={{ initial: '1', md: '2' }} gap="4" mb="6">
|
|
169
|
-
<Card>
|
|
170
|
-
<Flex direction="column" gap="4">
|
|
171
|
-
<Box>
|
|
172
|
-
<Heading size="5" mb="1">系统信息</Heading>
|
|
173
|
-
<Text size="2" color="gray">服务器运行状态</Text>
|
|
174
|
-
</Box>
|
|
175
|
-
|
|
176
|
-
<Flex direction="column" gap="3">
|
|
177
|
-
<Flex justify="between" align="center">
|
|
178
|
-
<Flex align="center" gap="2">
|
|
179
|
-
<Clock size={16} color="var(--gray-9)" />
|
|
180
|
-
<Text size="2">运行时间</Text>
|
|
181
|
-
</Flex>
|
|
182
|
-
<Badge variant="soft">
|
|
183
|
-
{systemStatus ? formatUptime(systemStatus.uptime) : '-'}
|
|
184
|
-
</Badge>
|
|
185
|
-
</Flex>
|
|
186
|
-
|
|
187
|
-
<Flex justify="between" align="center">
|
|
188
|
-
<Flex align="center" gap="2">
|
|
189
|
-
<Cpu size={16} color="var(--gray-9)" />
|
|
190
|
-
<Text size="2">平台</Text>
|
|
191
|
-
</Flex>
|
|
192
|
-
<Badge variant="soft">
|
|
193
|
-
{systemStatus?.platform || '-'}
|
|
194
|
-
</Badge>
|
|
195
|
-
</Flex>
|
|
196
|
-
|
|
197
|
-
<Flex justify="between" align="center">
|
|
198
|
-
<Flex align="center" gap="2">
|
|
199
|
-
<Activity size={16} color="var(--gray-9)" />
|
|
200
|
-
<Text size="2">Node 版本</Text>
|
|
201
|
-
</Flex>
|
|
202
|
-
<Badge variant="soft">
|
|
203
|
-
{systemStatus?.nodeVersion || '-'}
|
|
204
|
-
</Badge>
|
|
205
|
-
</Flex>
|
|
206
|
-
</Flex>
|
|
207
|
-
</Flex>
|
|
208
|
-
</Card>
|
|
209
|
-
|
|
210
|
-
<Card>
|
|
211
|
-
<Flex direction="column" gap="4">
|
|
212
|
-
<Box>
|
|
213
|
-
<Heading size="5" mb="1">资源使用</Heading>
|
|
214
|
-
<Text size="2" color="gray">内存使用情况</Text>
|
|
215
|
-
</Box>
|
|
216
|
-
|
|
217
|
-
<Flex direction="column" gap="3">
|
|
218
|
-
<Flex justify="between" align="center">
|
|
219
|
-
<Flex align="center" gap="2">
|
|
220
|
-
<MemoryStick size={16} color="var(--gray-9)" />
|
|
221
|
-
<Text size="2">堆内存使用</Text>
|
|
222
|
-
</Flex>
|
|
223
|
-
<Badge variant="soft">
|
|
224
|
-
{stats ? `${stats.memory.toFixed(2)} MB` : '-'}
|
|
225
|
-
</Badge>
|
|
226
|
-
</Flex>
|
|
227
|
-
|
|
228
|
-
<Flex justify="between" align="center">
|
|
229
|
-
<Flex align="center" gap="2">
|
|
230
|
-
<MemoryStick size={16} color="var(--gray-9)" />
|
|
231
|
-
<Text size="2">总堆内存</Text>
|
|
232
|
-
</Flex>
|
|
233
|
-
<Badge variant="soft">
|
|
234
|
-
{systemStatus ? formatMemory(systemStatus.memory.heapTotal) : '-'}
|
|
235
|
-
</Badge>
|
|
236
|
-
</Flex>
|
|
237
|
-
|
|
238
|
-
<Flex justify="between" align="center">
|
|
239
|
-
<Flex align="center" gap="2">
|
|
240
|
-
<MemoryStick size={16} color="var(--gray-9)" />
|
|
241
|
-
<Text size="2">RSS</Text>
|
|
242
|
-
</Flex>
|
|
243
|
-
<Badge variant="soft">
|
|
244
|
-
{systemStatus ? formatMemory(systemStatus.memory.rss) : '-'}
|
|
245
|
-
</Badge>
|
|
246
|
-
</Flex>
|
|
247
|
-
</Flex>
|
|
248
|
-
</Flex>
|
|
249
|
-
</Card>
|
|
250
|
-
</Grid>
|
|
251
|
-
|
|
252
|
-
{/* 快速操作 */}
|
|
253
|
-
<Card>
|
|
254
|
-
<Flex direction="column" gap="4">
|
|
255
|
-
<Box>
|
|
256
|
-
<Heading size="5" mb="1">快速操作</Heading>
|
|
257
|
-
<Text size="2" color="gray">常用功能快捷入口</Text>
|
|
258
|
-
</Box>
|
|
259
|
-
|
|
260
|
-
<Grid columns={{ initial: '1', md: '3' }} gap="3">
|
|
261
|
-
<Button
|
|
262
|
-
variant="outline"
|
|
263
|
-
onClick={() => navigate('/plugins')}
|
|
264
|
-
style={{ height: 'auto', padding: '16px', cursor: 'pointer' }}
|
|
265
|
-
>
|
|
266
|
-
<Flex direction="column" align="start" gap="2" style={{ width: '100%' }}>
|
|
267
|
-
<Package size={20} color="var(--blue-9)" />
|
|
268
|
-
<Text weight="medium">插件管理</Text>
|
|
269
|
-
<Text size="1" color="gray">查看和管理插件</Text>
|
|
270
|
-
</Flex>
|
|
271
|
-
</Button>
|
|
272
|
-
|
|
273
|
-
<Button
|
|
274
|
-
variant="outline"
|
|
275
|
-
onClick={() => navigate('/bots')}
|
|
276
|
-
style={{ height: 'auto', padding: '16px', cursor: 'pointer' }}
|
|
277
|
-
>
|
|
278
|
-
<Flex direction="column" align="start" gap="2" style={{ width: '100%' }}>
|
|
279
|
-
<Bot size={20} color="var(--green-9)" />
|
|
280
|
-
<Text weight="medium">机器人状态</Text>
|
|
281
|
-
<Text size="1" color="gray">监控机器人运行</Text>
|
|
282
|
-
</Flex>
|
|
283
|
-
</Button>
|
|
284
|
-
|
|
285
|
-
<Button
|
|
286
|
-
variant="outline"
|
|
287
|
-
onClick={() => navigate('/logs')}
|
|
288
|
-
style={{ height: 'auto', padding: '16px', cursor: 'pointer' }}
|
|
289
|
-
>
|
|
290
|
-
<Flex direction="column" align="start" gap="2" style={{ width: '100%' }}>
|
|
291
|
-
<FileText size={20} color="var(--purple-9)" />
|
|
292
|
-
<Text weight="medium">系统日志</Text>
|
|
293
|
-
<Text size="1" color="gray">查看运行日志</Text>
|
|
294
|
-
</Flex>
|
|
295
|
-
</Button>
|
|
296
|
-
</Grid>
|
|
297
|
-
</Flex>
|
|
298
|
-
</Card>
|
|
299
|
-
</Box>
|
|
300
|
-
)
|
|
301
|
-
}
|