random-api-go/web/components/admin/URLRulesTab.tsx

291 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import type { URLReplaceRule, APIEndpoint } from '@/types/admin'
interface URLRulesTabProps {
rules: URLReplaceRule[]
endpoints: APIEndpoint[]
onCreateRule?: (data: Partial<URLReplaceRule>) => void
onUpdateRule?: (id: number, data: Partial<URLReplaceRule>) => void
onDeleteRule?: (id: number) => void
}
export default function URLRulesTab({
rules,
endpoints,
onCreateRule,
onUpdateRule,
onDeleteRule
}: URLRulesTabProps) {
const [showCreateForm, setShowCreateForm] = useState(false)
const [editingRule, setEditingRule] = useState<URLReplaceRule | null>(null)
const [formData, setFormData] = useState({
name: '',
from_url: '',
to_url: '',
endpoint_id: undefined as number | undefined,
is_active: true
})
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (editingRule) {
// 更新规则
if (onUpdateRule) {
onUpdateRule(editingRule.id, formData)
setEditingRule(null)
}
} else {
// 创建规则
if (onCreateRule) {
onCreateRule(formData)
}
}
setFormData({ name: '', from_url: '', to_url: '', endpoint_id: undefined, is_active: true })
setShowCreateForm(false)
}
const handleEdit = (rule: URLReplaceRule) => {
setEditingRule(rule)
setFormData({
name: rule.name,
from_url: rule.from_url,
to_url: rule.to_url,
endpoint_id: rule.endpoint_id,
is_active: rule.is_active
})
setShowCreateForm(true)
}
const handleCancelEdit = () => {
setEditingRule(null)
setFormData({ name: '', from_url: '', to_url: '', endpoint_id: undefined, is_active: true })
setShowCreateForm(false)
}
const handleDelete = (ruleId: number) => {
if (confirm('确定要删除这个URL替换规则吗')) {
if (onDeleteRule) {
onDeleteRule(ruleId)
}
}
}
const toggleRuleStatus = (rule: URLReplaceRule) => {
if (onUpdateRule) {
onUpdateRule(rule.id, { is_active: !rule.is_active })
}
}
const getEndpointName = (endpointId?: number) => {
if (!endpointId) return '全局规则'
const endpoint = endpoints.find(ep => ep.id === endpointId)
return endpoint ? endpoint.name : `端点 ${endpointId}`
}
return (
<div>
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold tracking-tight">URL替换规则</h2>
<Button onClick={() => setShowCreateForm(true)}>
</Button>
</div>
{showCreateForm && (
<div className="bg-card rounded-lg border p-6 mb-6">
<h3 className="text-lg font-medium mb-4">
{editingRule ? '编辑规则' : '创建新规则'}
</h3>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="rule-name"></Label>
<Input
id="rule-name"
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="例如: 替换图床域名"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="endpoint-select"></Label>
<Select
value={formData.endpoint_id?.toString() || 'global'}
onValueChange={(value) => setFormData({
...formData,
endpoint_id: value === 'global' ? undefined : parseInt(value)
})}
>
<SelectTrigger>
<SelectValue placeholder="选择端点或设为全局规则" />
</SelectTrigger>
<SelectContent>
<SelectItem value="global"></SelectItem>
{endpoints.map((endpoint) => (
<SelectItem key={endpoint.id} value={endpoint.id.toString()}>
{endpoint.name} ({endpoint.url})
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-xs text-muted-foreground">
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="from-url">URL模式</Label>
<Input
id="from-url"
type="text"
value={formData.from_url}
onChange={(e) => setFormData({ ...formData, from_url: e.target.value })}
placeholder="例如: a.com"
required
/>
<p className="text-xs text-muted-foreground">
URL片段匹配
</p>
</div>
<div className="space-y-2">
<Label htmlFor="to-url">URL模式</Label>
<Input
id="to-url"
type="text"
value={formData.to_url}
onChange={(e) => setFormData({ ...formData, to_url: e.target.value })}
placeholder="例如: b.com"
required
/>
<p className="text-xs text-muted-foreground">
URL片段
</p>
</div>
</div>
<div className="flex items-center space-x-2">
<Switch
id="rule-active"
checked={formData.is_active}
onCheckedChange={(checked) => setFormData({ ...formData, is_active: checked })}
/>
<Label htmlFor="rule-active"></Label>
</div>
<div className="flex space-x-3">
<Button type="submit">
{editingRule ? '更新' : '创建'}
</Button>
<Button
type="button"
onClick={handleCancelEdit}
variant="outline"
>
</Button>
</div>
</form>
</div>
)}
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead>URL</TableHead>
<TableHead>URL</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rules.length > 0 ? (
rules.map((rule) => (
<TableRow key={rule.id}>
<TableCell className="font-medium">
{rule.name}
</TableCell>
<TableCell>
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
rule.endpoint_id
? 'bg-blue-100 text-blue-800 dark:bg-blue-800 dark:text-blue-100'
: 'bg-purple-100 text-purple-800 dark:bg-purple-800 dark:text-purple-100'
}`}>
{getEndpointName(rule.endpoint_id)}
</span>
</TableCell>
<TableCell>
<code className="bg-muted px-2 py-1 rounded text-sm">
{rule.from_url}
</code>
</TableCell>
<TableCell>
<code className="bg-muted px-2 py-1 rounded text-sm">
{rule.to_url}
</code>
</TableCell>
<TableCell>
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
rule.is_active
? 'bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100'
: 'bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100'
}`}>
{rule.is_active ? '启用' : '禁用'}
</span>
</TableCell>
<TableCell>
{new Date(rule.created_at).toLocaleDateString()}
</TableCell>
<TableCell>
<div className="flex space-x-1">
<Button
variant="outline"
size="sm"
onClick={() => handleEdit(rule)}
>
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toggleRuleStatus(rule)}
>
{rule.is_active ? '禁用' : '启用'}
</Button>
<Button
variant="outline"
size="sm"
onClick={() => handleDelete(rule.id)}
className="text-red-600 hover:text-red-700"
>
</Button>
</div>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={7} className="text-center text-muted-foreground py-8">
URL替换规则&quot;&quot;
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</div>
)
}