Files
deerflow-code/web-code/pages/SystemSettings.tsx
T
2026-05-28 18:29:37 +08:00

559 lines
28 KiB
TypeScript

import React, { useState } from 'react';
import { useTheme } from '../contexts/ThemeContext';
import { PageType } from '../components/Sidebar';
import {
Settings,
User,
Bell,
Shield,
Database,
Palette,
Key,
Globe,
Monitor,
Smartphone,
Mail,
MessageSquare,
Clock,
Save,
RefreshCw,
CheckCircle,
AlertTriangle,
ChevronRight,
Building,
Users,
Bot,
Workflow,
FileText,
Zap,
} from 'lucide-react';
interface SystemSettingsProps {
onNavigate: (page: PageType) => void;
}
const SystemSettings: React.FC<SystemSettingsProps> = ({ onNavigate }) => {
const { theme } = useTheme();
const isDark = theme === 'dark';
// 主题颜色类
const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white';
const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-200';
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
const textMuted = isDark ? 'text-slate-500' : 'text-gray-500';
const btnSecondary = isDark ? 'bg-slate-700/50 hover:bg-slate-600/50 border-blue-800/30 text-slate-300' : 'bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700';
const btnPrimary = isDark ? 'bg-blue-600 hover:bg-blue-500' : 'bg-red-600 hover:bg-red-500';
const inputBg = isDark ? 'bg-slate-900/50' : 'bg-gray-50';
const inputBorder = isDark ? 'border-blue-800/30' : 'border-gray-300';
const [activeTab, setActiveTab] = useState('general');
const [settings, setSettings] = useState({
// 通用设置
systemName: '智能策略系统',
systemVersion: 'V1.0.0',
language: 'zh-CN',
timezone: 'Asia/Shanghai',
// 通知设置
emailNotification: true,
inAppNotification: true,
smsNotification: false,
// 安全设置
sessionTimeout: 30,
passwordExpiration: 90,
twoFactorAuth: false,
// 运行规则
maxDiscussionRounds: 10,
maxRollbackTimes: 3,
enableStateGate: true,
enableLogicChainCheck: true,
enableRiskReview: true,
allowPartialParallel: true,
});
const tabs = [
{ id: 'general', label: '通用设置', icon: Settings },
{ id: 'user', label: '用户管理', icon: Users },
{ id: 'agent', label: '智能体管理', icon: Bot },
{ id: 'notification', label: '通知设置', icon: Bell },
{ id: 'security', label: '安全设置', icon: Shield },
{ id: 'workflow', label: '运行规则', icon: Workflow },
{ id: 'template', label: '模板管理', icon: FileText },
];
return (
<div className="space-y-6">
{/* 顶部标题栏 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-10 h-10 rounded-lg bg-blue-500/20 flex items-center justify-center">
<Settings className="w-5 h-5 text-blue-400" />
</div>
<div>
<h1 className={`${textPrimary} font-bold text-lg`}>系统设置</h1>
<p className={`${textSecondary} text-sm`}>管理智能策略系统的各项配置</p>
</div>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1.5 bg-green-500/20 text-green-400 rounded-full text-sm font-medium flex items-center gap-1.5">
<span className="w-2 h-2 bg-green-400 rounded-full" />
系统运行正常
</span>
</div>
</div>
</div>
<div className="grid grid-cols-12 gap-6">
{/* 左侧导航 (20%) */}
<div className="col-span-3">
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4 sticky top-6`}>
<h3 className={`${textSecondary} text-xs font-medium mb-3 uppercase tracking-wider`}>设置分类</h3>
<nav className="space-y-1">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left text-sm transition-colors ${
activeTab === tab.id
? 'bg-blue-600/20 text-blue-400 border border-blue-500/30'
: `${textSecondary} hover:bg-slate-700/50 hover:${textPrimary}`
}`}
>
<tab.icon className="w-4 h-4" />
{tab.label}
</button>
))}
</nav>
{/* 系统信息 */}
<div className="mt-6 pt-4 border-t border-blue-800/30">
<h3 className={`${textSecondary} text-xs font-medium mb-3 uppercase tracking-wider`}>系统信息</h3>
<div className="space-y-2 text-xs">
<div className="flex justify-between">
<span className={textMuted}>版本号</span>
<span className="text-cyan-400">{settings.systemVersion}</span>
</div>
<div className="flex justify-between">
<span className={textMuted}>运行环境</span>
<span className={textSecondary}>生产环境</span>
</div>
<div className="flex justify-between">
<span className={textMuted}>最后更新</span>
<span className={textSecondary}>2026-03-19</span>
</div>
</div>
</div>
</div>
</div>
{/* 右侧设置区 (80%) */}
<div className="col-span-9">
{/* 通用设置 */}
{activeTab === 'general' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h2 className={`${textPrimary} font-semibold text-lg mb-6 flex items-center gap-2`}>
<Settings className="w-5 h-5 text-blue-400" />
通用设置
</h2>
<div className="space-y-6">
<div className="grid grid-cols-2 gap-6">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>系统名称</label>
<input
type="text"
value={settings.systemName}
onChange={(e) => setSettings({ ...settings, systemName: e.target.value })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>系统版本</label>
<input
type="text"
value={settings.systemVersion}
disabled
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textMuted} text-sm`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>语言</label>
<select
value={settings.language}
onChange={(e) => setSettings({ ...settings, language: e.target.value })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
>
<option value="zh-CN">简体中文</option>
<option value="en-US">English</option>
</select>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>时区</label>
<select
value={settings.timezone}
onChange={(e) => setSettings({ ...settings, timezone: e.target.value })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
>
<option value="Asia/Shanghai">北京时间 (UTC+8)</option>
<option value="UTC">世界时间 (UTC)</option>
</select>
</div>
</div>
<div className="pt-4 border-t border-blue-800/30">
<div className="flex items-center justify-between p-4 bg-blue-500/10 border border-blue-500/30 rounded-lg">
<div className="flex items-center gap-3">
<Zap className="w-5 h-5 text-blue-400" />
<div>
<p className={`${textPrimary} text-sm font-medium`}>自动保存设置</p>
<p className={`${textSecondary} text-xs`}>开启后,系统会自动保存您的设置更改</p>
</div>
</div>
<button className={`px-4 py-2 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors`}>
已开启
</button>
</div>
</div>
</div>
</div>
)}
{/* 用户管理 */}
{activeTab === 'user' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<div className="flex items-center justify-between mb-6">
<h2 className={`${textPrimary} font-semibold text-lg flex items-center gap-2`}>
<Users className="w-5 h-5 text-cyan-400" />
用户管理
</h2>
<button className={`px-4 py-2 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors flex items-center gap-2`}>
<User className="w-4 h-4" />
添加用户
</button>
</div>
<div className="space-y-3">
{[
{ name: '张策略', role: '管理员', email: 'zhang@company.com', status: 'active' },
{ name: '李智能', role: '策略分析师', email: 'li@company.com', status: 'active' },
{ name: '王智能体', role: '智能体管理员', email: 'wang@company.com', status: 'active' },
{ name: '赵运维', role: '运维工程师', email: 'zhao@company.com', status: 'inactive' },
].map((user, i) => (
<div key={i} className={`flex items-center justify-between p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center gap-4">
<div className="w-10 h-10 rounded-full bg-blue-500/20 flex items-center justify-center">
<User className="w-5 h-5 text-blue-400" />
</div>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{user.name}</p>
<p className={`${textSecondary} text-xs`}>{user.email}</p>
</div>
</div>
<div className="flex items-center gap-4">
<span className={`px-3 py-1 rounded-full text-xs ${
user.role === '管理员' ? 'bg-purple-500/20 text-purple-400' : 'bg-blue-500/20 text-blue-400'
}`}>
{user.role}
</span>
<span className={`px-3 py-1 rounded-full text-xs ${
user.status === 'active' ? 'bg-green-500/20 text-green-400' : 'bg-slate-500/20 text-slate-400'
}`}>
{user.status === 'active' ? '在线' : '离线'}
</span>
<button className="p-2 hover:bg-slate-700 rounded-lg transition-colors">
<ChevronRight className={`w-4 h-4 ${textSecondary}`} />
</button>
</div>
</div>
))}
</div>
</div>
)}
{/* 智能体管理 */}
{activeTab === 'agent' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<div className="flex items-center justify-between mb-6">
<h2 className={`${textPrimary} font-semibold text-lg flex items-center gap-2`}>
<Bot className="w-5 h-5 text-purple-400" />
智能体管理
</h2>
<button className={`px-4 py-2 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors flex items-center gap-2`}>
<Bot className="w-4 h-4" />
添加智能体
</button>
</div>
<div className="grid grid-cols-2 gap-4">
{[
{ name: 'GoalAgent', type: '目标分析', status: 'running', tasks: 156 },
{ name: 'AudienceAgent', type: '受众分析', status: 'running', tasks: 142 },
{ name: 'BehaviorAgent', type: '行为分析', status: 'idle', tasks: 98 },
{ name: 'DriverAgent', type: '驱动分析', status: 'idle', tasks: 87 },
{ name: 'NarrativeAgent', type: '叙事分析', status: 'idle', tasks: 76 },
{ name: 'LogicChainAgent', type: '逻辑链收敛', status: 'idle', tasks: 65 },
].map((agent, i) => (
<div key={i} className={`p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Bot className="w-4 h-4 text-purple-400" />
<span className={`${textPrimary} text-sm font-medium`}>{agent.name}</span>
</div>
<span className={`px-2 py-0.5 rounded text-xs ${
agent.status === 'running' ? 'bg-green-500/20 text-green-400' : 'bg-slate-500/20 text-slate-400'
}`}>
{agent.status === 'running' ? '运行中' : '空闲'}
</span>
</div>
<p className={`${textSecondary} text-xs mb-3`}>{agent.type}</p>
<div className="flex items-center justify-between text-xs">
<span className={textMuted}>已完成任务</span>
<span className="text-cyan-400">{agent.tasks}</span>
</div>
</div>
))}
</div>
</div>
)}
{/* 通知设置 */}
{activeTab === 'notification' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h2 className={`${textPrimary} font-semibold text-lg mb-6 flex items-center gap-2`}>
<Bell className="w-5 h-5 text-amber-400" />
通知设置
</h2>
<div className="space-y-4">
{[
{ id: 'email', label: '邮件通知', description: '接收任务完成、风险提醒等邮件通知', icon: Mail, enabled: settings.emailNotification },
{ id: 'inApp', label: '站内通知', description: '在系统内显示通知消息', icon: MessageSquare, enabled: settings.inAppNotification },
{ id: 'sms', label: '短信通知', description: '发送重要事项的短信提醒', icon: Smartphone, enabled: settings.smsNotification },
].map((item) => (
<div key={item.id} className={`flex items-center justify-between p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center gap-4">
<div className="w-10 h-10 rounded-lg bg-blue-500/20 flex items-center justify-center">
<item.icon className="w-5 h-5 text-blue-400" />
</div>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{item.label}</p>
<p className={`${textSecondary} text-xs`}>{item.description}</p>
</div>
</div>
<button
onClick={() => setSettings({ ...settings, [item.id === 'email' ? 'emailNotification' : item.id === 'inApp' ? 'inAppNotification' : 'smsNotification']: !item.enabled })}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
item.enabled
? 'bg-green-600 hover:bg-green-500 text-white'
: btnSecondary
}`}
>
{item.enabled ? '已开启' : '已关闭'}
</button>
</div>
))}
<div className="pt-4 border-t border-blue-800/30">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>通知时段</label>
<div className="flex items-center gap-4">
<select className={`px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}>
<option>09:00</option>
<option>10:00</option>
<option>11:00</option>
</select>
<span className={textMuted}>至</span>
<select className={`px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}>
<option>18:00</option>
<option>19:00</option>
<option>20:00</option>
</select>
</div>
</div>
</div>
</div>
</div>
)}
{/* 安全设置 */}
{activeTab === 'security' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h2 className={`${textPrimary} font-semibold text-lg mb-6 flex items-center gap-2`}>
<Shield className="w-5 h-5 text-red-400" />
安全设置
</h2>
<div className="space-y-6">
<div className="grid grid-cols-2 gap-6">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>会话超时时间(分钟)</label>
<select
value={settings.sessionTimeout}
onChange={(e) => setSettings({ ...settings, sessionTimeout: Number(e.target.value) })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
>
<option value={15}>15 分钟</option>
<option value={30}>30 分钟</option>
<option value={60}>1 小时</option>
<option value={120}>2 小时</option>
</select>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>密码过期时间(天)</label>
<select
value={settings.passwordExpiration}
onChange={(e) => setSettings({ ...settings, passwordExpiration: Number(e.target.value) })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
>
<option value={30}>30 天</option>
<option value={60}>60 天</option>
<option value={90}>90 天</option>
<option value={180}>180 天</option>
</select>
</div>
</div>
<div className={`flex items-center justify-between p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center gap-4">
<Key className="w-5 h-5 text-purple-400" />
<div>
<p className={`${textPrimary} text-sm font-medium`}>双因素认证</p>
<p className={`${textSecondary} text-xs`}>登录时需要额外的验证码验证</p>
</div>
</div>
<button
onClick={() => setSettings({ ...settings, twoFactorAuth: !settings.twoFactorAuth })}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
settings.twoFactorAuth
? 'bg-green-600 hover:bg-green-500 text-white'
: btnSecondary
}`}
>
{settings.twoFactorAuth ? '已开启' : '已关闭'}
</button>
</div>
<div className="pt-4 border-t border-blue-800/30">
<button className="flex items-center gap-2 px-4 py-2.5 bg-red-600/20 hover:bg-red-600/30 border border-red-500/30 text-red-400 rounded-lg text-sm transition-colors">
<Shield className="w-4 h-4" />
重置所有安全设置
</button>
</div>
</div>
</div>
)}
{/* 运行规则 */}
{activeTab === 'workflow' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h2 className={`${textPrimary} font-semibold text-lg mb-6 flex items-center gap-2`}>
<Workflow className="w-5 h-5 text-green-400" />
运行规则配置
</h2>
<div className="space-y-4">
{[
{ id: 'enableStateGate', label: '启用状态门控', description: '智能体输出需要通过状态门控检查才能进入下一节点' },
{ id: 'enableLogicChainCheck', label: '启用逻辑链校验', description: '在逻辑链收敛阶段进行一致性检查' },
{ id: 'enableRiskReview', label: '启用风险强制复核', description: '高风险项必须经过人工确认才能继续' },
{ id: 'allowPartialParallel', label: '允许局部并行', description: '独立的流程节点可以并行执行' },
].map((item) => (
<div key={item.id} className={`flex items-center justify-between p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{item.label}</p>
<p className={`${textSecondary} text-xs mt-1`}>{item.description}</p>
</div>
<button
onClick={() => setSettings({ ...settings, [item.id]: !settings[item.id as keyof typeof settings] as boolean })}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
settings[item.id as keyof typeof settings]
? 'bg-green-600 hover:bg-green-500 text-white'
: btnSecondary
}`}
>
{settings[item.id as keyof typeof settings] ? '已开启' : '已关闭'}
</button>
</div>
))}
<div className="grid grid-cols-2 gap-6 pt-4 border-t border-blue-800/30">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>最大讨论轮数</label>
<input
type="number"
value={settings.maxDiscussionRounds}
onChange={(e) => setSettings({ ...settings, maxDiscussionRounds: Number(e.target.value) })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
/>
<p className={`${textMuted} text-xs mt-1`}>超出此轮数将自动收敛</p>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>最大回退次数</label>
<input
type="number"
value={settings.maxRollbackTimes}
onChange={(e) => setSettings({ ...settings, maxRollbackTimes: Number(e.target.value) })}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm`}
/>
<p className={`${textMuted} text-xs mt-1`}>超出此次数将终止任务</p>
</div>
</div>
</div>
</div>
)}
{/* 模板管理 */}
{activeTab === 'template' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<div className="flex items-center justify-between mb-6">
<h2 className={`${textPrimary} font-semibold text-lg flex items-center gap-2`}>
<FileText className="w-5 h-5 text-cyan-400" />
模板管理
</h2>
<button className={`px-4 py-2 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors flex items-center gap-2`}>
<FileText className="w-4 h-4" />
新建模板
</button>
</div>
<div className="grid grid-cols-3 gap-4">
{[
{ name: '宣传策略模板', type: '策略生成', fields: 24, updated: '2026-03-15' },
{ name: '活动方案模板', type: '方案推演', fields: 32, updated: '2026-03-10' },
{ name: '市场分析模板', type: '市场调研', fields: 18, updated: '2026-03-08' },
{ name: '产品推广模板', type: '产品营销', fields: 28, updated: '2026-03-05' },
{ name: '品牌公关模板', type: '公关传播', fields: 22, updated: '2026-03-01' },
{ name: '用户调研模板', type: '用户洞察', fields: 16, updated: '2026-02-28' },
].map((template, i) => (
<div key={i} className={`p-4 ${inputBg} ${inputBorder} rounded-lg hover:border-blue-500/50 transition-colors cursor-pointer`}>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<FileText className="w-4 h-4 text-cyan-400" />
<span className={`${textPrimary} text-sm font-medium`}>{template.name}</span>
</div>
<ChevronRight className={`w-4 h-4 ${textSecondary}`} />
</div>
<p className={`${textSecondary} text-xs mb-2`}>{template.type}</p>
<div className="flex items-center justify-between text-xs">
<span className={textMuted}>{template.fields} 个字段</span>
<span className={textMuted}>更新于 {template.updated}</span>
</div>
</div>
))}
</div>
</div>
)}
{/* 保存按钮 */}
<div className="mt-6 flex items-center justify-end gap-3">
<button className={`px-6 py-2.5 ${btnSecondary} rounded-lg text-sm transition-colors flex items-center gap-2`}>
<RefreshCw className="w-4 h-4" />
重置
</button>
<button className={`px-6 py-2.5 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors flex items-center gap-2`}>
<Save className="w-4 h-4" />
保存设置
</button>
</div>
</div>
</div>
</div>
);
};
export default SystemSettings;