mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 19:04:23 +08:00
feat: 实现依赖注入系统、插件架构和窗口管理
- 引入ExamAware的DI系统并适配SecScore项目 - 添加服务注册表和窗口管理器 - 实现基于Koishi的Disposable设计的插件系统 - 集成Winston日志服务 - 分离设置窗口为独立页面 - 将非核心功能改为内置插件 - 更新README文件 - 添加相关hooks和工具函数
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
import React from "react"
|
||||
import { Card, List, Button, Tag, Space, Typography, Spin, Empty, message } from "antd"
|
||||
import {
|
||||
ThunderboltOutlined,
|
||||
DashboardOutlined,
|
||||
HistoryOutlined,
|
||||
CloudOutlined,
|
||||
CheckCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
DownloadOutlined,
|
||||
DeleteOutlined,
|
||||
} from "@ant-design/icons"
|
||||
import { useBuiltinPlugins } from "../hooks/useBuiltinPlugins"
|
||||
import { BuiltinPluginMeta } from "../plugins/builtin"
|
||||
|
||||
const { Title, Text, Paragraph } = Typography
|
||||
|
||||
const categoryIcons: Record<string, React.ReactNode> = {
|
||||
automation: <ThunderboltOutlined />,
|
||||
visualization: <DashboardOutlined />,
|
||||
management: <HistoryOutlined />,
|
||||
integration: <CloudOutlined />,
|
||||
}
|
||||
|
||||
const categoryLabels: Record<string, string> = {
|
||||
automation: "自动化",
|
||||
visualization: "可视化",
|
||||
management: "管理",
|
||||
integration: "集成",
|
||||
}
|
||||
|
||||
interface BuiltinPluginManagerProps {
|
||||
canEdit: boolean
|
||||
}
|
||||
|
||||
export const BuiltinPluginManager: React.FC<BuiltinPluginManagerProps> = ({ canEdit }) => {
|
||||
const { plugins, loading, install, uninstall, enable, disable } = useBuiltinPlugins()
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
|
||||
const handleInstall = async (pluginId: string) => {
|
||||
try {
|
||||
await install(pluginId)
|
||||
messageApi.success("插件安装成功")
|
||||
} catch (error) {
|
||||
messageApi.error("插件安装失败")
|
||||
}
|
||||
}
|
||||
|
||||
const handleUninstall = async (pluginId: string) => {
|
||||
try {
|
||||
await uninstall(pluginId)
|
||||
messageApi.success("插件已卸载")
|
||||
} catch (error) {
|
||||
messageApi.error("插件卸载失败")
|
||||
}
|
||||
}
|
||||
|
||||
const handleEnable = async (pluginId: string) => {
|
||||
try {
|
||||
await enable(pluginId)
|
||||
messageApi.success("插件已启用")
|
||||
} catch (error) {
|
||||
messageApi.error("插件启用失败")
|
||||
}
|
||||
}
|
||||
|
||||
const handleDisable = async (pluginId: string) => {
|
||||
try {
|
||||
await disable(pluginId)
|
||||
messageApi.success("插件已禁用")
|
||||
} catch (error) {
|
||||
messageApi.error("插件禁用失败")
|
||||
}
|
||||
}
|
||||
|
||||
const renderPluginActions = (
|
||||
plugin: BuiltinPluginMeta & { installed: boolean; enabled: boolean }
|
||||
) => {
|
||||
if (!plugin.installed) {
|
||||
return (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={() => handleInstall(plugin.id)}
|
||||
disabled={!canEdit}
|
||||
>
|
||||
安装
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Space>
|
||||
{plugin.enabled ? (
|
||||
<Button
|
||||
type="default"
|
||||
icon={<CloseCircleOutlined />}
|
||||
onClick={() => handleDisable(plugin.id)}
|
||||
disabled={!canEdit}
|
||||
>
|
||||
禁用
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<CheckCircleOutlined />}
|
||||
onClick={() => handleEnable(plugin.id)}
|
||||
disabled={!canEdit}
|
||||
>
|
||||
启用
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleUninstall(plugin.id)}
|
||||
disabled={!canEdit}
|
||||
>
|
||||
卸载
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: "24px" }}>
|
||||
{contextHolder}
|
||||
<Title level={4}>内置插件管理</Title>
|
||||
<Paragraph type="secondary">
|
||||
管理 SecScore 的内置功能插件。安装后可在侧边栏访问对应功能。
|
||||
</Paragraph>
|
||||
|
||||
{loading ? (
|
||||
<div style={{ textAlign: "center", padding: "40px" }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
) : plugins.length === 0 ? (
|
||||
<Empty description="暂无可用插件" />
|
||||
) : (
|
||||
<List
|
||||
grid={{ gutter: 16, xs: 1, sm: 1, md: 2, lg: 2, xl: 3, xxl: 3 }}
|
||||
dataSource={plugins}
|
||||
renderItem={(plugin) => (
|
||||
<List.Item>
|
||||
<Card
|
||||
hoverable
|
||||
style={{
|
||||
backgroundColor: "var(--ss-card-bg)",
|
||||
borderColor: plugin.enabled
|
||||
? "var(--ant-color-primary)"
|
||||
: "var(--ss-border-color)",
|
||||
}}
|
||||
title={
|
||||
<Space>
|
||||
{categoryIcons[plugin.category]}
|
||||
<span>{plugin.name}</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<Tag color={plugin.enabled ? "success" : "default"}>
|
||||
{plugin.enabled ? "已启用" : plugin.installed ? "已安装" : "未安装"}
|
||||
</Tag>
|
||||
}
|
||||
>
|
||||
<div style={{ marginBottom: "12px" }}>
|
||||
<Text type="secondary">{plugin.description}</Text>
|
||||
</div>
|
||||
<Space direction="vertical" size="small" style={{ width: "100%" }}>
|
||||
<div>
|
||||
<Tag>{categoryLabels[plugin.category]}</Tag>
|
||||
{plugin.requiresAdmin && <Tag color="warning">需要管理员权限</Tag>}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Text type="secondary" style={{ fontSize: "12px" }}>
|
||||
版本 {plugin.version}
|
||||
</Text>
|
||||
{renderPluginActions(plugin)}
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user