feat(a11y): 设置页无障碍审计并修复开关可访问名称

axe 结构性规则扩展到设置页(安全 Tab + 其他 Tab):
- security-tab 8 个 Switch/SelectTrigger 补可访问名称(Label htmlFor 关联 + aria-label)
- other-tab / auth-source-modal 各 1 个未命名 Switch 补 aria-label
- 新增 2 个 axe 测试,vitest 126 全绿
- 翻译键 loginCaptchaEnabled 加入 fragments(admin.zh-CN/en)
This commit is contained in:
ryan
2026-08-17 00:02:51 +08:00
parent e7b8fb2f99
commit 3de0a54d47
8 changed files with 117 additions and 14 deletions
@@ -180,6 +180,7 @@ export function AuthSourceModal({
</div>
</div>
<Switch
aria-label={t('enableAuthSource')}
checked={form.is_active}
onCheckedChange={(checked) =>
setForm((prev) => ({ ...prev, is_active: checked }))
@@ -314,6 +314,7 @@ export function OtherTab({ configs }: OtherTabProps) {
</div>
<div className='flex items-center'>
<Switch
aria-label={tNav(item.labelKey)}
checked={checked}
disabled={
isReadOnly || updateMenuConfigMutation.isPending
@@ -329,15 +329,19 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
<div className='space-y-1'>
<div className='flex items-center gap-2'>
{Icon && <Icon className='size-4 text-primary' />}
<span className='font-medium text-sm text-foreground'>
<Label
htmlFor={item.key}
className='font-medium text-sm text-foreground'
>
{t(item.titleKey)}
</span>
</Label>
</div>
<p className='text-xs text-muted-foreground leading-relaxed pr-2'>
{t(item.descKey)}
</p>
</div>
<Switch
id={item.key}
checked={checked}
disabled={updateConfigMutation.isPending}
onCheckedChange={(value) => handleToggle(item.key, value)}
@@ -366,7 +370,10 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
disabled={updateTTLMutation.isPending}
onValueChange={handleTTLChange}
>
<SelectTrigger className='w-[180px] bg-card border-dashed text-xs h-8'>
<SelectTrigger
className='w-[180px] bg-card border-dashed text-xs h-8'
aria-label={t('loginSessionTTL')}
>
<SelectValue placeholder={t('selectRetentionTime')} />
</SelectTrigger>
<SelectContent>
@@ -554,15 +561,22 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
onCheckedChange={(checked) =>
handleToggle('cap_login_enabled', checked)
}
aria-label={t('loginCaptchaEnabled')}
/>
</CardHeader>
<CardContent className='pt-6'>
{/* 自动开始计算 Switch */}
<div className='flex items-center justify-between rounded-xl border border-dashed p-4 bg-card mb-4'>
<div className='space-y-0.5'>
<p className='text-sm font-semibold'>{t('autoStartSolving')}</p>
<Label htmlFor='cap_auto_solve' className='text-sm font-semibold'>
{t('autoStartSolving')}
</Label>
</div>
<Switch checked={capAutoSolve} onCheckedChange={setCapAutoSolve} />
<Switch
id='cap_auto_solve'
checked={capAutoSolve}
onCheckedChange={setCapAutoSolve}
/>
</div>
<form onSubmit={handleCapSave} className='space-y-6'>
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>