This commit is contained in:
ryan
2026-07-13 15:08:40 +08:00
parent 08e8eea932
commit 1eff7878a1
441 changed files with 26491 additions and 18405 deletions
@@ -1,10 +1,10 @@
'use client';
import Link from 'next/link';
import {useMemo, useState} from 'react';
import {useMutation} from '@tanstack/react-query';
import {Eye, Plus, Trash2} from 'lucide-react';
import {toast} from 'sonner';
import { useMemo, useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import { Eye, Plus, Trash2 } from 'lucide-react';
import { toast } from 'sonner';
import {
AlertDialog,
@@ -16,10 +16,22 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import {Button} from '@/components/ui/button';
import {EmptyStateWithBorder} from '@/components/layout/empty';
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table';
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from '@/components/ui/tooltip';
import { Button } from '@/components/ui/button';
import { EmptyStateWithBorder } from '@/components/layout/empty';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';
import {
ZoneDomainService,
type ProxyRouteItem,
@@ -27,8 +39,8 @@ import {
type ZoneDomainItem,
} from '@/lib/services/openflare';
import {getUpstreamLabels} from '../../../proxy-routes/components/helpers';
import {ZoneDomainDialog} from './zone-domain-dialog';
import { getUpstreamLabels } from '../../../proxy-routes/components/helpers';
import { ZoneDomainDialog } from './zone-domain-dialog';
export function ZoneDomainsTable({
zoneId,
@@ -57,11 +69,13 @@ export function ZoneDomainsTable({
setDeleting(null);
await onChanged();
},
onError: (error) => toast.error(error instanceof Error ? error.message : '删除失败'),
onError: (error) =>
toast.error(error instanceof Error ? error.message : '删除失败'),
});
const certificateMap = useMemo(
() => new Map(certificates.map((certificate) => [certificate.id, certificate])),
() =>
new Map(certificates.map((certificate) => [certificate.id, certificate])),
[certificates],
);
const routeMap = useMemo(
@@ -71,36 +85,36 @@ export function ZoneDomainsTable({
return (
<>
<div className="mb-3 flex justify-end">
<div className='mb-3 flex justify-end'>
<Button
variant="secondary"
size="sm"
className="h-7 text-xs"
variant='secondary'
size='sm'
className='h-7 text-xs'
onClick={() => setCreateOpen(true)}
>
<Plus className="mr-1 size-3.5" />
<Plus className='mr-1 size-3.5' />
添加域名
</Button>
</div>
{domains.length === 0 ? (
<EmptyStateWithBorder description="暂无已添加域名" />
<EmptyStateWithBorder description='暂无已添加域名' />
) : (
<div className="overflow-hidden rounded-lg border border-dashed shadow-none">
<div className='overflow-hidden rounded-lg border border-dashed shadow-none'>
<TooltipProvider delayDuration={0}>
<Table className="w-full min-w-full caption-bottom text-sm">
<TableHeader className="sticky top-0 z-20 bg-background">
<TableRow className="border-b border-dashed hover:bg-transparent">
<TableHead className="h-8 whitespace-nowrap py-2 min-w-[160px]">
<Table className='w-full min-w-full caption-bottom text-sm'>
<TableHeader className='sticky top-0 z-20 bg-background'>
<TableRow className='border-b border-dashed hover:bg-transparent'>
<TableHead className='h-8 whitespace-nowrap py-2 min-w-[160px]'>
FQDN
</TableHead>
<TableHead className="h-8 whitespace-nowrap py-2 min-w-[120px]">
<TableHead className='h-8 whitespace-nowrap py-2 min-w-[120px]'>
证书
</TableHead>
<TableHead className="h-8 whitespace-nowrap py-2 min-w-[200px]">
<TableHead className='h-8 whitespace-nowrap py-2 min-w-[200px]'>
上游
</TableHead>
<TableHead className="sticky right-0 z-10 h-8 w-[90px] bg-background py-2 text-center">
<TableHead className='sticky right-0 z-10 h-8 w-[90px] bg-background py-2 text-center'>
操作
</TableHead>
</TableRow>
@@ -113,44 +127,45 @@ export function ZoneDomainsTable({
: undefined;
const upstreams = route ? getUpstreamLabels(route) : [];
const certLabel = domain.cert_id
? (certificateMap.get(domain.cert_id)?.name ?? `证书 #${domain.cert_id}`)
? (certificateMap.get(domain.cert_id)?.name ??
`证书 #${domain.cert_id}`)
: '未绑定';
return (
<TableRow
key={domain.id}
className="group border-dashed hover:bg-muted/30"
className='group border-dashed hover:bg-muted/30'
>
<TableCell className="py-1">
<TableCell className='py-1'>
<span
className="max-w-[220px] truncate text-[11px] font-medium leading-tight"
className='max-w-[220px] truncate text-[11px] font-medium leading-tight'
title={domain.domain}
>
{domain.domain}
</span>
</TableCell>
<TableCell className="py-1 font-mono text-[10px] whitespace-nowrap text-muted-foreground">
<TableCell className='py-1 font-mono text-[10px] whitespace-nowrap text-muted-foreground'>
{certLabel}
</TableCell>
<TableCell className="max-w-[280px] py-1">
<TableCell className='max-w-[280px] py-1'>
{!domain.proxy_route_id ? (
<span className="font-mono text-[10px] text-muted-foreground">
<span className='font-mono text-[10px] text-muted-foreground'>
未关联路由
</span>
) : routesLoading && !route ? (
<span className="font-mono text-[10px] text-muted-foreground">
<span className='font-mono text-[10px] text-muted-foreground'>
加载中…
</span>
) : upstreams.length === 0 ? (
<span className="font-mono text-[10px] text-muted-foreground">
<span className='font-mono text-[10px] text-muted-foreground'>
未配置上游
</span>
) : (
<div className="flex flex-col gap-0">
<div className='flex flex-col gap-0'>
{upstreams.map((upstream) => (
<span
key={upstream}
className="truncate font-mono text-[10px] leading-tight text-muted-foreground"
className='truncate font-mono text-[10px] leading-tight text-muted-foreground'
title={upstream}
>
{upstream}
@@ -160,27 +175,27 @@ export function ZoneDomainsTable({
)}
</TableCell>
<TableCell
className="sticky right-0 z-10 bg-background py-1 text-center"
className='sticky right-0 z-10 bg-background py-1 text-center'
onClick={(event) => event.stopPropagation()}
>
<div className="flex items-center justify-center gap-0.5">
<div className='flex items-center justify-center gap-0.5'>
{domain.proxy_route_id ? (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-6 w-6 text-muted-foreground hover:text-foreground"
variant='ghost'
size='icon'
className='h-6 w-6 text-muted-foreground hover:text-foreground'
asChild
>
<Link
href={`/proxy-routes/detail?id=${domain.proxy_route_id}`}
>
<Eye className="size-3" />
<Eye className='size-3' />
</Link>
</Button>
</TooltipTrigger>
<TooltipContent side="top" className="text-xs">
<TooltipContent side='top' className='text-xs'>
查看路由详情
</TooltipContent>
</Tooltip>
@@ -189,15 +204,15 @@ export function ZoneDomainsTable({
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-6 w-6 text-muted-foreground hover:text-destructive"
variant='ghost'
size='icon'
className='h-6 w-6 text-muted-foreground hover:text-destructive'
onClick={() => setDeleting(domain)}
>
<Trash2 className="size-3" />
<Trash2 className='size-3' />
</Button>
</TooltipTrigger>
<TooltipContent side="top" className="text-xs">
<TooltipContent side='top' className='text-xs'>
删除域名
</TooltipContent>
</Tooltip>
@@ -236,9 +251,11 @@ export function ZoneDomainsTable({
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={remove.isPending}>取消</AlertDialogCancel>
<AlertDialogCancel disabled={remove.isPending}>
取消
</AlertDialogCancel>
<AlertDialogAction
className="bg-destructive text-white hover:bg-destructive/90"
className='bg-destructive text-white hover:bg-destructive/90'
disabled={remove.isPending || !deleting}
onClick={(event) => {
event.preventDefault();