import 'package:flutter/material.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:ln_jq_app/common/login_util.dart'; import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/common/styles/theme.dart'; import 'package:ln_jq_app/pages/b_page/base_widgets/view.dart'; import 'package:ln_jq_app/pages/c_page/base_widgets/view.dart'; import 'package:ln_jq_app/pages/login/controller.dart'; import 'package:ln_jq_app/storage_service.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } class _LoginPageState extends State with SingleTickerProviderStateMixin { late TabController tabController; bool cLogin = true; bool _obscureText = true; // 用于管理“记住密码”的复选框状态 bool _rememberPassword = true; // 用于确保凭证只在首次加载时回填一次 bool _credentialsLoaded = false; @override void initState() { super.initState(); tabController = TabController(length: 2, vsync: this); tabController.addListener(_tabChangeListener); } void _tabChangeListener() { if (!tabController.indexIsChanging) { switchTab(tabController.index); } } void switchTab(int index) { setState(() { cLogin = (index == 0); }); } @override void dispose() { tabController.dispose(); super.dispose(); } Widget _buildView(LoginController controller) { // 在视图构建时,检查并回填已保存的凭证 if (!_credentialsLoaded) { final savedAccount = StorageService.to.stationAccount; final savedPassword = StorageService.to.stationPassword; if (savedAccount != null && savedPassword != null) { controller.stationIdController.text = savedAccount; controller.passwordController.text = savedPassword; _rememberPassword = true; // 如果有保存的密码,则默认勾选 } _credentialsLoaded = true; // 标记为已加载,防止重复执行 } return Container( color: Color(0xFFEFF4F7), child: [ Icon(cLogin ? AntdIcon.car : AntdIcon.USB), SizedBox(height: 5.h), TextX.bodyLarge(cLogin ? '司机端' : "加氢站", weight: FontWeight.w700), SizedBox(height: 5.h), TextX.bodyLarge(cLogin ? '安全驾驶·智能服务' : "氢能服务·专业运营"), Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), // 设置圆角弧度 ), margin: EdgeInsets.all(15), elevation: 4, child: Container( height: cLogin ? 285.h : 360.h, padding: EdgeInsets.all(15), child: Column( children: [ Card( elevation: 2, child: Container( height: 55.h, padding: EdgeInsets.all(3), child: TabBar( controller: tabController, onTap: (index) { delayed(300, () { switchTab(index); }); }, labelColor: Colors.white, unselectedLabelColor: Colors.black, indicator: BoxDecoration( color: AppTheme.themeColor, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.2), spreadRadius: 1, blurRadius: 6, ), ], ), tabs: [ Tab(text: '司机端登录'), Tab(text: '加氢站登录'), ], isScrollable: false, ), ), ), Flexible( child: TabBarView( controller: tabController, children: [ _driverLoginView(controller), _stationLoginView(controller), ], ), ), ], ), ), ), ].toColumn(mainAxisSize: MainAxisSize.min).center(), ); } Widget _driverLoginView(LoginController controller) { return !cLogin ? SizedBox() : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 20.h), TextFormField( controller: controller.driverIdentityController, cursorColor: AppTheme.themeColor, maxLength: 8, style: TextStyle(fontSize: 14), decoration: InputDecoration( hintText: '请输入身份后8位', border: OutlineInputBorder(), hintStyle: TextStyle(fontSize: 14), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 10), prefixIcon: Icon(Icons.person_2_outlined, color: Colors.grey), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: AppTheme.themeColor), ), ), ), SizedBox(height: 20.h), ElevatedButton( onPressed: () async { String password = controller.driverIdentityController.text; if (password.isEmpty) { showToast("请输入密码"); return; } showLoading('登录中...'); try { var responseData = await HttpService.to.post( 'appointment/login/loginForDriver', data: {'idNo': password}, ); if (responseData == null && responseData!.data == null) { dismissLoading(); showToast('登录失败:无法获取凭证'); return; } try { var result = BaseModel.fromJson(responseData.data); String token = result.data['token'] ?? ''; String idCard = result.data['idCard'] ?? ''; String name = result.data['name'] ?? ''; String phone = result.data['phone'] ?? ''; await StorageService.to.saveLoginInfo( token: token, userId: "", channel: "driver", idCard: idCard, name: name, phone: phone, ); dismissLoading(); showToast('登录成功,欢迎您'); Get.offAll(() => BaseWidgetsPage()); } catch (e) { dismissLoading(); showToast('登录失败:数据异常'); } } catch (e) { dismissLoading(); } }, style: ElevatedButton.styleFrom( backgroundColor: AppTheme.themeColor, minimumSize: Size(double.infinity, 50), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: Text('登录'), ), ], ); } Widget _stationLoginView(LoginController controller) { return cLogin ? SizedBox() : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 20), TextFormField( controller: controller.stationIdController, cursorColor: AppTheme.themeColor, style: TextStyle(fontSize: 14), decoration: InputDecoration( hintText: '请输入加氢站编号', border: OutlineInputBorder(), hintStyle: TextStyle(fontSize: 14), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 10), prefixIcon: Icon(Icons.person_2_outlined, color: Colors.grey), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: AppTheme.themeColor), ), ), ), SizedBox(height: 10), TextFormField( controller: controller.passwordController, obscureText: _obscureText, style: TextStyle(fontSize: 14), cursorColor: AppTheme.themeColor, decoration: InputDecoration( hintStyle: TextStyle(fontSize: 14), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 10), hintText: '请输入密码', border: OutlineInputBorder(), suffixIcon: IconButton( icon: Icon( _obscureText ? Icons.visibility_off : Icons.visibility, ), onPressed: () { setState(() { _obscureText = !_obscureText; }); }, ), prefixIcon: Icon(Icons.lock_outline, color: Colors.grey), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: AppTheme.themeColor), ), ), ), SizedBox(height: 10), //记住密码复选框 --- Row( children: [ SizedBox( height: 24, width: 24, child: Checkbox( value: _rememberPassword, activeColor: AppTheme.themeColor, onChanged: (bool? value) { setState(() { _rememberPassword = value ?? true; }); }, ), ), GestureDetector( onTap: () => setState(() => _rememberPassword = !_rememberPassword), child: const Text('记住密码', style: TextStyle(color: Colors.grey)), ) ], ), SizedBox(height: 20), // 调整间距 ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppTheme.themeColor, minimumSize: Size(double.infinity, 50), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), onPressed: () async { String account = controller.stationIdController.text; String password = controller.passwordController.text; if (account.isEmpty || password.isEmpty) { showToast("请输入账号和密码"); return; } showLoading('登录中...'); try { String encryptedPassword = LoginUtil.encrypt(password); var responseData = await HttpService.to.post( '/login/password', data: { 'account': account, 'password': encryptedPassword, 'loginType': "station", }, ); if (responseData == null && responseData!.data == null) { dismissLoading(); showToast('登录失败:无法获取凭证'); return; } try { var result = BaseModel.fromJson(responseData.data); String token = result.data['token'] ?? ''; String userId = result.data['userId'] ?? ''; await StorageService.to.saveLoginInfo( token: token, userId: userId, channel: "station", ); // 根据复选框状态保存或清除密码 --- if (_rememberPassword) { await StorageService.to.saveStationCredentials(account, password); } else { await StorageService.to.clearStationCredentials(); } dismissLoading(); showToast('登录成功,欢迎您'); Get.offAll(() => B_BaseWidgetsPage()); } catch (e) { dismissLoading(); showToast('登录失败:数据异常'); } } catch (e) { dismissLoading(); } }, child: Text('登录'), ), ], ); } @override Widget build(BuildContext context) { return GetBuilder( init: LoginController(), id: 'login', builder: (controller) { return Scaffold(body: _buildView(controller)); }, ); } }