297 lines
8.6 KiB
Dart
297 lines
8.6 KiB
Dart
import 'package:autosos_flutter/provider/providers.dart';
|
||
import 'package:autosos_flutter/util/toast.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
/// 认证页(对应 Android AuthenticationActivity)
|
||
/// 三种:个人 / 企业 / 司机
|
||
class AuthenticationPage extends ConsumerStatefulWidget {
|
||
const AuthenticationPage({super.key});
|
||
|
||
@override
|
||
ConsumerState<AuthenticationPage> createState() =>
|
||
_AuthenticationPageState();
|
||
}
|
||
|
||
class _AuthenticationPageState extends ConsumerState<AuthenticationPage>
|
||
with SingleTickerProviderStateMixin {
|
||
late final TabController _tab;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_tab = TabController(length: 3, vsync: this);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_tab.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: const Text('认证'),
|
||
bottom: TabBar(
|
||
controller: _tab,
|
||
tabs: const [
|
||
Tab(text: '个人'),
|
||
Tab(text: '企业'),
|
||
Tab(text: '司机'),
|
||
],
|
||
),
|
||
),
|
||
body: TabBarView(
|
||
controller: _tab,
|
||
children: const [
|
||
_PersonalForm(),
|
||
_EnterpriseForm(),
|
||
_DriverForm(),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _PersonalForm extends ConsumerStatefulWidget {
|
||
const _PersonalForm();
|
||
@override
|
||
ConsumerState<_PersonalForm> createState() => _PersonalFormState();
|
||
}
|
||
|
||
class _PersonalFormState extends ConsumerState<_PersonalForm> {
|
||
final _name = TextEditingController();
|
||
final _idCard = TextEditingController();
|
||
final _front = TextEditingController();
|
||
final _back = TextEditingController();
|
||
bool _loading = false;
|
||
|
||
@override
|
||
void dispose() {
|
||
_name.dispose();
|
||
_idCard.dispose();
|
||
_front.dispose();
|
||
_back.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _submit() async {
|
||
if (_name.text.isEmpty || _idCard.text.isEmpty) {
|
||
Toast.error('请填写姓名和身份证号');
|
||
return;
|
||
}
|
||
if (_front.text.isEmpty || _back.text.isEmpty) {
|
||
Toast.error('请上传身份证正反面');
|
||
return;
|
||
}
|
||
setState(() => _loading = true);
|
||
EasyLoading.show(status: '提交中…');
|
||
try {
|
||
final r = await ref.read(userApiProvider).authPersonal(
|
||
name: _name.text.trim(),
|
||
idCard: _idCard.text.trim(),
|
||
idCardFront: _front.text.trim(),
|
||
idCardBack: _back.text.trim(),
|
||
);
|
||
EasyLoading.dismiss();
|
||
if (!r.isSuccess) {
|
||
Toast.error(r.message ?? '提交失败');
|
||
return;
|
||
}
|
||
Toast.success('已提交,请等待审核');
|
||
if (mounted) Navigator.pop(context);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('提交失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) => _form(children: [
|
||
_tf(_name, '真实姓名'),
|
||
_tf(_idCard, '身份证号'),
|
||
_imgField(_front, '身份证正面 URL(七牛)'),
|
||
_imgField(_back, '身份证反面 URL(七牛)'),
|
||
_submitBtn('提交个人认证', _loading, _submit),
|
||
]);
|
||
}
|
||
|
||
class _EnterpriseForm extends ConsumerStatefulWidget {
|
||
const _EnterpriseForm();
|
||
@override
|
||
ConsumerState<_EnterpriseForm> createState() => _EnterpriseFormState();
|
||
}
|
||
|
||
class _EnterpriseFormState extends ConsumerState<_EnterpriseForm> {
|
||
final _company = TextEditingController();
|
||
final _license = TextEditingController();
|
||
final _licenseImg = TextEditingController();
|
||
final _legalName = TextEditingController();
|
||
final _legalId = TextEditingController();
|
||
final _legalFront = TextEditingController();
|
||
final _legalBack = TextEditingController();
|
||
bool _loading = false;
|
||
|
||
@override
|
||
void dispose() {
|
||
_company.dispose();
|
||
_license.dispose();
|
||
_licenseImg.dispose();
|
||
_legalName.dispose();
|
||
_legalId.dispose();
|
||
_legalFront.dispose();
|
||
_legalBack.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _submit() async {
|
||
if (_company.text.isEmpty || _license.text.isEmpty) {
|
||
Toast.error('请填写公司名和营业执照号');
|
||
return;
|
||
}
|
||
setState(() => _loading = true);
|
||
EasyLoading.show(status: '提交中…');
|
||
try {
|
||
final r = await ref.read(userApiProvider).authEnterprise(
|
||
companyName: _company.text.trim(),
|
||
licenseNo: _license.text.trim(),
|
||
licenseImg: _licenseImg.text.trim(),
|
||
legalPerson: _legalName.text.trim(),
|
||
legalIdCard: _legalId.text.trim(),
|
||
legalIdFront: _legalFront.text.trim(),
|
||
legalIdBack: _legalBack.text.trim(),
|
||
);
|
||
EasyLoading.dismiss();
|
||
if (!r.isSuccess) {
|
||
Toast.error(r.message ?? '提交失败');
|
||
return;
|
||
}
|
||
Toast.success('已提交,请等待审核');
|
||
if (mounted) Navigator.pop(context);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('提交失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) => _form(children: [
|
||
_tf(_company, '公司名称'),
|
||
_tf(_license, '营业执照号'),
|
||
_imgField(_licenseImg, '营业执照图片 URL'),
|
||
const Divider(),
|
||
_tf(_legalName, '法人姓名'),
|
||
_tf(_legalId, '法人身份证号'),
|
||
_imgField(_legalFront, '法人身份证正面 URL'),
|
||
_imgField(_legalBack, '法人身份证反面 URL'),
|
||
_submitBtn('提交企业认证', _loading, _submit),
|
||
]);
|
||
}
|
||
|
||
class _DriverForm extends ConsumerStatefulWidget {
|
||
const _DriverForm();
|
||
@override
|
||
ConsumerState<_DriverForm> createState() => _DriverFormState();
|
||
}
|
||
|
||
class _DriverFormState extends ConsumerState<_DriverForm> {
|
||
final _driverNo = TextEditingController();
|
||
final _driverLicense = TextEditingController();
|
||
final _front = TextEditingController();
|
||
final _back = TextEditingController();
|
||
bool _loading = false;
|
||
|
||
@override
|
||
void dispose() {
|
||
_driverNo.dispose();
|
||
_driverLicense.dispose();
|
||
_front.dispose();
|
||
_back.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _submit() async {
|
||
if (_driverNo.text.isEmpty || _driverLicense.text.isEmpty) {
|
||
Toast.error('请填写驾驶证号和驾驶证');
|
||
return;
|
||
}
|
||
setState(() => _loading = true);
|
||
EasyLoading.show(status: '提交中…');
|
||
try {
|
||
final r = await ref.read(userApiProvider).authDriver(
|
||
driverNo: _driverNo.text.trim(),
|
||
driverLicense: _driverLicense.text.trim(),
|
||
drivingLicenseFront: _front.text.trim(),
|
||
drivingLicenseBack: _back.text.trim(),
|
||
);
|
||
EasyLoading.dismiss();
|
||
if (!r.isSuccess) {
|
||
Toast.error(r.message ?? '提交失败');
|
||
return;
|
||
}
|
||
Toast.success('已提交,请等待审核');
|
||
if (mounted) Navigator.pop(context);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('提交失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) => _form(children: [
|
||
_tf(_driverNo, '驾驶证号'),
|
||
_tf(_driverLicense, '驾驶证档案编号'),
|
||
_imgField(_front, '驾驶证正面 URL'),
|
||
_imgField(_back, '驾驶证反面 URL'),
|
||
_submitBtn('提交司机认证', _loading, _submit),
|
||
]);
|
||
}
|
||
|
||
Widget _form({required List<Widget> children}) => SingleChildScrollView(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: children),
|
||
);
|
||
|
||
Widget _tf(TextEditingController c, String label) => Padding(
|
||
padding: const EdgeInsets.only(bottom: 12),
|
||
child: TextField(
|
||
controller: c,
|
||
decoration: InputDecoration(
|
||
labelText: label,
|
||
border: const OutlineInputBorder(),
|
||
),
|
||
),
|
||
);
|
||
|
||
Widget _imgField(TextEditingController c, String label) => Padding(
|
||
padding: const EdgeInsets.only(bottom: 12),
|
||
child: TextField(
|
||
controller: c,
|
||
decoration: InputDecoration(
|
||
labelText: label,
|
||
hintText: '七牛上传后返回的 URL',
|
||
border: const OutlineInputBorder(),
|
||
),
|
||
),
|
||
);
|
||
|
||
Widget _submitBtn(String text, bool loading, VoidCallback onTap) => SizedBox(
|
||
height: 48,
|
||
child: ElevatedButton(
|
||
onPressed: loading ? null : onTap,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.red,
|
||
),
|
||
child: Text(loading ? '提交中…' : text),
|
||
),
|
||
);
|