feat: improve accessibility and mobile responsiveness across UI components

Enhanced dialog accessibility by adding descriptive text to all dialog components. Implemented responsive layouts for mobile devices including card-based user table, adaptive navigation bar, and improved dialog spacing. Fixed Aliyun TTS health check to use WebSocket-based connectivity testing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 18:03:38 +08:00
parent e7b3700a28
commit d8a9f277be
11 changed files with 172 additions and 77 deletions

View File

@@ -28,60 +28,115 @@ export function UserTable({ users, isLoading, onEdit, onDelete }: UserTableProps
}
return (
<div className="overflow-x-auto">
<table className="w-full">
<thead className="border-b">
<tr className="text-left">
<th className="px-4 py-3 font-medium">ID</th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium text-right"></th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id} className="border-b hover:bg-muted/50">
<td className="px-4 py-3">{user.id}</td>
<td className="px-4 py-3">{user.username}</td>
<td className="px-4 py-3">{user.email}</td>
<td className="px-4 py-3">
<>
<div className="hidden md:block overflow-x-auto">
<table className="w-full">
<thead className="border-b">
<tr className="text-left">
<th className="px-4 py-3 font-medium">ID</th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium"></th>
<th className="px-4 py-3 font-medium text-right"></th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id} className="border-b hover:bg-muted/50">
<td className="px-4 py-3">{user.id}</td>
<td className="px-4 py-3">{user.username}</td>
<td className="px-4 py-3">{user.email}</td>
<td className="px-4 py-3">
<Badge variant={user.is_active ? 'default' : 'secondary'}>
{user.is_active ? '活跃' : '停用'}
</Badge>
</td>
<td className="px-4 py-3">
<Badge variant={user.is_superuser ? 'destructive' : 'outline'}>
{user.is_superuser ? '超级管理员' : '普通用户'}
</Badge>
</td>
<td className="px-4 py-3">
{new Date(user.created_at).toLocaleString('zh-CN')}
</td>
<td className="px-4 py-3">
<div className="flex justify-end gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => onEdit(user)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(user)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="md:hidden space-y-4">
{users.map((user) => (
<div key={user.id} className="border rounded-lg p-4 space-y-3">
<div className="flex items-center justify-between">
<div className="font-medium">{user.username}</div>
<div className="flex gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => onEdit(user)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(user)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-muted-foreground">ID:</span>
<span>{user.id}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">:</span>
<span className="truncate ml-2">{user.email}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-muted-foreground">:</span>
<Badge variant={user.is_active ? 'default' : 'secondary'}>
{user.is_active ? '活跃' : '停用'}
</Badge>
</td>
<td className="px-4 py-3">
</div>
<div className="flex justify-between items-center">
<span className="text-muted-foreground">:</span>
<Badge variant={user.is_superuser ? 'destructive' : 'outline'}>
{user.is_superuser ? '超级管理员' : '普通用户'}
</Badge>
</td>
<td className="px-4 py-3">
{new Date(user.created_at).toLocaleString('zh-CN')}
</td>
<td className="px-4 py-3">
<div className="flex justify-end gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => onEdit(user)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(user)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">:</span>
<span className="text-xs">{new Date(user.created_at).toLocaleString('zh-CN')}</span>
</div>
</div>
</div>
))}
</div>
</>
)
}