598 lines
34 KiB
TypeScript
598 lines
34 KiB
TypeScript
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Slider } from "@/components/ui/slider"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Separator } from "@/components/ui/separator"
|
|
import { Switch } from "@/components/ui/switch"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
import { Textarea } from "@/components/ui/textarea"
|
|
import { Checkbox } from "@/components/ui/checkbox"
|
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
|
import { ScrollArea } from "@/components/ui/scroll-area"
|
|
import { useState } from "react"
|
|
import { Config, defaultConfig } from "@/types/config"
|
|
import {
|
|
Settings,
|
|
Volume2,
|
|
FlashlightIcon as Brightness4,
|
|
Wifi,
|
|
Database,
|
|
Shield,
|
|
Monitor,
|
|
Bell,
|
|
Server,
|
|
Lock,
|
|
Zap,
|
|
HardDrive,
|
|
Cpu,
|
|
} from "lucide-react"
|
|
|
|
|
|
|
|
export default function Control() {
|
|
const [config, setConfig] = useState<Config>(defaultConfig)
|
|
|
|
const updateConfig = (key: keyof Config, value: any) => {
|
|
setConfig(prev => ({
|
|
...prev,
|
|
[key]: value
|
|
}))
|
|
}
|
|
|
|
const updateSliderConfig = (key: keyof Config, value: number[]) => {
|
|
updateConfig(key, value[0])
|
|
}
|
|
|
|
return (
|
|
<ScrollArea className="flex-1 h-full">
|
|
<div className="min-h-screen p-6">
|
|
<div className="mx-auto max-w-7xl space-y-6">
|
|
<div className="grid gap-6 lg:grid-cols-3">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Volume2 className="h-5 w-5" />
|
|
System Controls
|
|
</CardTitle>
|
|
<CardDescription>Audio, display, and hardware settings</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="volume">Volume: {config.volume}%</Label>
|
|
<Slider
|
|
id="volume"
|
|
value={[config.volume]}
|
|
onValueChange={(value) => updateSliderConfig('volume', value)}
|
|
max={100}
|
|
step={1}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="brightness">
|
|
<Brightness4 className="inline h-4 w-4 mr-1" />
|
|
Brightness: {config.brightness}%
|
|
</Label>
|
|
<Slider
|
|
id="brightness"
|
|
value={[config.brightness]}
|
|
onValueChange={(value) => updateSliderConfig('brightness', value)}
|
|
max={100}
|
|
step={1}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="temperature">Temperature: {config.temperature}°C</Label>
|
|
<Slider
|
|
id="temperature"
|
|
value={[config.temperature]}
|
|
onValueChange={(value) => updateSliderConfig('temperature', value)}
|
|
min={16}
|
|
max={30}
|
|
step={0.5}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Theme Selection</Label>
|
|
<Select value={config.theme} onValueChange={(value) => updateConfig('theme', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="light">Light Theme</SelectItem>
|
|
<SelectItem value="dark">Dark Theme</SelectItem>
|
|
<SelectItem value="auto">Auto Theme</SelectItem>
|
|
<SelectItem value="high-contrast">High Contrast</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Server Configuration */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Server className="h-5 w-5" />
|
|
Server Configuration
|
|
</CardTitle>
|
|
<CardDescription>Core server and API settings</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="server-name">Server Name</Label>
|
|
<Input
|
|
id="server-name"
|
|
value={config.serverName}
|
|
onChange={(e) => updateConfig('serverName', e.target.value)}
|
|
placeholder="Enter server name"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="api-key">API Key</Label>
|
|
<Input
|
|
id="api-key"
|
|
type="password"
|
|
value={config.apiKey}
|
|
onChange={(e) => updateConfig('apiKey', e.target.value)}
|
|
placeholder="Enter API key"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Environment</Label>
|
|
<Select value={config.environment} onValueChange={(value) => updateConfig('environment', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="development">Development</SelectItem>
|
|
<SelectItem value="staging">Staging</SelectItem>
|
|
<SelectItem value="production">Production</SelectItem>
|
|
<SelectItem value="testing">Testing</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Region</Label>
|
|
<Select value={config.region} onValueChange={(value) => updateConfig('region', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
|
|
<SelectItem value="us-west-2">US West (Oregon)</SelectItem>
|
|
<SelectItem value="eu-west-1">Europe (Ireland)</SelectItem>
|
|
<SelectItem value="ap-southeast-1">Asia Pacific (Singapore)</SelectItem>
|
|
<SelectItem value="ap-northeast-1">Asia Pacific (Tokyo)</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Performance Settings */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Cpu className="h-5 w-5" />
|
|
Performance Settings
|
|
</CardTitle>
|
|
<CardDescription>Resource allocation and optimization</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="connections">Max Connections: {config.maxConnections}</Label>
|
|
<Slider
|
|
id="connections"
|
|
value={[config.maxConnections]}
|
|
onValueChange={(value) => updateSliderConfig('maxConnections', value)}
|
|
min={10}
|
|
max={500}
|
|
step={10}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="cache-size">Cache Size: {config.cacheSize}MB</Label>
|
|
<Slider
|
|
id="cache-size"
|
|
value={[config.cacheSize]}
|
|
onValueChange={(value) => updateSliderConfig('cacheSize', value)}
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="thread-count">Thread Count: {config.threadCount}</Label>
|
|
<Slider
|
|
id="thread-count"
|
|
value={[config.threadCount]}
|
|
onValueChange={(value) => updateSliderConfig('threadCount', value)}
|
|
min={1}
|
|
max={32}
|
|
step={1}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="memory-limit">Memory Limit: {config.memoryLimit}MB</Label>
|
|
<Slider
|
|
id="memory-limit"
|
|
value={[config.memoryLimit]}
|
|
onValueChange={(value) => updateSliderConfig('memoryLimit', value)}
|
|
min={512}
|
|
max={8192}
|
|
step={256}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="bandwidth">Network Bandwidth: {config.networkBandwidth}Mbps</Label>
|
|
<Slider
|
|
id="bandwidth"
|
|
value={[config.networkBandwidth]}
|
|
onValueChange={(value) => updateSliderConfig('networkBandwidth', value)}
|
|
min={10}
|
|
max={1000}
|
|
step={10}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Security & Features */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Shield className="h-5 w-5" />
|
|
Security & Features
|
|
</CardTitle>
|
|
<CardDescription>Security settings and feature toggles</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="ssl-enabled" className="flex items-center gap-2">
|
|
<Lock className="h-4 w-4" />
|
|
SSL Enabled
|
|
</Label>
|
|
<Switch
|
|
id="ssl-enabled"
|
|
checked={config.sslEnabled}
|
|
onCheckedChange={(checked) => updateConfig('sslEnabled', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="auto-backup">Auto Backup</Label>
|
|
<Switch
|
|
id="auto-backup"
|
|
checked={config.autoBackup}
|
|
onCheckedChange={(checked) => updateConfig('autoBackup', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="compression">Compression</Label>
|
|
<Switch
|
|
id="compression"
|
|
checked={config.compressionEnabled}
|
|
onCheckedChange={(checked) => updateConfig('compressionEnabled', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="debug-mode">Debug Mode</Label>
|
|
<Switch
|
|
id="debug-mode"
|
|
checked={config.debugMode}
|
|
onCheckedChange={(checked) => updateConfig('debugMode', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="maintenance">Maintenance Mode</Label>
|
|
<Switch
|
|
id="maintenance"
|
|
checked={config.maintenanceMode}
|
|
onCheckedChange={(checked) => updateConfig('maintenanceMode', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Log Level</Label>
|
|
<Select value={config.logLevel} onValueChange={(value) => updateConfig('logLevel', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="debug">Debug</SelectItem>
|
|
<SelectItem value="info">Info</SelectItem>
|
|
<SelectItem value="warn">Warning</SelectItem>
|
|
<SelectItem value="error">Error</SelectItem>
|
|
<SelectItem value="fatal">Fatal</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Notifications & Alerts */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Bell className="h-5 w-5" />
|
|
Notifications & Alerts
|
|
</CardTitle>
|
|
<CardDescription>Configure notification preferences</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="notifications">Push Notifications</Label>
|
|
<Switch
|
|
id="notifications"
|
|
checked={config.notifications}
|
|
onCheckedChange={(checked) => updateConfig('notifications', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="email-alerts">Email Alerts</Label>
|
|
<Switch
|
|
id="email-alerts"
|
|
checked={config.emailAlerts}
|
|
onCheckedChange={(checked) => updateConfig('emailAlerts', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="sms-alerts">SMS Alerts</Label>
|
|
<Switch
|
|
id="sms-alerts"
|
|
checked={config.smsAlerts}
|
|
onCheckedChange={(checked) => updateConfig('smsAlerts', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="monitoring">System Monitoring</Label>
|
|
<Switch
|
|
id="monitoring"
|
|
checked={config.monitoringEnabled}
|
|
onCheckedChange={(checked) => updateConfig('monitoringEnabled', checked)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Language</Label>
|
|
<Select value={config.language} onValueChange={(value) => updateConfig('language', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="en">English</SelectItem>
|
|
<SelectItem value="es">Español</SelectItem>
|
|
<SelectItem value="fr">Français</SelectItem>
|
|
<SelectItem value="de">Deutsch</SelectItem>
|
|
<SelectItem value="zh">中文</SelectItem>
|
|
<SelectItem value="ja">日本語</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Timezone</Label>
|
|
<Select value={config.timezone} onValueChange={(value) => updateConfig('timezone', value)}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="UTC">UTC</SelectItem>
|
|
<SelectItem value="EST">Eastern Time</SelectItem>
|
|
<SelectItem value="PST">Pacific Time</SelectItem>
|
|
<SelectItem value="GMT">Greenwich Mean Time</SelectItem>
|
|
<SelectItem value="JST">Japan Standard Time</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Advanced Configuration */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Database className="h-5 w-5" />
|
|
Advanced Configuration
|
|
</CardTitle>
|
|
<CardDescription>Detailed system configuration options</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="description">System Description</Label>
|
|
<Textarea
|
|
id="description"
|
|
value={config.description}
|
|
onChange={(e) => updateConfig('description', e.target.value)}
|
|
placeholder="Enter system description..."
|
|
rows={3}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Deployment Strategy</Label>
|
|
<RadioGroup value={config.deploymentStrategy} onValueChange={(value) => updateConfig('deploymentStrategy', value)}>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="rolling" id="rolling" />
|
|
<Label htmlFor="rolling">Rolling Deployment</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="blue-green" id="blue-green" />
|
|
<Label htmlFor="blue-green">Blue-Green Deployment</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="canary" id="canary" />
|
|
<Label htmlFor="canary">Canary Deployment</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Label>Enabled Features</Label>
|
|
<div className="space-y-2">
|
|
{[
|
|
{ id: "analytics", label: "Analytics" },
|
|
{ id: "caching", label: "Caching" },
|
|
{ id: "cdn", label: "CDN" },
|
|
{ id: "load-balancing", label: "Load Balancing" },
|
|
{ id: "auto-scaling", label: "Auto Scaling" },
|
|
].map((feature) => (
|
|
<div key={feature.id} className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id={feature.id}
|
|
checked={config.selectedFeatures.includes(feature.id)}
|
|
onCheckedChange={(checked) => {
|
|
if (checked) {
|
|
updateConfig('selectedFeatures', [...config.selectedFeatures, feature.id])
|
|
} else {
|
|
updateConfig('selectedFeatures', config.selectedFeatures.filter((f) => f !== feature.id))
|
|
}
|
|
}}
|
|
/>
|
|
<Label htmlFor={feature.id}>{feature.label}</Label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Status Dashboard */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Monitor className="h-5 w-5" />
|
|
System Status Dashboard
|
|
</CardTitle>
|
|
<CardDescription>Real-time system metrics and performance indicators</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
<div className="space-y-2">
|
|
<Label className="text-sm font-medium flex items-center gap-2">
|
|
<Cpu className="h-4 w-4" />
|
|
CPU Usage
|
|
</Label>
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1 bg-slate-200 rounded-full h-2">
|
|
<div className="bg-blue-500 h-2 rounded-full w-3/4"></div>
|
|
</div>
|
|
<Badge variant="secondary">75%</Badge>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label className="text-sm font-medium flex items-center gap-2">
|
|
<HardDrive className="h-4 w-4" />
|
|
Memory
|
|
</Label>
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1 bg-slate-200 rounded-full h-2">
|
|
<div className="bg-green-500 h-2 rounded-full w-1/2"></div>
|
|
</div>
|
|
<Badge variant="secondary">8.2GB</Badge>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label className="text-sm font-medium flex items-center gap-2">
|
|
<Database className="h-4 w-4" />
|
|
Storage
|
|
</Label>
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1 bg-slate-200 rounded-full h-2">
|
|
<div className="bg-orange-500 h-2 rounded-full w-5/6"></div>
|
|
</div>
|
|
<Badge variant="secondary">456GB</Badge>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label className="text-sm font-medium flex items-center gap-2">
|
|
<Wifi className="h-4 w-4" />
|
|
Network
|
|
</Label>
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex-1 bg-slate-200 rounded-full h-2">
|
|
<div className="bg-purple-500 h-2 rounded-full w-1/3"></div>
|
|
</div>
|
|
<Badge variant="outline" className="text-green-600 border-green-600">
|
|
Online
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator className="my-6" />
|
|
|
|
<div className="flex flex-wrap gap-3">
|
|
<Button className="flex items-center gap-2" onClick={() => {
|
|
// 这里可以添加保存配置到后端的逻辑
|
|
console.log('Applying configuration:', config)
|
|
alert('Configuration applied successfully!')
|
|
}}>
|
|
<Zap className="h-4 w-4" />
|
|
Apply All Settings
|
|
</Button>
|
|
<Button variant="outline" onClick={() => setConfig(defaultConfig)}>Reset to Default</Button>
|
|
<Button variant="outline" onClick={() => {
|
|
const dataStr = JSON.stringify(config, null, 2)
|
|
const dataBlob = new Blob([dataStr], { type: 'application/json' })
|
|
const url = URL.createObjectURL(dataBlob)
|
|
const link = document.createElement('a')
|
|
link.href = url
|
|
link.download = 'config.json'
|
|
link.click()
|
|
URL.revokeObjectURL(url)
|
|
}}>Export Configuration</Button>
|
|
<Button variant="outline" onClick={() => {
|
|
const input = document.createElement('input')
|
|
input.type = 'file'
|
|
input.accept = '.json'
|
|
input.onchange = (e) => {
|
|
const file = (e.target as HTMLInputElement).files?.[0]
|
|
if (file) {
|
|
const reader = new FileReader()
|
|
reader.onload = (e) => {
|
|
try {
|
|
const importedConfig = JSON.parse(e.target?.result as string)
|
|
setConfig(importedConfig)
|
|
} catch (error) {
|
|
console.error('Failed to parse config file:', error)
|
|
alert('Invalid configuration file')
|
|
}
|
|
}
|
|
reader.readAsText(file)
|
|
}
|
|
}
|
|
input.click()
|
|
}}>Import Configuration</Button>
|
|
<Button variant="ghost">View Logs</Button>
|
|
<Button variant="ghost">System Health Check</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</ScrollArea>
|
|
);
|
|
} |