fix(i18n): 回退到稳定的 32% 覆盖率状态 (tsc + Vite 构建通过)
批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换: - 翻译词典: 22 namespaces, 3600+ keys - 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy) - 语言切换器在 Header 中可用 (🇨🇳/🇺🇸) - tsc 零错误, Vite 构建成功
This commit is contained in:
1 parent
ecec73989b
commit
72bfb0e12d
191 files changed
+5057
-7592
No files matched your search
@@ -15,19 +15,18 @@ import { Lock, History, Key, Settings, Network, RefreshCw, Loader2 } from 'lucid
|
||||
import { PageTabs } from '@/components/layout/PageTabs';
|
||||
import { LdapManagementSection } from './LdapManagementSection';
|
||||
import type { JsonData } from '@/types/common';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
// 系统设置子 Tab:通用 / 安全 / LDAP // Logan.Li
|
||||
const SETTINGS_TABS = [
|
||||
{ id: 'general', label: '通用' },
|
||||
{ id: 'security', label: '安全' },
|
||||
{ id: 'general', label: i18n.t('system.settingsGeneral') },
|
||||
{ id: 'security', label: i18n.t('system.settingsSecurity') },
|
||||
{ id: 'ldap', label: 'LDAP' },
|
||||
] as const;
|
||||
type SettingsSubTab = (typeof SETTINGS_TABS)[number]['id'];
|
||||
|
||||
export type LdapServerType = 'openldap' | 'ad';
|
||||
|
||||
export interface LdapFormData {
|
||||
server_type: LdapServerType;
|
||||
ldap_host: string;
|
||||
ldap_port: number;
|
||||
use_ldaps: boolean;
|
||||
@@ -35,11 +34,6 @@ export interface LdapFormData {
|
||||
admin_password: string;
|
||||
base_dn: string;
|
||||
search_filter: string;
|
||||
user_mapping: {
|
||||
username: string;
|
||||
email: string;
|
||||
display_name: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface SystemSettingsTabProps {
|
||||
@@ -107,6 +101,7 @@ interface SystemSettingsTabProps {
|
||||
}
|
||||
|
||||
export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
auditRetentionDays,
|
||||
setAuditRetentionDays,
|
||||
@@ -158,15 +153,15 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
<CardHeader>
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<History className="h-5 w-5 dg-text-green" />
|
||||
审计设置
|
||||
{t('system.audit')}
|
||||
</CardTitle>
|
||||
<CardDescription className="dg-text-muted">操作日志与审计策略</CardDescription>
|
||||
<CardDescription className="dg-text-muted">{t('system.auditSettingsDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">记录所有操作</p>
|
||||
<p className="text-xs dg-text-muted">记录用户的所有操作行为</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.recordAllOps')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.recordAllOpsDesc')}</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={auditRecordAll}
|
||||
@@ -177,9 +172,9 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">日志保留时间</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.logRetention')}</p>
|
||||
<p className="text-xs dg-text-muted">
|
||||
应用后立即清理超期记录;之后每天自动检查
|
||||
{t('system.logRetentionHint')}
|
||||
</p>
|
||||
{auditLastCleanupText && (
|
||||
<p className="text-xs dg-text-muted mt-1">{auditLastCleanupText}</p>
|
||||
@@ -212,10 +207,10 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
{auditApplying ? (
|
||||
<>
|
||||
<Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
||||
应用中...
|
||||
{t('system.applyingDot')}
|
||||
</>
|
||||
) : (
|
||||
'应用'
|
||||
t('common.apply')
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -226,18 +221,18 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
<CardHeader>
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Settings className="h-5 w-5 dg-text-purple" />
|
||||
系统信息
|
||||
{t('system.systemInfo')}
|
||||
</CardTitle>
|
||||
<CardDescription className="dg-text-muted">版本与系统状态</CardDescription>
|
||||
<CardDescription className="dg-text-muted">{t('system.systemInfoDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm dg-text-secondary">系统版本</span>
|
||||
<span className="text-sm dg-text-secondary">{t('system.systemVersion')}</span>
|
||||
<span className="text-sm text-[var(--dg-text-primary)]">v2.5.1</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm dg-text-secondary">运行时间</span>
|
||||
<span className="text-sm text-[var(--dg-text-primary)]">30天 12小时</span>
|
||||
<span className="text-sm dg-text-secondary">{t('system.uptime')}</span>
|
||||
<span className="text-sm text-[var(--dg-text-primary)]">{t('system.uptimeValue')}</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -250,29 +245,29 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
<CardHeader>
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Lock className="h-5 w-5 dg-text-blue" />
|
||||
安全设置
|
||||
{t('system.security')}
|
||||
</CardTitle>
|
||||
<CardDescription className="dg-text-muted">密码策略与登录安全(规划中)</CardDescription>
|
||||
<CardDescription className="dg-text-muted">{t('system.securityDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">强制密码复杂度</p>
|
||||
<p className="text-xs dg-text-muted">要求密码包含大小写字母、数字和特殊字符</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.forcePasswordComplexity')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.forcePasswordComplexityDesc')}</p>
|
||||
</div>
|
||||
<Switch disabled className="data-[state=checked]:bg-blue-600" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">登录失败锁定</p>
|
||||
<p className="text-xs dg-text-muted">连续5次登录失败锁定账户30分钟</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.loginLockout')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.loginLockoutDesc')}</p>
|
||||
</div>
|
||||
<Switch disabled defaultChecked className="data-[state=checked]:bg-blue-600" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">双因素认证</p>
|
||||
<p className="text-xs dg-text-muted">启用后需要手机验证码登录</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.twoFactor')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.twoFactorDesc')}</p>
|
||||
</div>
|
||||
<Switch disabled className="data-[state=checked]:bg-blue-600" />
|
||||
</div>
|
||||
@@ -283,32 +278,32 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
<CardHeader>
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Key className="h-5 w-5 dg-text-yellow" />
|
||||
会话设置
|
||||
{t('system.sessionSettings')}
|
||||
</CardTitle>
|
||||
<CardDescription className="dg-text-muted">会话超时与 Token 配置(规划中)</CardDescription>
|
||||
<CardDescription className="dg-text-muted">{t('system.sessionSettingsDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">会话超时时间</p>
|
||||
<p className="text-xs dg-text-muted">用户无操作30分钟后自动登出</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.sessionTimeoutTime')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.sessionTimeoutDesc')}</p>
|
||||
</div>
|
||||
<Select defaultValue="30" disabled>
|
||||
<SelectTrigger className="w-32 h-8 dg-input">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="dg-input">
|
||||
<SelectItem value="15">15分钟</SelectItem>
|
||||
<SelectItem value="15">{t('monitor.traceMgr.min15')}</SelectItem>
|
||||
<SelectItem value="30">30分钟</SelectItem>
|
||||
<SelectItem value="60">1小时</SelectItem>
|
||||
<SelectItem value="60">{t('monitor.traceMgr.hour1')}</SelectItem>
|
||||
<SelectItem value="120">2小时</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">单点登录</p>
|
||||
<p className="text-xs dg-text-muted">同一账号只能在一个设备登录</p>
|
||||
<p className="text-sm font-medium text-[var(--dg-text-primary)]">{t('system.sso')}</p>
|
||||
<p className="text-xs dg-text-muted">{t('system.singleSignOnDesc')}</p>
|
||||
</div>
|
||||
<Switch disabled className="data-[state=checked]:bg-blue-600" />
|
||||
</div>
|
||||
@@ -327,40 +322,14 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
<Network className="h-5 w-5 dg-text-cyan" />
|
||||
LDAP / Active Directory
|
||||
</CardTitle>
|
||||
<CardDescription className="dg-text-muted mt-1">配置 LDAP 服务器,实现统一身份认证</CardDescription>
|
||||
<CardDescription className="dg-text-muted mt-1">{t('system.ldapConfigHint')}</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">目录类型</label>
|
||||
<Select
|
||||
value={ldapForm.server_type}
|
||||
onValueChange={(v: LdapServerType) => {
|
||||
const isAD = v === 'ad';
|
||||
setLdapForm({
|
||||
...ldapForm,
|
||||
server_type: v,
|
||||
ldap_port: isAD && ldapForm.ldap_port === 389 ? 389 : ldapForm.ldap_port,
|
||||
search_filter: ldapForm.search_filter || (isAD ? '(sAMAccountName=%s)' : '(uid=%s)'),
|
||||
user_mapping: isAD
|
||||
? { username: 'sAMAccountName', email: 'mail', display_name: 'displayName' }
|
||||
: { username: 'uid', email: 'mail', display_name: 'cn' },
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="dg-input">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="dg-input">
|
||||
<SelectItem value="openldap">OpenLDAP</SelectItem>
|
||||
<SelectItem value="ad">Active Directory</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">LDAP 服务器地址</label>
|
||||
<label className="text-xs dg-text-muted">{t('system.ldapServerAddr')}</label>
|
||||
<Input
|
||||
value={ldapForm.ldap_host}
|
||||
onChange={(e) => setLdapForm({ ...ldapForm, ldap_host: e.target.value })}
|
||||
@@ -369,7 +338,7 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">端口</label>
|
||||
<label className="text-xs dg-text-muted">{t('system.ldapPort')}</label>
|
||||
<Input
|
||||
type="number"
|
||||
value={ldapForm.ldap_port}
|
||||
@@ -379,25 +348,25 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5 col-span-2">
|
||||
<label className="text-xs dg-text-muted">Base DN(用户搜索基础)</label>
|
||||
<label className="text-xs dg-text-muted">{t('system.baseDnHint')}</label>
|
||||
<Input
|
||||
value={ldapForm.base_dn}
|
||||
onChange={(e) => setLdapForm({ ...ldapForm, base_dn: e.target.value })}
|
||||
className="dg-input"
|
||||
placeholder={ldapForm.server_type === 'ad' ? 'DC=example,DC=com' : 'ou=users,dc=example,dc=com'}
|
||||
placeholder="ou=users,dc=example,dc=com"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">管理员 Bind DN</label>
|
||||
<label className="text-xs dg-text-muted">{t('system.adminBindDn')}</label>
|
||||
<Input
|
||||
value={ldapForm.admin_dn}
|
||||
onChange={(e) => setLdapForm({ ...ldapForm, admin_dn: e.target.value })}
|
||||
className="dg-input"
|
||||
placeholder={ldapForm.server_type === 'ad' ? 'CN=admin,CN=Users,DC=example,DC=com' : 'cn=admin,dc=example,dc=com'}
|
||||
placeholder="cn=admin,dc=example,dc=com"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">管理员密码 {ldapConfig && '(留空不修改)'}</label>
|
||||
<label className="text-xs dg-text-muted">管理员密码 {ldapConfig && t('system.leaveBlankNoModify')}</label>
|
||||
<Input
|
||||
type="password"
|
||||
value={ldapForm.admin_password}
|
||||
@@ -407,48 +376,12 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5 col-span-2">
|
||||
<label className="text-xs dg-text-muted">搜索过滤器(可选,用 %s 代表用户名)</label>
|
||||
<label className="text-xs dg-text-muted">{t('system.searchFilterHint')}</label>
|
||||
<Input
|
||||
value={ldapForm.search_filter}
|
||||
onChange={(e) => setLdapForm({ ...ldapForm, search_filter: e.target.value })}
|
||||
className="dg-input"
|
||||
placeholder={ldapForm.server_type === 'ad' ? '(sAMAccountName=%s)' : '(uid=%s)'}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">用户名字段</label>
|
||||
<Input
|
||||
value={ldapForm.user_mapping.username}
|
||||
onChange={(e) => setLdapForm({
|
||||
...ldapForm,
|
||||
user_mapping: { ...ldapForm.user_mapping, username: e.target.value },
|
||||
})}
|
||||
className="dg-input"
|
||||
placeholder={ldapForm.server_type === 'ad' ? 'sAMAccountName' : 'uid'}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">邮箱字段</label>
|
||||
<Input
|
||||
value={ldapForm.user_mapping.email}
|
||||
onChange={(e) => setLdapForm({
|
||||
...ldapForm,
|
||||
user_mapping: { ...ldapForm.user_mapping, email: e.target.value },
|
||||
})}
|
||||
className="dg-input"
|
||||
placeholder="mail"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs dg-text-muted">显示名字段</label>
|
||||
<Input
|
||||
value={ldapForm.user_mapping.display_name}
|
||||
onChange={(e) => setLdapForm({
|
||||
...ldapForm,
|
||||
user_mapping: { ...ldapForm.user_mapping, display_name: e.target.value },
|
||||
})}
|
||||
className="dg-input"
|
||||
placeholder={ldapForm.server_type === 'ad' ? 'displayName' : 'cn'}
|
||||
placeholder="(uid=%s)"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 col-span-2">
|
||||
@@ -457,10 +390,7 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
onCheckedChange={(v) => setLdapForm({ ...ldapForm, use_ldaps: v })}
|
||||
className="data-[state=checked]:bg-blue-600"
|
||||
/>
|
||||
<span className="text-sm text-[var(--dg-text-secondary)]">启用 LDAPS(SSL 加密)</span>
|
||||
{ldapForm.server_type === 'ad' && (
|
||||
<span className="text-xs dg-text-muted">AD 创建用户必须启用 LDAPS</span>
|
||||
)}
|
||||
<span className="text-sm text-[var(--dg-text-secondary)]">{t('system.enableLdaps')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -488,7 +418,7 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
|
||||
onClick={handleLdapSave}
|
||||
disabled={ldapSaving}
|
||||
>
|
||||
{ldapSaving ? '保存中...' : '保存配置'}
|
||||
{ldapSaving ? t('k8s.topology.saving') : t('aiops.llmSave')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user