flutter_integrated_whb/lib/pages/login_page.dart

461 lines
17 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:io';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/mine/mine_set_pwd_page.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../tools/tools.dart';
import 'main_tab.dart';
import 'mine/webViewPage.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '登录页面',
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: const InputDecorationTheme(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
),
home: const LoginPage(),
debugShowCheckedModeBanner: false,
);
}
}
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final TextEditingController _phoneController = TextEditingController(
// text: '13293211008',
);
final TextEditingController _passwordController = TextEditingController(
// text: 'Zsaq@123456',
);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _errorMessage = '';
bool _isLoading = false;
bool _obscurePassword = true;
bool _agreed = false;
@override
void initState() {
super.initState();
_phoneController.addListener(_onTextChanged);
_getData();
// _phoneController.text= SessionService.instance.loginPhone ?? "";
// _passwordController.text= SessionService.instance.loginPass?? "";
_checkUpdata();
}
Future<void> _getData() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_phoneController.text= prefs.getString('savePhone') ?? '';
_passwordController.text=prefs.getString('savePass') ?? '';
});
}
Future<void> _saveData(String phone,String pass) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString("savePhone", phone);
await prefs.setString("savePass", pass);
}
void dispose() {
_phoneController.removeListener(_onTextChanged);
_phoneController.dispose();
super.dispose();
}
void _onTextChanged() {
setState(() {}); // 文本变化时刷新UI
}
Future<void> _checkUpdata() async {
try{
final result = await AuthService.checkUpdate();
if (FormUtils.hasValue(result, 'pd')) {
Map pd = result['pd'];
final versionInfo = await getAppVersion();
bool isWifi = true;
if (versionInfo.versionName != pd['VERSION']) {
//有更新 提示更新
final ok = await CustomAlertDialog.showConfirm(
context,
barrierDismissible:false,
title: '更新通知',
content: isWifi ? '发现新版本,是否更新?为了更好的体验,请更新到最新版本。' : '发现新版本,检查到您当前使用的是移动网络,是否更新?更新时请注意流量消耗。为了更好的体验,请更新到最新版本。',
cancelText: pd['ISUPDATE'] == '1' ? '' : '稍后更新',
confirmText: '立即更新'
);
if (ok) {
if (Platform.isIOS) {
openAppStore();
}else{
final apkUrl = pd['FILEURL'] ?? '';
await showUpdateConfirm(context, apkUrl: apkUrl);
}
}
return;
}
}
}catch(_) {}
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/bg-login.png'),
fit: BoxFit.cover,
),
),
child: Form(
key: _formKey,
child: Stack(
children: [
Positioned.fill(
child: Image.asset(
'assets/images/bg-login.png',
fit: BoxFit.cover,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
// child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 70),
Row(
children: [
Image.asset('assets/image/logo.png', height: 50),
const SizedBox(width: 15),
const Expanded(
child: Text(
'欢迎使用,\n智守安全云平台!',
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
const SizedBox(height: 50),
_buildInputSection(
label: "手机号码",
controller: _phoneController,
hintText: "请输入手机号...",
keyboardType: TextInputType.phone,
validator: (value) {
if (value == null || value.isEmpty) return '请输入手机号';
// if (!RegExp(r'^1[3-9]\d{9}\$').hasMatch(value))
// return '请输入有效的手机号';
return null;
},
suffixIcon: _phoneController.text.isEmpty
? const SizedBox(height: 20,)
: IconButton(
icon: Icon(Icons.cancel, size: 20,color: Colors.white,),
onPressed: () => _phoneController.clear(),
),
),
_buildInputSection(
label: "密码",
controller: _passwordController,
hintText: "请输入密码...",
obscureText: _obscurePassword,
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? Icons.visibility_off
: Icons.visibility,
color: Colors.white,
),
onPressed:
() => setState(
() => _obscurePassword = !_obscurePassword,
),
),
validator: (value) {
if (value == null || value.isEmpty) return '请输入密码';
return null;
},
),
const SizedBox(height: 30),
if (_errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Text(
_errorMessage,
style: const TextStyle(color: Colors.blue),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 0),
child: SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton(
onPressed:
_handleLogin,
// (!_isLoading && _agreed) ? _handleLogin : null,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
'登录',
style: TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
Spacer(),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Center( // 关键:把 Row 放到 Center 中
child: Row(
mainAxisSize: MainAxisSize.min, // Row 根据子项宽度自适应,不再铺满父宽度
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Checkbox(
value: _agreed,
activeColor: Colors.white,
checkColor: Colors.blueAccent,
side: const BorderSide(color: Colors.white),
onChanged: (value) {
setState(() {
_agreed = value ?? false;
});
},
),
// 用 Flexible 而非 Expanded且给 RichText 一个居中对齐
Flexible(
fit: FlexFit.loose,
child: RichText(
textAlign: TextAlign.center, // 使文本在它的可用宽度内居中
text: TextSpan(
children: [
const TextSpan(
text: '我已阅读并同意',
style: TextStyle(
color: Colors.white,
fontSize: 12,
),
),
TextSpan(
text: '《服务协议》',
style: const TextStyle(
color: Color(0xFF0D1D8C),
fontSize: 12,
),
recognizer: TapGestureRecognizer()
..onTap = () {
pushPage(
const WebViewPage(
name: "用户服务协议",
url: 'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
),
context,
);
},
),
const TextSpan(
text: '',
style: TextStyle(
color: Colors.white,
fontSize: 12,
),
),
TextSpan(
text: '《隐私政策》',
style: const TextStyle(
color: Color(0xFF0D1D8C),
fontSize: 12,
),
recognizer: TapGestureRecognizer()
..onTap = () {
pushPage(
const WebViewPage(
name: "隐私政策",
url: 'http://47.92.102.56:7811/file/xieyi/zsysq.htm',
),
context,
);
},
),
],
),
),
),
],
),
),
),
],
),
// ),
),
],
),
),
),
);
}
Widget _buildInputSection({
required String label,
required TextEditingController controller,
required String hintText,
bool obscureText = false,
TextInputType keyboardType = TextInputType.text,
Widget? suffixIcon,
String? Function(String?)? validator,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
const SizedBox(height: 0),
TextFormField(
controller: controller,
obscureText: obscureText,
keyboardType: keyboardType,
validator: validator,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: hintText,
hintStyle: const TextStyle(color: Colors.white70),
suffixIcon: suffixIcon,
isDense: true,
contentPadding: EdgeInsets.zero,
),
style: const TextStyle(color: Colors.white),
),
const Divider(
height: 1,
thickness: 1,
color: Colors.white70,
),
],
),
);
}
Future<void> _handleLogin() async {
if(_isLoading){
return;
}
if (!(_formKey.currentState?.validate() ?? false)) return;
if(!_agreed){
ToastUtil.showNormal(context, "请先阅读并同意《服务协议》和《隐私政策》");
return;
}
final userName = _phoneController.text.trim();
final userPwd = _passwordController.text;
_saveData(userName,userPwd);
// SessionService.instance.setSavePhone(userName);
// SessionService.instance.setSavePass(userPwd);
setState(() => _isLoading = true);
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const Center(child: CircularProgressIndicator()),
);
try {
final data = await AuthService.login(userName, userPwd);
Navigator.of(context).pop(); // 关loading
setState(() => _isLoading = false);
if(data.isEmpty){
return;
}
if (data['result'] == 'success') {
if(FormUtils.hasValue(data, 'WEAK_PASSWORD') && data['WEAK_PASSWORD'] == '1'){
pushPage(const MineSetPwdPage("1"), context);
}else if(FormUtils.hasValue(data, 'LONG_TERM_PASSWORD_NOT_CHANGED') && data['LONG_TERM_PASSWORD_NOT_CHANGED']=='1'){
pushPage(const MineSetPwdPage("2"), context);
}else{
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const MainPage()),
);
}
}
} catch (e) {
Navigator.of(context).pop();
setState(() => _isLoading = false);
Fluttertoast.showToast(msg: '登录失败: $e');
}
}
}