diff --git a/mobile-next/lib/company/auth/company_login_logic.dart b/mobile-next/lib/company/auth/company_login_logic.dart index 873e0df..1916f74 100644 --- a/mobile-next/lib/company/auth/company_login_logic.dart +++ b/mobile-next/lib/company/auth/company_login_logic.dart @@ -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(); @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 submit() async { if (submitting.value) return; final staffNo = staffCtrl.text.trim(); @@ -58,10 +70,10 @@ class CompanyLoginLogic extends GetxController { Get.find().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; } diff --git a/mobile-next/lib/company/ui/company_login_page.dart b/mobile-next/lib/company/ui/company_login_page.dart index ed73103..b603343 100644 --- a/mobile-next/lib/company/ui/company_login_page.dart +++ b/mobile-next/lib/company/ui/company_login_page.dart @@ -16,77 +16,94 @@ class CompanyLoginPage extends StatelessWidget { final logic = Get.find(); 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), + ), + ), ), ), ), ); - }, - ), + }), + ], ), ); }