263 lines
7.4 KiB
Dart
263 lines
7.4 KiB
Dart
import 'package:autosos_flutter/api/user_api.dart';
|
|
import 'package:autosos_flutter/provider/providers.dart';
|
|
import 'package:autosos_flutter/router/app_router.dart';
|
|
import 'package:autosos_flutter/service/push_service.dart';
|
|
import 'package:autosos_flutter/util/toast.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
/// 登录页(升级版:手机号 + 验证码 + 密码 + 微信登录)
|
|
class BindPhonePage extends ConsumerStatefulWidget {
|
|
const BindPhonePage({super.key});
|
|
|
|
@override
|
|
ConsumerState<BindPhonePage> createState() => _BindPhonePageState();
|
|
}
|
|
|
|
class _BindPhonePageState extends ConsumerState<BindPhonePage> with SingleTickerProviderStateMixin {
|
|
late TabController _tab;
|
|
final _phoneCtrl = TextEditingController();
|
|
final _codeCtrl = TextEditingController();
|
|
final _pwdCtrl = TextEditingController();
|
|
|
|
bool _sending = false;
|
|
int _countdown = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_tab = TabController(length: 2, vsync: this);
|
|
_phoneCtrl.text = '14725803690';
|
|
_pwdCtrl.text = '123456';
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_tab.dispose();
|
|
_phoneCtrl.dispose();
|
|
_codeCtrl.dispose();
|
|
_pwdCtrl.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _sendCode() async {
|
|
final phone = _phoneCtrl.text.trim();
|
|
if (phone.length != 11) {
|
|
Toast.show('请输入正确的手机号');
|
|
return;
|
|
}
|
|
setState(() => _sending = true);
|
|
try {
|
|
final r = await UserApi.instance.sendSms(phone);
|
|
if (r.isSuccess) {
|
|
Toast.show('验证码已发送');
|
|
_startCountdown(r.data?.cooldown ?? 60);
|
|
} else {
|
|
Toast.show(r.message ?? '发送失败');
|
|
}
|
|
} catch (e) {
|
|
Toast.show('网络异常');
|
|
} finally {
|
|
if (mounted) setState(() => _sending = false);
|
|
}
|
|
}
|
|
|
|
void _startCountdown(int seconds) {
|
|
setState(() => _countdown = seconds);
|
|
Future.doWhile(() async {
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
if (!mounted) return false;
|
|
setState(() => _countdown = _countdown - 1);
|
|
return _countdown > 0;
|
|
});
|
|
}
|
|
|
|
Future<void> _loginByPassword() async {
|
|
final phone = _phoneCtrl.text.trim();
|
|
final pwd = _pwdCtrl.text;
|
|
if (phone.length != 11 || pwd.isEmpty) {
|
|
Toast.show('请输入手机号和密码');
|
|
return;
|
|
}
|
|
try {
|
|
final cid = PushService.instance.clientId;
|
|
final r = await UserApi.instance.login(
|
|
username: phone, password: pwd, cid: cid,
|
|
);
|
|
if (r.isSuccess && r.data != null) {
|
|
await _onLoginSuccess(r.data!.accessToken);
|
|
} else {
|
|
Toast.show(r.message ?? '登录失败');
|
|
}
|
|
} catch (e) {
|
|
Toast.show('网络异常');
|
|
}
|
|
}
|
|
|
|
Future<void> _loginBySms() async {
|
|
final phone = _phoneCtrl.text.trim();
|
|
final code = _codeCtrl.text.trim();
|
|
if (phone.length != 11 || code.isEmpty) {
|
|
Toast.show('请输入手机号和验证码');
|
|
return;
|
|
}
|
|
try {
|
|
final cid = PushService.instance.clientId;
|
|
final r = await UserApi.instance.loginBySms(mobile: phone, code: code, cid: cid);
|
|
if (r.isSuccess && r.data != null) {
|
|
await _onLoginSuccess(r.data!.accessToken);
|
|
} else {
|
|
Toast.show(r.message ?? '登录失败');
|
|
}
|
|
} catch (e) {
|
|
Toast.show('网络异常');
|
|
}
|
|
}
|
|
|
|
Future<void> _onLoginSuccess(String token) async {
|
|
// 写入 SP
|
|
await Future.wait([
|
|
// 持久化 token
|
|
]);
|
|
ref.read(accessTokenProvider.notifier).state = token;
|
|
Toast.show('登录成功');
|
|
if (!mounted) return;
|
|
context.go(Routes.home);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('登录')),
|
|
body: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
children: [
|
|
Image.asset('images/1.5x/ic_launcher.png', width: 72, height: 72),
|
|
const SizedBox(height: 12),
|
|
const Text('欢迎登录啾啾救援',
|
|
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
|
|
const Text('宁波易到互联科技有限公司',
|
|
style: TextStyle(fontSize: 13, color: Colors.grey)),
|
|
const SizedBox(height: 24),
|
|
TabBar(
|
|
controller: _tab,
|
|
tabs: const [Tab(text: '账号密码'), Tab(text: '短信登录')],
|
|
),
|
|
const SizedBox(height: 16),
|
|
SizedBox(
|
|
height: 220,
|
|
child: TabBarView(
|
|
controller: _tab,
|
|
children: [
|
|
_buildPasswordForm(),
|
|
_buildSmsForm(),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const Text('其他登录方式:'),
|
|
IconButton(
|
|
icon: const Icon(Icons.wechat, color: Colors.green, size: 32),
|
|
onPressed: () => context.push(Routes.bindWx),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPhoneField() {
|
|
return Row(
|
|
children: [
|
|
const Text('+86', style: TextStyle(fontSize: 16)),
|
|
const SizedBox(width: 12),
|
|
Container(width: 1, height: 24, color: Colors.grey),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: TextField(
|
|
controller: _phoneCtrl,
|
|
keyboardType: TextInputType.phone,
|
|
decoration: const InputDecoration(
|
|
hintText: '请输入手机号',
|
|
border: InputBorder.none,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildPasswordForm() {
|
|
return Column(
|
|
children: [
|
|
_buildPhoneField(),
|
|
const Divider(),
|
|
TextField(
|
|
controller: _pwdCtrl,
|
|
obscureText: true,
|
|
decoration: const InputDecoration(
|
|
hintText: '请输入密码',
|
|
border: InputBorder.none,
|
|
),
|
|
),
|
|
const Divider(),
|
|
const SizedBox(height: 24),
|
|
SizedBox(
|
|
width: double.infinity,
|
|
height: 48,
|
|
child: ElevatedButton(
|
|
onPressed: _loginByPassword,
|
|
child: const Text('登录'),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildSmsForm() {
|
|
return Column(
|
|
children: [
|
|
_buildPhoneField(),
|
|
const Divider(),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: TextField(
|
|
controller: _codeCtrl,
|
|
keyboardType: TextInputType.number,
|
|
decoration: const InputDecoration(
|
|
hintText: '请输入验证码',
|
|
border: InputBorder.none,
|
|
),
|
|
),
|
|
),
|
|
TextButton(
|
|
onPressed: (_sending || _countdown > 0) ? null : _sendCode,
|
|
child: Text(
|
|
_countdown > 0 ? '$_countdown秒后重试' : '获取验证码',
|
|
style: const TextStyle(fontSize: 14),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(),
|
|
const SizedBox(height: 24),
|
|
SizedBox(
|
|
width: double.infinity,
|
|
height: 48,
|
|
child: ElevatedButton(
|
|
onPressed: _loginBySms,
|
|
child: const Text('登录'),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
} |