fix(mobile-next): 登录失败改为顶部 toast,2 秒后自动消失

改 company_login_page.dart 与 company_login_logic.dart。
保留「工号或密码不正确」「网络异常,请稍后重试」;去掉按钮下方常驻错误字。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
编码工程师
2026-08-20 02:49:48 +08:00
co-authored by Cursor multica-agent
parent 87a5930906
commit 092f513708
2 changed files with 97 additions and 68 deletions
@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:openim/core/controller/im_controller.dart';
@@ -15,12 +17,14 @@ class CompanyLoginLogic extends GetxController {
final staffError = RxnString();
final pwdError = RxnString();
final toast = RxnString();
Timer? _toastTimer;
final _auth = AuthApi();
final _im = Get.find<IMController>();
@override
void onClose() {
_toastTimer?.cancel();
staffCtrl.dispose();
pwdCtrl.dispose();
super.onClose();
@@ -28,6 +32,14 @@ class CompanyLoginLogic extends GetxController {
void toggleObscure() => obscure.toggle();
void _showToast(String msg) {
toast.value = msg;
_toastTimer?.cancel();
_toastTimer = Timer(const Duration(seconds: 2), () {
toast.value = null;
});
}
Future<void> submit() async {
if (submitting.value) return;
final staffNo = staffCtrl.text.trim();
@@ -58,10 +70,10 @@ class CompanyLoginLogic extends GetxController {
Get.find<CacheController>().resetCache();
AppNavigator.startMain(conversations: conversations);
} on AuthException catch (e) {
toast.value = e.network ? '网络异常,请稍后重试' : '工号或密码不正确';
_showToast(e.network ? '网络异常,请稍后重试' : '工号或密码不正确');
} catch (e, s) {
Logger.print('company login e: $e $s');
toast.value = '网络异常,请稍后重试';
_showToast('网络异常,请稍后重试');
} finally {
submitting.value = false;
}
@@ -16,77 +16,94 @@ class CompanyLoginPage extends StatelessWidget {
final logic = Get.find<CompanyLoginLogic>();
return Scaffold(
backgroundColor: AppColors.pageBg,
body: SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: AppGap.x8),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
children: [
const Spacer(flex: 2),
_logo(),
const SizedBox(height: AppGap.x4),
Text(
FeatureFlags.brandMigration ? '畅联' : 'OpenIM',
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w700,
color: AppColors.textPrimary,
),
),
const SizedBox(height: AppGap.x1),
const Text(
'企业内部通讯',
style: TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary),
),
const SizedBox(height: AppGap.x8),
Obx(() => _field(
controller: logic.staffCtrl,
hint: '请输入工号',
icon: Icons.person_outline,
error: logic.staffError.value,
enabled: !logic.submitting.value,
)),
const SizedBox(height: AppGap.x3),
Obx(() => _field(
controller: logic.pwdCtrl,
hint: '请输入密码',
icon: Icons.lock_outline,
obscure: logic.obscure.value,
onToggleObscure: logic.toggleObscure,
error: logic.pwdError.value,
enabled: !logic.submitting.value,
onSubmitted: (_) => logic.submit(),
)),
const SizedBox(height: AppGap.x4),
Obx(() => _loginButton(logic)),
const SizedBox(height: AppGap.x3),
const Text(
'登录即代表同意内部使用规范',
style: TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary),
),
Obx(() {
final msg = logic.toast.value;
if (msg == null) return const SizedBox.shrink();
return Padding(
padding: const EdgeInsets.only(top: AppGap.x3),
child: Text(
msg,
style: const TextStyle(fontSize: AppFont.sub, color: AppColors.danger),
body: Stack(
children: [
SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: AppGap.x8),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
children: [
const Spacer(flex: 2),
_logo(),
const SizedBox(height: AppGap.x4),
Text(
FeatureFlags.brandMigration ? '畅联' : 'OpenIM',
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w700,
color: AppColors.textPrimary,
),
),
);
}),
const Spacer(flex: 3),
],
const SizedBox(height: AppGap.x1),
const Text(
'企业内部通讯',
style: TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary),
),
const SizedBox(height: AppGap.x8),
Obx(() => _field(
controller: logic.staffCtrl,
hint: '请输入工号',
icon: Icons.person_outline,
error: logic.staffError.value,
enabled: !logic.submitting.value,
)),
const SizedBox(height: AppGap.x3),
Obx(() => _field(
controller: logic.pwdCtrl,
hint: '请输入密码',
icon: Icons.lock_outline,
obscure: logic.obscure.value,
onToggleObscure: logic.toggleObscure,
error: logic.pwdError.value,
enabled: !logic.submitting.value,
onSubmitted: (_) => logic.submit(),
)),
const SizedBox(height: AppGap.x4),
Obx(() => _loginButton(logic)),
const SizedBox(height: AppGap.x3),
const Text(
'登录即代表同意内部使用规范',
style: TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary),
),
const Spacer(flex: 3),
],
),
),
),
);
},
),
),
Obx(() {
final msg = logic.toast.value;
if (msg == null) return const SizedBox.shrink();
return SafeArea(
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.fromLTRB(AppGap.x4, AppGap.x2, AppGap.x4, 0),
child: Material(
color: AppColors.bannerBg,
borderRadius: BorderRadius.circular(AppRadius.control),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: AppGap.x4, vertical: AppGap.x3),
child: Text(
msg,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: AppFont.sub, color: Colors.white),
),
),
),
),
),
);
},
),
}),
],
),
);
}