@zhin.js/client 1.0.4 → 1.0.5

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.
Files changed (97) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/router/index.d.ts +25 -0
  5. package/dist/router/index.d.ts.map +1 -0
  6. package/dist/router/index.js +49 -0
  7. package/dist/router/index.js.map +1 -0
  8. package/dist/store/index.d.ts +19 -0
  9. package/dist/store/index.d.ts.map +1 -0
  10. package/dist/store/index.js +67 -0
  11. package/dist/store/index.js.map +1 -0
  12. package/dist/store/reducers/config.d.ts +54 -0
  13. package/dist/store/reducers/config.d.ts.map +1 -0
  14. package/dist/store/reducers/config.js +78 -0
  15. package/dist/store/reducers/config.js.map +1 -0
  16. package/dist/store/reducers/index.d.ts +13 -0
  17. package/dist/store/reducers/index.d.ts.map +1 -0
  18. package/dist/store/reducers/index.js +11 -0
  19. package/dist/store/reducers/index.js.map +1 -0
  20. package/dist/store/reducers/route.d.ts +37 -0
  21. package/dist/store/reducers/route.d.ts.map +1 -0
  22. package/dist/store/reducers/route.js +85 -0
  23. package/dist/store/reducers/route.js.map +1 -0
  24. package/dist/store/reducers/script.d.ts +17 -0
  25. package/dist/store/reducers/script.d.ts.map +1 -0
  26. package/dist/store/reducers/script.js +74 -0
  27. package/dist/store/reducers/script.js.map +1 -0
  28. package/dist/store/reducers/ui.d.ts +14 -0
  29. package/dist/store/reducers/ui.d.ts.map +1 -0
  30. package/dist/store/reducers/ui.js +23 -0
  31. package/dist/store/reducers/ui.js.map +1 -0
  32. package/dist/types.d.ts +7 -0
  33. package/dist/types.d.ts.map +1 -0
  34. package/dist/types.js +2 -0
  35. package/dist/types.js.map +1 -0
  36. package/dist/websocket/hooks.d.ts +55 -0
  37. package/dist/websocket/hooks.d.ts.map +1 -0
  38. package/dist/websocket/hooks.js +225 -0
  39. package/dist/websocket/hooks.js.map +1 -0
  40. package/dist/websocket/index.d.ts +13 -0
  41. package/dist/websocket/index.d.ts.map +1 -0
  42. package/dist/websocket/index.js +31 -0
  43. package/dist/websocket/index.js.map +1 -0
  44. package/dist/websocket/instance.d.ts +18 -0
  45. package/dist/websocket/instance.d.ts.map +1 -0
  46. package/dist/websocket/instance.js +39 -0
  47. package/dist/websocket/instance.js.map +1 -0
  48. package/dist/websocket/manager.d.ts +110 -0
  49. package/dist/websocket/manager.d.ts.map +1 -0
  50. package/dist/websocket/manager.js +341 -0
  51. package/dist/websocket/manager.js.map +1 -0
  52. package/dist/websocket/messageHandler.d.ts +48 -0
  53. package/dist/websocket/messageHandler.d.ts.map +1 -0
  54. package/dist/websocket/messageHandler.js +140 -0
  55. package/dist/websocket/messageHandler.js.map +1 -0
  56. package/dist/websocket/types.d.ts +125 -0
  57. package/dist/websocket/types.d.ts.map +1 -0
  58. package/dist/websocket/types.js +43 -0
  59. package/dist/websocket/types.js.map +1 -0
  60. package/package.json +8 -18
  61. package/app/index.html +0 -13
  62. package/app/postcss.config.js +0 -5
  63. package/app/src/components/PluginConfigForm/BasicFieldRenderers.tsx +0 -253
  64. package/app/src/components/PluginConfigForm/CollectionFieldRenderers.tsx +0 -261
  65. package/app/src/components/PluginConfigForm/CompositeFieldRenderers.tsx +0 -105
  66. package/app/src/components/PluginConfigForm/FieldRenderer.tsx +0 -110
  67. package/app/src/components/PluginConfigForm/NestedFieldRenderer.tsx +0 -95
  68. package/app/src/components/PluginConfigForm/index.tsx +0 -237
  69. package/app/src/components/PluginConfigForm/types.ts +0 -46
  70. package/app/src/components/ThemeToggle.tsx +0 -21
  71. package/app/src/hooks/useTheme.ts +0 -17
  72. package/app/src/layouts/dashboard.tsx +0 -259
  73. package/app/src/main.tsx +0 -121
  74. package/app/src/pages/dashboard-bots.tsx +0 -198
  75. package/app/src/pages/dashboard-home.tsx +0 -301
  76. package/app/src/pages/dashboard-logs.tsx +0 -298
  77. package/app/src/pages/dashboard-plugin-detail.tsx +0 -360
  78. package/app/src/pages/dashboard-plugins.tsx +0 -166
  79. package/app/src/style.css +0 -1105
  80. package/app/src/theme/index.ts +0 -92
  81. package/app/tailwind.config.js +0 -70
  82. package/app/tsconfig.json +0 -16
  83. /package/{src → client}/index.ts +0 -0
  84. /package/{src → client}/router/index.tsx +0 -0
  85. /package/{src → client}/store/index.ts +0 -0
  86. /package/{src → client}/store/reducers/config.ts +0 -0
  87. /package/{src → client}/store/reducers/index.ts +0 -0
  88. /package/{src → client}/store/reducers/route.ts +0 -0
  89. /package/{src → client}/store/reducers/script.ts +0 -0
  90. /package/{src → client}/store/reducers/ui.ts +0 -0
  91. /package/{src → client}/types.ts +0 -0
  92. /package/{src → client}/websocket/hooks.ts +0 -0
  93. /package/{src → client}/websocket/index.ts +0 -0
  94. /package/{src → client}/websocket/instance.ts +0 -0
  95. /package/{src → client}/websocket/manager.ts +0 -0
  96. /package/{src → client}/websocket/messageHandler.ts +0 -0
  97. /package/{src → client}/websocket/types.ts +0 -0
