fix(frontend): 优化前端组件和国际化支持

- 添加 Accept-Language 请求头支持后端翻译
- 优化账户状态指示器和测试模态框
- 简化用户属性表单和配置模态框
- 新增多个国际化翻译条目
- 重构管理视图代码,提升可维护性
This commit is contained in:
IanShaw027
2026-01-04 20:49:34 +08:00
parent 4df712624e
commit 6c036d7b59
14 changed files with 189 additions and 142 deletions

View File

@@ -31,47 +31,29 @@
</div>
<!-- Role Filter (visible when enabled) -->
<div v-if="visibleFilters.has('role')" class="relative">
<select
<div v-if="visibleFilters.has('role')" class="w-32">
<Select
v-model="filters.role"
:options="[
{ value: '', label: t('admin.users.allRoles') },
{ value: 'admin', label: t('admin.users.admin') },
{ value: 'user', label: t('admin.users.user') }
]"
@change="applyFilter"
class="input w-32 cursor-pointer appearance-none pr-8"
>
<option value="">{{ t('admin.users.allRoles') }}</option>
<option value="admin">{{ t('admin.users.admin') }}</option>
<option value="user">{{ t('admin.users.user') }}</option>
</select>
<svg
class="pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
stroke-width="1.5"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
/>
</div>
<!-- Status Filter (visible when enabled) -->
<div v-if="visibleFilters.has('status')" class="relative">
<select
<div v-if="visibleFilters.has('status')" class="w-32">
<Select
v-model="filters.status"
:options="[
{ value: '', label: t('admin.users.allStatus') },
{ value: 'active', label: t('common.active') },
{ value: 'disabled', label: t('admin.users.disabled') }
]"
@change="applyFilter"
class="input w-32 cursor-pointer appearance-none pr-8"
>
<option value="">{{ t('admin.users.allStatus') }}</option>
<option value="active">{{ t('common.active') }}</option>
<option value="disabled">{{ t('admin.users.disabled') }}</option>
</select>
<svg
class="pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
stroke-width="1.5"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
/>
</div>
<!-- Dynamic Attribute Filters -->
@@ -98,29 +80,16 @@
/>
<!-- Select/Multi-select type -->
<template v-else-if="['select', 'multi_select'].includes(getAttributeDefinition(Number(attrId))?.type || '')">
<select
:value="value"
@change="(e) => { updateAttributeFilter(Number(attrId), (e.target as HTMLSelectElement).value); applyFilter() }"
class="input w-36 cursor-pointer appearance-none pr-8"
>
<option value="">{{ getAttributeDefinitionName(Number(attrId)) }}</option>
<option
v-for="opt in getAttributeDefinition(Number(attrId))?.options || []"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</option>
</select>
<svg
class="pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
stroke-width="1.5"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
<div class="w-36">
<Select
:model-value="value"
:options="[
{ value: '', label: getAttributeDefinitionName(Number(attrId)) },
...(getAttributeDefinition(Number(attrId))?.options || [])
]"
@update:model-value="(val) => { updateAttributeFilter(Number(attrId), String(val ?? '')); applyFilter() }"
/>
</div>
</template>
<!-- Fallback -->
<input
@@ -337,7 +306,7 @@
<template #cell-role="{ value }">
<span :class="['badge', value === 'admin' ? 'badge-purple' : 'badge-gray']">
{{ value }}
{{ t('admin.users.roles.' + value) }}
</span>
</template>
@@ -1419,6 +1388,7 @@ import BaseDialog from '@/components/common/BaseDialog.vue'
import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
import EmptyState from '@/components/common/EmptyState.vue'
import GroupBadge from '@/components/common/GroupBadge.vue'
import Select from '@/components/common/Select.vue'
import UserAttributesConfigModal from '@/components/user/UserAttributesConfigModal.vue'
import UserAttributeForm from '@/components/user/UserAttributeForm.vue'