fix: 移除logo白色背景 + 优化登录页面UI和中文化
Logo修复: - 移除 logo.svg 中的白色背景矩形 (fill="#ffffff") - Logo 现在为透明背景,在深色主题上正确显示 登录页面优化: - 添加 "iAgent" 品牌标题 (28px, bold, 带字间距) - 副标题改为中文 "服务器集群运维智能体" - 表单中文化: 邮箱/密码/登录 - 错误提示改为带背景色的卡片样式 (红色图标+文字) - 添加邮箱输入框 placeholder (user@example.com) - 密码框支持回车提交 - 底部提示: "账号由管理员在后台创建或通过邀请链接注册" - 限制表单最大宽度 360px,外层改用 SingleChildScrollView 防溢出 用户账号说明: App 端不提供自助注册功能,用户账号通过以下方式创建: 1. 管理员在 Web 后台 (用户管理页) 直接创建 2. 管理员发送邀请链接,用户通过链接注册 3. 通过 Web 端自助注册 (可选填公司名创建新租户) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5d12ada262
commit
68d0c9d6f7
|
|
@ -1,7 +1,4 @@
|
||||||
<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<!-- Background -->
|
|
||||||
<rect width="400" height="400" fill="#ffffff"/>
|
|
||||||
|
|
||||||
<!-- Antenna stick -->
|
<!-- Antenna stick -->
|
||||||
<line x1="200" y1="88" x2="200" y2="58" stroke="#3CC98C" stroke-width="7" stroke-linecap="round"/>
|
<line x1="200" y1="88" x2="200" y2="58" stroke="#3CC98C" stroke-width="7" stroke-linecap="round"/>
|
||||||
<!-- Antenna ball -->
|
<!-- Antenna ball -->
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
|
@ -24,81 +24,134 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColors.background,
|
backgroundColor: AppColors.background,
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Padding(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 48),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: ConstrainedBox(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
constraints: const BoxConstraints(maxWidth: 360),
|
||||||
children: [
|
child: Column(
|
||||||
SvgPicture.asset(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
'assets/icons/logo.svg',
|
children: [
|
||||||
width: 100,
|
SvgPicture.asset(
|
||||||
height: 100,
|
'assets/icons/logo.svg',
|
||||||
),
|
width: 96,
|
||||||
const SizedBox(height: 8),
|
height: 96,
|
||||||
const Text(
|
|
||||||
'Operations Intelligent Agent',
|
|
||||||
style: TextStyle(color: AppColors.textSecondary),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 48),
|
|
||||||
TextFormField(
|
|
||||||
controller: _emailController,
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Email',
|
|
||||||
prefixIcon: Icon(Icons.email),
|
|
||||||
),
|
),
|
||||||
validator: (value) {
|
const SizedBox(height: 12),
|
||||||
if (value == null || value.isEmpty) {
|
const Text(
|
||||||
return 'Please enter your email';
|
'iAgent',
|
||||||
}
|
style: TextStyle(
|
||||||
if (!value.contains('@')) {
|
color: AppColors.textPrimary,
|
||||||
return 'Please enter a valid email';
|
fontSize: 28,
|
||||||
}
|
fontWeight: FontWeight.bold,
|
||||||
return null;
|
letterSpacing: 2,
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 4),
|
||||||
TextFormField(
|
const Text(
|
||||||
controller: _passwordController,
|
'服务器集群运维智能体',
|
||||||
obscureText: true,
|
style: TextStyle(
|
||||||
decoration: const InputDecoration(
|
color: AppColors.textSecondary,
|
||||||
labelText: 'Password',
|
fontSize: 14,
|
||||||
prefixIcon: Icon(Icons.lock),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 48),
|
||||||
|
TextFormField(
|
||||||
|
controller: _emailController,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: '邮箱',
|
||||||
|
hintText: 'user@example.com',
|
||||||
|
prefixIcon: Icon(Icons.email_outlined),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return '请输入邮箱地址';
|
||||||
|
}
|
||||||
|
if (!value.contains('@')) {
|
||||||
|
return '请输入有效的邮箱地址';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Please enter your password';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (authState.error != null) ...[
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _passwordController,
|
||||||
|
obscureText: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: '密码',
|
||||||
|
prefixIcon: Icon(Icons.lock_outline),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return '请输入密码';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onFieldSubmitted: (_) => _handleLogin(),
|
||||||
|
),
|
||||||
|
if (authState.error != null) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.error.withAlpha(25),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.error_outline,
|
||||||
|
color: AppColors.error, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
authState.error!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.error,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 48,
|
||||||
|
child: FilledButton(
|
||||||
|
onPressed: authState.isLoading ? null : _handleLogin,
|
||||||
|
child: authState.isLoading
|
||||||
|
? const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Text(
|
||||||
|
'登录',
|
||||||
|
style: TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
Text(
|
Text(
|
||||||
authState.error!,
|
'账号由管理员在后台创建或通过邀请链接注册',
|
||||||
style: const TextStyle(color: Colors.red),
|
style: TextStyle(
|
||||||
|
color: AppColors.textMuted,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 24),
|
),
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: FilledButton(
|
|
||||||
onPressed: authState.isLoading ? null : _handleLogin,
|
|
||||||
child: authState.isLoading
|
|
||||||
? const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const Text('Login'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue