fix(frontend): login P0 — 去卡头重复、offline 文案、显密可键盘
去掉卡内盾牌标题;后端不可用改为「服务暂不可用」并禁用登录钮;显密切换可 Tab 聚焦。
This commit is contained in:
1 parent
c759e111ec
commit
c1e21c20d8
3 files changed
+34
-15
No files matched your search
@@ -11,6 +11,7 @@ export default {
|
|||||||
collectors: 'Log Collectors',
|
collectors: 'Log Collectors',
|
||||||
logs: 'Log Query',
|
logs: 'Log Query',
|
||||||
alerts: 'Alerts',
|
alerts: 'Alerts',
|
||||||
|
analysis: 'Log Analysis',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
users: 'Users',
|
users: 'Users',
|
||||||
login: 'Sign In',
|
login: 'Sign In',
|
||||||
@@ -42,8 +43,10 @@ export default {
|
|||||||
errCredential: 'Invalid username or password',
|
errCredential: 'Invalid username or password',
|
||||||
errConn: 'Cannot reach the backend. Make sure it is running on port 8080.',
|
errConn: 'Cannot reach the backend. Make sure it is running on port 8080.',
|
||||||
errFallback: 'Sign-in failed',
|
errFallback: 'Sign-in failed',
|
||||||
backendDown: 'Backend is not running',
|
backendDown: 'Service temporarily unavailable',
|
||||||
backendDownHint: 'Cannot reach the API service. Start the backend first:',
|
showPassword: 'Show password',
|
||||||
|
hidePassword: 'Hide password',
|
||||||
|
backendDownHint: 'Cannot reach the service. Try again later or contact an admin.',
|
||||||
},
|
},
|
||||||
dialog: {
|
dialog: {
|
||||||
confirmTitle: 'Confirm Deletion',
|
confirmTitle: 'Confirm Deletion',
|
||||||
@@ -92,6 +95,17 @@ export default {
|
|||||||
spinner: {
|
spinner: {
|
||||||
default: 'Loading...',
|
default: 'Loading...',
|
||||||
},
|
},
|
||||||
|
range: {
|
||||||
|
lastMinutes: 'Last {{count}} minutes',
|
||||||
|
lastHours: 'Last {{count}} hours',
|
||||||
|
lastHours_one: 'Last {{count}} hour',
|
||||||
|
custom: 'Custom time',
|
||||||
|
title: 'Select time range',
|
||||||
|
start: 'Start time',
|
||||||
|
end: 'End time',
|
||||||
|
apply: 'Apply',
|
||||||
|
recent: 'Recently used',
|
||||||
|
},
|
||||||
password: {
|
password: {
|
||||||
hide: 'Hide password',
|
hide: 'Hide password',
|
||||||
show: 'Show password',
|
show: 'Show password',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export default {
|
|||||||
collectors: '日志采集',
|
collectors: '日志采集',
|
||||||
logs: '日志查询',
|
logs: '日志查询',
|
||||||
alerts: '日志告警',
|
alerts: '日志告警',
|
||||||
|
analysis: '日志分析',
|
||||||
settings: '系统设置',
|
settings: '系统设置',
|
||||||
users: '用户管理',
|
users: '用户管理',
|
||||||
login: '登录',
|
login: '登录',
|
||||||
@@ -42,8 +43,10 @@ export default {
|
|||||||
errCredential: '用户名或密码错误',
|
errCredential: '用户名或密码错误',
|
||||||
errConn: '无法连接后端服务,请确认后端已启动(端口 8080)。',
|
errConn: '无法连接后端服务,请确认后端已启动(端口 8080)。',
|
||||||
errFallback: '登录失败',
|
errFallback: '登录失败',
|
||||||
backendDown: '后端服务未启动',
|
backendDown: '服务暂不可用',
|
||||||
backendDownHint: '无法连接 API 服务,请先启动后端:',
|
showPassword: '显示密码',
|
||||||
|
hidePassword: '隐藏密码',
|
||||||
|
backendDownHint: '暂时连不上服务,请稍后再试或联系管理员。',
|
||||||
},
|
},
|
||||||
dialog: {
|
dialog: {
|
||||||
confirmTitle: '确认删除',
|
confirmTitle: '确认删除',
|
||||||
@@ -92,6 +95,16 @@ export default {
|
|||||||
spinner: {
|
spinner: {
|
||||||
default: '加载中...',
|
default: '加载中...',
|
||||||
},
|
},
|
||||||
|
range: {
|
||||||
|
lastMinutes: '最近 {{count}} 分钟',
|
||||||
|
lastHours: '最近 {{count}} 小时',
|
||||||
|
custom: '自定义时间',
|
||||||
|
title: '选择时间范围',
|
||||||
|
start: '开始时间',
|
||||||
|
end: '结束时间',
|
||||||
|
apply: '应用时间',
|
||||||
|
recent: '最近使用',
|
||||||
|
},
|
||||||
password: {
|
password: {
|
||||||
hide: '隐藏密码',
|
hide: '隐藏密码',
|
||||||
show: '显示密码',
|
show: '显示密码',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { memo, useCallback, useEffect, useState } from 'react'
|
import { memo, useCallback, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router'
|
import { useLocation, useNavigate } from 'react-router'
|
||||||
import { Activity, Eye, EyeOff, Shield, ServerOff } from 'lucide-react'
|
import { Activity, Eye, EyeOff, ServerOff } from 'lucide-react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Checkbox } from '@/components/ui/checkbox'
|
import { Checkbox } from '@/components/ui/checkbox'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
@@ -106,20 +106,12 @@ const Login = memo(function Login() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-warning">{t('login.backendDown')}</p>
|
<p className="text-sm font-medium text-warning">{t('login.backendDown')}</p>
|
||||||
<p className="text-xs text-warning mt-1">{t('login.backendDownHint')}</p>
|
<p className="text-xs text-warning mt-1">{t('login.backendDownHint')}</p>
|
||||||
<code className="block mt-2 px-3 py-2 bg-warning/20 rounded text-xs font-mono text-warning">
|
|
||||||
./run.sh
|
|
||||||
</code>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Login Card */}
|
{/* Login Card */}
|
||||||
<div className="bg-card rounded-2xl shadow-lg border border-border p-8">
|
<div className="bg-card rounded-2xl shadow-lg border border-border p-8">
|
||||||
<div className="flex items-center gap-2 mb-6">
|
|
||||||
<Shield className="w-5 h-5 text-primary" />
|
|
||||||
<h2 className="text-lg font-semibold text-foreground">{t('login.heading')}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 p-3 rounded-lg bg-destructive/10 border border-destructive/30 text-destructive text-sm">
|
<div className="mb-4 p-3 rounded-lg bg-destructive/10 border border-destructive/30 text-destructive text-sm">
|
||||||
{error}
|
{error}
|
||||||
@@ -157,7 +149,7 @@ const Login = memo(function Login() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={togglePassword}
|
onClick={togglePassword}
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
||||||
tabIndex={-1}
|
aria-label={showPassword ? t('login.hidePassword') : t('login.showPassword')}
|
||||||
>
|
>
|
||||||
{showPassword ? (
|
{showPassword ? (
|
||||||
<EyeOff className="w-4 h-4" />
|
<EyeOff className="w-4 h-4" />
|
||||||
@@ -182,7 +174,7 @@ const Login = memo(function Login() {
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full h-10 bg-primary hover:bg-primary/90 text-primary-foreground"
|
className="w-full h-10 bg-primary hover:bg-primary/90 text-primary-foreground"
|
||||||
disabled={loading}
|
disabled={loading || backendStatus === 'offline'}
|
||||||
>
|
>
|
||||||
{loading ? t('login.submitting') : t('login.submit')}
|
{loading ? t('login.submitting') : t('login.submit')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in new issue
Block a user