@@ -1,259 +0,0 @@
1
- import { Outlet, Link, useSelector, useDispatch, toggleSidebar, setActiveMenu, useWebSocket } from "@zhin.js/client"
2
- import React, { useMemo } from "react"
3
- import { Avatar, DropdownMenu } from 'radix-ui'
4
- import * as Themes from '@radix-ui/themes'
5
- import { Icons, cn } from "@zhin.js/client"
6
- import { ThemeToggle } from "../components/ThemeToggle"
7
-
8
- const { Box, Flex, Text, Heading, IconButton, Badge, TextField, ScrollArea, Container } = Themes
9
-
10
- export default function DashboardLayout() {
11
- const dispatch = useDispatch()
12
- const ws = useWebSocket()
13
- const sidebarOpen = useSelector(state => state.ui.sidebarOpen)
14
- const activeMenu = useSelector(state => state.ui.activeMenu)
15
- const routes = useSelector(state => state.route.routes)
16
-
17
- const menuItems = useMemo(() => {
18
- // 找到 dashboard 路由
19
- const dashboardRoute = routes.find(route => route.key === 'dashboard-layout')
20
- if (!dashboardRoute || !dashboardRoute.children) {
21
- return []
22
- }
23
- return dashboardRoute.children
24
- .filter(route => !route.meta?.hideInMenu && route.key !== 'dashboard-layout')
25
- .map((route, index) => ({
26
- key: route.key || `menu-item-${index}`,
27
- title: route.title,
28
- index: route.index,
29
- icon: route.icon,
30
- href: route.path
31
- }))
32
- }, [routes])
33
-
34
- return (
35
- <Flex className="h-screen bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800">
36
- {/* 侧边栏 */}
37
- <Flex
38
- direction="column"
39
- className={cn(
40
- "glass transition-all duration-300 shadow-xl border-r border-gray-200/50 dark:border-gray-700/50",
41
- sidebarOpen ? "w-64" : "w-20"
42
- )}
43
- >
44
- {/* Logo 区域 */}
45
- <Box p="4" className="border-b border-gray-200/50 dark:border-gray-700/50">
46
- <Flex
47
- align="center"
48
- className={cn(
49
- "transition-all duration-300",
50
- sidebarOpen ? "gap-3" : "justify-center"
51
- )}
52
- >
53
- <Flex
54
- align="center"
55
- justify="center"
56
- className="w-11 min-w-11 h-11 rounded-xl shadow-md bg-gradient-to-br from-blue-500 to-purple-600"
57
- >
58
- <Text size="5" weight="bold" className="text-white">
59
- Z
60
- </Text>
61
- </Flex>
62
- {sidebarOpen && (
63
- <Flex direction="column" gap="0">
64
- <Heading size="4" className="text-gray-900 dark:text-gray-100">
65
- Zhin.js
66
- </Heading>
67
- <Text size="1" color="gray">管理控制台</Text>
68
- </Flex>
69
- )}
70
- </Flex>
71
- </Box>
72
-
73
- {/* 菜单列表 */}
74
- <ScrollArea className="flex-1" scrollbars="vertical">
75
- <Box p="3">
76
- <Flex direction="column" gap="2">
77
- {menuItems.map((item) => {
78
- const isActive = activeMenu === item.key
79
- return (
80
- <Link
81
- key={item.key}
82
- to={item.href}
83
- onClick={() => dispatch(setActiveMenu(item.key))}
84
- className={cn("menu-item", isActive && "active")}
85
- >
86
- {item.icon && React.isValidElement(item.icon) && (
87
- <div className="icon">
88
- {item.icon}
89
- </div>
90
- )}
91
- {sidebarOpen && (
92
- <div className="text">
93
- <div className="title">{item.title}</div>
94
- </div>
95
- )}
96
- {isActive && sidebarOpen && <div className="indicator" />}
97
- </Link>
98
- )
99
- })}
100
- </Flex>
101
- </Box>
102
- </ScrollArea>
103
-
104
- {/* 侧边栏底部用户信息 */}
105
- <Flex p="3" className="border-t border-gray-200/50 dark:border-gray-700/50 flex-shrink-0">
106
- <Flex
107
- align="center"
108
- gap="2"
109
- p="2"
110
- className={cn(
111
- "rounded-xl bg-gray-50/50 dark:bg-gray-800/50 transition-all duration-200 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700",
112
- !sidebarOpen && "justify-center"
113
- )}
114
- >
115
- <Avatar.Root className="w-8 h-8 min-w-8 border-2 border-gray-200 dark:border-gray-700 flex-shrink-0">
116
- <Avatar.Image src="https://i.pravatar.cc/150?u=admin" alt="管理员" />
117
- <Avatar.Fallback>管</Avatar.Fallback>
118
- </Avatar.Root>
119
- {sidebarOpen && (
120
- <Flex direction="column" gap="0" className="flex-1 min-w-0">
121
- <Text size="2" weight="medium" className="truncate text-gray-900 dark:text-gray-100">
122
- 管理员
123
- </Text>
124
- <Text size="1" color="gray" className="truncate">
125
- admin@zhin.com
126
- </Text>
127
- </Flex>
128
- )}
129
- </Flex>
130
- </Flex>
131
- </Flex>
132
-
133
- {/* 主内容区域 */}
134
- <Flex direction="column" className="flex-1 overflow-hidden">
135
- {/* 顶部导航栏 */}
136
- <Box className="glass border-b border-gray-200/50 dark:border-gray-700/50 shadow-sm">
137
- <Flex justify="between" align="center" px="4" className="h-16">
138
- {/* 左侧 */}
139
- <Flex align="center" gap="3">
140
- <IconButton
141
- variant="ghost"
142
- size="2"
143
- onClick={() => dispatch(toggleSidebar())}
144
- className="hover-lift rounded-xl"
145
- >
146
- <Icons.Menu className="w-5 h-5" />
147
- </IconButton>
148
- <Flex direction="column" gap="0">
149
- <Heading size="3" className="text-gray-900 dark:text-gray-100">控制台</Heading>
150
- <Text size="1" color="gray">欢迎回来!</Text>
151
- </Flex>
152
- </Flex>
153
-
154
- {/* 中间搜索栏 */}
155
- <Flex className="hidden md:flex flex-1 max-w-xl mx-6">
156
- <Box className="relative">
157
- <Icons.Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 dark:text-gray-500" />
158
- <TextField.Root
159
- placeholder="搜索功能、用户、设置..."
160
- size="2"
161
- className="w-full pl-10"
162
- />
163
- </Box>
164
- </Flex>
165
-
166
- {/* 右侧操作区 */}
167
- <Flex align="center" gap="2">
168
- {/* 主题切换 */}
169
- <ThemeToggle />
170
-
171
- {/* 通知按钮 */}
172
- <Box className="relative">
173
- <IconButton
174
- variant="ghost"
175
- size="2"
176
- className="hover-lift rounded-xl"
177
- >
178
- <Icons.Bell className="w-5 h-5" />
179
- </IconButton>
180
- <Badge
181
- color="red"
182
- variant="solid"
183
- size="1"
184
- className="absolute -top-1 -right-1 min-w-5 h-5 flex items-center justify-center p-0"
185
- >
186
- 3
187
- </Badge>
188
- </Box>
189
-
190
- {/* 用户菜单 */}
191
- <DropdownMenu.Root>
192
- <DropdownMenu.Trigger asChild>
193
- <Flex
194
- align="center"
195
- gap="2"
196
- px="2"
197
- py="1"
198
- className="cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition-all duration-200 rounded-xl"
199
- >
200
- <Avatar.Root className="w-8 h-8 border-2 border-blue-500/20 dark:border-blue-400/30">
201
- <Avatar.Image src="https://i.pravatar.cc/150?u=admin" alt="管理员" />
202
- <Avatar.Fallback>管</Avatar.Fallback>
203
- </Avatar.Root>
204
- <Flex direction="column" gap="0" className="hidden lg:flex">
205
- <Text size="2" weight="medium" className="text-gray-900 dark:text-gray-100">
206
- 管理员
207
- </Text>
208
- <Text size="1" color="gray">
209
- admin@zhin.com
210
- </Text>
211
- </Flex>
212
- </Flex>
213
- </DropdownMenu.Trigger>
214
- <DropdownMenu.Content align="end" className="min-w-56">
215
- <Box p="3" className="border-b border-gray-200 dark:border-gray-700">
216
- <Text size="2" weight="bold" className="block">
217
- 登录为
218
- </Text>
219
- <Text size="1" color="gray" className="block">
220
- admin@zhin.com
221
- </Text>
222
- </Box>
223
- <DropdownMenu.Item>
224
- <Icons.User className="mr-2 h-4 w-4" />
225
- 我的设置
226
- </DropdownMenu.Item>
227
- <DropdownMenu.Item>
228
- <Icons.Users className="mr-2 h-4 w-4" />
229
- 团队设置
230
- </DropdownMenu.Item>
231
- <DropdownMenu.Item>
232
- <Icons.BarChart3 className="mr-2 h-4 w-4" />
233
- 数据分析
234
- </DropdownMenu.Item>
235
- <DropdownMenu.Item>
236
- <Icons.HelpCircle className="mr-2 h-4 w-4" />
237
- 帮助与反馈
238
- </DropdownMenu.Item>
239
- <DropdownMenu.Separator />
240
- <DropdownMenu.Item color="red">
241
- <Icons.LogOut className="mr-2 h-4 w-4" />
242
- 退出登录
243
- </DropdownMenu.Item>
244
- </DropdownMenu.Content>
245
- </DropdownMenu.Root>
246
- </Flex>
247
- </Flex>
248
- </Box>
249
-
250
- {/* 主内容区域 */}
251
- <Flex className="flex-1 overflow-auto">
252
- <Container size="4" p="6">
253
- <Outlet />
254
- </Container>
255
- </Flex>
256
- </Flex>
257
- </Flex>
258
- )
259
- }
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
- }