Files
juip-web/src/admin/whitelist/page.tsx

128 lines
4.3 KiB
TypeScript
Raw Normal View History

2026-08-31 14:49:28 +08:00
import { Lock, Trash2, Unlock } from "lucide-react"
import { useState } from "react"
import DataTable from "@/components/data-table"
2026-07-30 13:55:28 +08:00
import Page from "@/components/page"
2026-08-31 14:49:28 +08:00
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import type { WhiteIpItem } from "@/lib/models/whitelist"
// TODO: 后端白名单接口就绪后,将 saveWhiteIp/fetchWhiteList 接入(见 src/api/whitelist.ts)
2026-07-30 13:55:28 +08:00
export default function WhitelistPage() {
2026-08-31 14:49:28 +08:00
const [ip, setIp] = useState("")
const [list, setList] = useState<WhiteIpItem[]>([])
const handleSave = () => {
const value = ip.trim()
if (!value) return
// TODO: await saveWhiteIp(value)
setList(prev => [
{ id: Date.now(), ip: value, createTime: "", isLocked: "未锁定" },
...prev,
])
setIp("")
}
return (
<Page>
<div className="bg-white rounded-lg p-4">
<div className="space-y-4">
<div className="flex items-center gap-3">
<Input
value={ip}
onChange={e => setIp(e.target.value)}
onKeyDown={e => e.key === "Enter" && handleSave()}
placeholder="请输入IP地址并点击保存白名单"
className="max-w-sm"
/>
<Button onClick={handleSave}>保存</Button>
</div>
<div className="flex items-center gap-3">
<h3 className="font-semibold text-lg">当前白名单列表</h3>
<Badge variant="secondary" className="text-yellow-600">
当前仅允许保留白名单数量:5个
</Badge>
</div>
<DataTable<WhiteIpItem>
data={list}
status="done"
columns={[
{
accessorKey: "ip",
header: "IP地址",
},
{
accessorKey: "createTime",
header: "设置时间",
},
{
accessorKey: "isLocked",
header: "锁定状态",
cell: ({ row }) => {
const isLocked = row.original.isLocked === "已锁定"
return (
<Badge variant={isLocked ? "destructive" : "outline"}>
{row.original.isLocked}
</Badge>
)
},
},
{
id: "actions",
header: "操作",
cell: ({ row }) => {
const item = row.original
// TODO: 接入 lockWhiteIp / deleteWhiteIp
return (
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() =>
setList(prev =>
prev.map(i =>
i.id === item.id
? {
...i,
isLocked:
i.isLocked === "未锁定"
? "已锁定"
: "未锁定",
}
: i,
),
)
}
>
{item.isLocked === "未锁定" ? (
<Lock className="mr-1 h-3 w-3" />
) : (
<Unlock className="mr-1 h-3 w-3" />
)}
{item.isLocked === "未锁定" ? "锁定" : "解锁"}
</Button>
<Button
variant="destructive"
size="sm"
onClick={() =>
setList(prev => prev.filter(i => i.id !== item.id))
}
>
<Trash2 className="mr-1 h-3 w-3" />
删除
</Button>
</div>
)
},
},
]}
/>
</div>
</div>
</Page>
)
2026-07-30 13:55:28 +08:00
}