基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

login_page.dart 18 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/gestures.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:flutter_alibc/alibc_model.dart';
  8. import 'package:flutter_alibc/flutter_alibc.dart';
  9. import 'package:flutter_bloc/flutter_bloc.dart';
  10. import 'package:fluttertoast/fluttertoast.dart';
  11. import 'package:sharesdk_plugin/sharesdk_plugin.dart';
  12. import 'package:zhiying_comm/pages/login_page/account/login_account_page.dart';
  13. import 'package:zhiying_comm/pages/login_page/bind/login_bind_phone_page.dart';
  14. import 'package:zhiying_comm/util/dialog/loading/loading.dart';
  15. import 'package:zhiying_comm/util/empty_util.dart';
  16. import 'package:zhiying_comm/util/mob_util/mob_util.dart';
  17. import 'package:zhiying_comm/zhiying_comm.dart';
  18. import 'package:provider/provider.dart';
  19. import 'package:ali_auth_wbq/ali_auth_wbq.dart';
  20. import 'bloc/bloc.dart';
  21. import 'bloc/login_repository.dart';
  22. import 'login_page_sk.dart';
  23. import 'model/login_style_model.dart';
  24. ///
  25. /// 登陆页面
  26. ///
  27. class LoginPage extends StatelessWidget {
  28. const LoginPage({Key key}) : super(key: key);
  29. @override
  30. Widget build(BuildContext context) {
  31. return Scaffold(
  32. backgroundColor: HexColor.fromHex('#FFFFFF'),
  33. body: BlocProvider<LoginBloc>(
  34. create: (_) => LoginBloc(repository: LoginRepository())..add(LoginInitEvent()),
  35. child: LoginPageContainer(),
  36. ),
  37. );
  38. }
  39. }
  40. class LoginPageContainer extends StatefulWidget {
  41. @override
  42. _LoginPageContainerState createState() => _LoginPageContainerState();
  43. }
  44. class _LoginPageContainerState extends State<LoginPageContainer> {
  45. LoginModel _taoBao;
  46. var _qqUserData;
  47. var _wxUserData;
  48. String _appleData;
  49. bool checkBool = false;
  50. @override
  51. void initState() {
  52. // 登录监听
  53. AliAuthPlugin.loginListen(type: false, onEvent: _onAppleLoginEvent);
  54. super.initState();
  55. }
  56. // 返回授权信息
  57. // returnCode: 200成功 500失败
  58. // returnMsg
  59. // user
  60. // familyName //可能为 @""
  61. // givenName //可能为 @""
  62. // email //可能为 @""
  63. // identityTokenStr //需要使用的参数
  64. // authorizationCodeStr
  65. void _onAppleLoginEvent(event) {
  66. var stateCode = event['returnCode'];
  67. String stateMsg = event['returnMsg'];
  68. // _appleData = event['identityTokenStr'];
  69. _appleData = event['user'];
  70. Logger.debug('event == ' + event?.toString());
  71. if (stateCode == 200 && !EmptyUtil.isEmpty(_appleData)) {
  72. Loading.dismiss();
  73. print("成功------$event");
  74. BlocProvider.of<LoginBloc>(context).add(LoginThirdAppleEvent(identityToken: _appleData));
  75. } else {
  76. Loading.dismiss();
  77. print("失败------$stateMsg");
  78. }
  79. }
  80. /// 微信or手机登陆
  81. void _loginClick(String type, LoginStyleModel model) {
  82. if(!checkBool){
  83. Fluttertoast.showToast(msg: "请阅读并勾选同意用户协议选项");
  84. return;
  85. }
  86. print('登陆$type');
  87. RouterUtil.hideKeyboard(context);
  88. if ('mobile' == type) {
  89. if (model?.flashLoginEnable == '1') {
  90. // mob 一键登录
  91. MobUtil.openQuickLoginPage(context, model?.quick);
  92. } else {
  93. Navigator.push(context, CupertinoPageRoute(builder: (_) => LoginAccountPage(null)));
  94. }
  95. } else if ('wechat' == type) {
  96. /// 微信登录
  97. Loading.show(context);
  98. SharesdkPlugin.getUserInfo(ShareSDKPlatforms.wechatSession, (SSDKResponseState state, Map userdata, SSDKError error) {
  99. Logger.log('state = ${state?.toString()}, userInfo = ${userdata?.toString()}');
  100. if (state == SSDKResponseState.Success) {
  101. try {
  102. if (Platform.isIOS) {
  103. Map credentialDic = userdata['credential'];
  104. Map rawDatalDic = userdata['rawData'];
  105. var name = userdata['nickname'];
  106. var gender = userdata['gender'];
  107. var icon = userdata['icon'];
  108. var userID = userdata['uid'];
  109. var unionid = rawDatalDic['unionid'];
  110. var token = credentialDic['token'];
  111. Map dbInfoDic = {
  112. 'nickname': name,
  113. 'gender': gender,
  114. 'icon': icon,
  115. 'userID': userID,
  116. 'unionid': unionid,
  117. 'token': token,
  118. };
  119. Map tempUserData = {'dbInfo': jsonEncode(dbInfoDic)};
  120. _wxUserData = jsonDecode(tempUserData['dbInfo']);
  121. BlocProvider.of<LoginBloc>(context).add(LoginThirdWeChatEvent(model: tempUserData));
  122. } else if (Platform.isAndroid) {
  123. _wxUserData = jsonDecode(userdata['dbInfo']);
  124. BlocProvider.of<LoginBloc>(context).add(LoginThirdWeChatEvent(model: userdata));
  125. }
  126. Loading.dismiss();
  127. } catch (e) {
  128. Fluttertoast.showToast(msg: '登录失败');
  129. Loading.dismiss();
  130. }
  131. } else {
  132. Loading.dismiss();
  133. }
  134. });
  135. }
  136. }
  137. /// 第三方登陆
  138. void _otherLoginClick(BottomIcons model) async {
  139. if(!checkBool){
  140. Fluttertoast.showToast(msg: "请阅读并勾选同意用户协议选项");
  141. return;
  142. }
  143. print('第三方登陆${model.type}');
  144. if (EmptyUtil.isEmpty(model) || EmptyUtil.isEmpty(model.type)) {
  145. Fluttertoast.showToast(msg: '暂不支持~');
  146. return;
  147. }
  148. /// 淘宝登录
  149. if ('taobao' == model.type) {
  150. Loading.show(context);
  151. _taoBao = await FlutterAlibc.loginTaoBao();
  152. if (!EmptyUtil.isEmpty(_taoBao) && !EmptyUtil.isEmpty(_taoBao?.errorCode) && _taoBao.errorCode == '0') {
  153. BlocProvider.of<LoginBloc>(context).add(LoginThirdAliEvent(
  154. nick: _taoBao?.data?.nick,
  155. avatarUrl: _taoBao?.data?.avatarUrl,
  156. openId: _taoBao?.data?.openId,
  157. openSid: _taoBao?.data?.openSid,
  158. topAccessToken: _taoBao?.data?.topAccessToken,
  159. topAuthCode: _taoBao?.data?.topAuthCode));
  160. // Logger.warn(' tao login = ${_taoBao?.errorCode} , msg = ${_taoBao?.errorMessage}, nick = ${_taoBao?.data?.nick}, '
  161. // 'avatar = ${_taoBao?.data?.avatarUrl}, openId = ${_taoBao?.data?.openId}, openSid = ${_taoBao?.data?.openSid}, '
  162. // 'topAccessToken = ${_taoBao?.data?.topAccessToken}, topAuthCode = ${_taoBao?.data?.topAuthCode}');
  163. }
  164. Loading.dismiss();
  165. }
  166. /// QQ登录
  167. if ('qq' == model.type) {
  168. Loading.show(context);
  169. SharesdkPlugin.getUserInfo(ShareSDKPlatforms.qq, (SSDKResponseState state, Map userdata, SSDKError error) {
  170. Logger.log('state = ${state?.toString()}\nuserData = ${userdata?.toString()}');
  171. if (state == SSDKResponseState.Success && !EmptyUtil.isEmpty(userdata)) {
  172. try {
  173. _qqUserData = jsonDecode(userdata['dbInfo']);
  174. BlocProvider.of<LoginBloc>(context).add(LoginThirdQQEvent(model: userdata));
  175. Loading.dismiss();
  176. } catch (e) {
  177. Fluttertoast.showToast(msg: '登录失败');
  178. Loading.dismiss();
  179. }
  180. } else {
  181. Loading.dismiss();
  182. }
  183. });
  184. // Fluttertoast.showToast(msg: '暂不支持~');
  185. }
  186. /// 苹果登录
  187. if ('apple' == model.type) {
  188. if (Platform.isIOS) {
  189. Loading.show(context);
  190. await AliAuthPlugin.appleLogin;
  191. // final appleLogin = await AliAuthPlugin.appleLogin;
  192. } else {
  193. Fluttertoast.showToast(msg: '暂不支持~');
  194. }
  195. }
  196. }
  197. /// 跳到用户协议
  198. void _jumpUserAgreement(String url) {
  199. if (!EmptyUtil.isEmpty(url)) {
  200. print('协议');
  201. RouterUtil.openWebview(url, context);
  202. }
  203. }
  204. /// 跳到绑定手机号
  205. void _jumpBindPhonePage(String thirdType) {
  206. /// 如果是苹果登录
  207. if (GlobalConfig.LOGIN_THIRD_APPLE == thirdType) {
  208. Navigator.push(
  209. context,
  210. CupertinoPageRoute(
  211. builder: (_) => LoginBindPhonePage({
  212. 'thirdType': thirdType,
  213. 'identityTokenStr': _appleData,
  214. })));
  215. }
  216. /// 如果是淘宝登录
  217. if (GlobalConfig.LOGIN_THIRD_ALI == thirdType) {
  218. Navigator.push(
  219. context,
  220. CupertinoPageRoute(
  221. builder: (_) => LoginBindPhonePage({
  222. 'thirdType': thirdType,
  223. 'nick': _taoBao?.data?.nick,
  224. 'avatarUrl': _taoBao?.data?.avatarUrl,
  225. 'openId': _taoBao?.data?.openId,
  226. 'openSid': _taoBao?.data?.openSid,
  227. 'topAccessToken': _taoBao?.data?.topAccessToken,
  228. 'topAuthCode': _taoBao?.data?.topAuthCode,
  229. })));
  230. }
  231. /// 如果是QQ登录
  232. if (GlobalConfig.LOGIN_THIRD_QQ == thirdType) {
  233. if (!EmptyUtil.isEmpty(_qqUserData)) {
  234. Navigator.push(
  235. context,
  236. CupertinoPageRoute(
  237. builder: (_) => LoginBindPhonePage({
  238. 'thirdType': thirdType,
  239. 'nickname': _qqUserData['nickname']?.toString(),
  240. 'avatar_url': _qqUserData['icon']?.toString(),
  241. 'open_id': _qqUserData['userID']?.toString(),
  242. 'gender': _qqUserData['gender']?.toString() == '0' ? '1' : '2',
  243. 'unionid': _qqUserData['unionid']?.toString(),
  244. 'token': _qqUserData['token']?.toString(),
  245. })));
  246. }
  247. }
  248. /// 微信登录
  249. if (GlobalConfig.LOGIN_THIRD_WECHAT == thirdType) {
  250. if (!EmptyUtil.isEmpty(_wxUserData)) {
  251. Navigator.push(
  252. context,
  253. CupertinoPageRoute(
  254. builder: (_) => LoginBindPhonePage({
  255. 'thirdType': thirdType,
  256. 'nickname': _wxUserData['nickname']?.toString(),
  257. 'avatar_url': _wxUserData['icon']?.toString(),
  258. 'open_id': _wxUserData['userID']?.toString(),
  259. 'gender': _wxUserData['gender']?.toString() == '0' ? '1' : '2',
  260. 'unionid': _wxUserData['unionid']?.toString(),
  261. 'token': _wxUserData['token']?.toString(),
  262. })));
  263. }
  264. }
  265. }
  266. /// 跳到首页
  267. void _jumpHomePage() {
  268. RouterUtil.goBackHomePage(context);
  269. }
  270. /// 展开关闭其它登陆
  271. void _showOrCloseOtherLogin() {
  272. setState(() {
  273. _showOther = !_showOther;
  274. });
  275. }
  276. final _sizedHeight50 = const SizedBox(height: 50);
  277. final _sizedHeight9 = const SizedBox(height: 9);
  278. final _sizedHeight18 = const SizedBox(height: 18);
  279. final _sizedHeight21 = const SizedBox(height: 21);
  280. bool _showOther = true;
  281. @override
  282. Widget build(BuildContext context) {
  283. return BlocConsumer<LoginBloc, LoginState>(
  284. listener: (context, state) {
  285. // Fluttertoast.showToast(msg: '网络异常');
  286. },
  287. buildWhen: (prev, current) {
  288. if (current is LoginErrorState) {
  289. return false;
  290. }
  291. /// 登录失败
  292. if (current is LoginThirdLoginErrorState) {
  293. return false;
  294. }
  295. /// 登录成功
  296. if (current is LoginThirdLoginSuccessState) {
  297. // 需要绑定手机号
  298. if (current.model.bindPhoneEnable == '1') {
  299. // 打开绑定手机号页面
  300. _jumpBindPhonePage(current.thirdType);
  301. } else {
  302. // 更新登录数据
  303. Provider.of<UserInfoNotifier>(context, listen: false)?.setUserInfo(current.model);
  304. // 直接打开首页
  305. _jumpHomePage();
  306. Fluttertoast.showToast(msg: '登录成功~');
  307. }
  308. return false;
  309. }
  310. return true;
  311. },
  312. builder: (context, state) {
  313. if (state is LoginCacheState) {
  314. return _getMainWidget(state.model);
  315. }
  316. if (state is LoginLoadedState) {
  317. return _getMainWidget(state.model);
  318. }
  319. return LoginPageSkeleton(); // 骨架屏幕
  320. },
  321. );
  322. }
  323. /// 主视图
  324. Widget _getMainWidget(LoginStyleModel model) {
  325. return Column(
  326. children: <Widget>[
  327. /// 头部
  328. _headWidget(model),
  329. _sizedHeight50,
  330. /// 按钮
  331. _buttonsWidget(model),
  332. _sizedHeight9,
  333. /// 协议
  334. _protocolWidget(model),
  335. /// 其它登陆方式
  336. _otherLoginWidget(model),
  337. ],
  338. );
  339. }
  340. /// 头部Widget
  341. Widget _headWidget(LoginStyleModel model) {
  342. return Container(
  343. height: 228 + MediaQuery.of(context).padding.top,
  344. width: double.infinity,
  345. decoration: BoxDecoration(
  346. image: DecorationImage(
  347. image: CachedNetworkImageProvider(model?.main?.backgroundImg ?? ''),
  348. fit: BoxFit.fill,
  349. ),
  350. ),
  351. child: Stack(
  352. alignment: Alignment.center,
  353. children: <Widget>[
  354. AppBar(
  355. backgroundColor: Colors.transparent,
  356. elevation: 0,
  357. leading: IconButton(
  358. icon: Icon(
  359. Icons.arrow_back_ios,
  360. size: 22,
  361. color: HexColor.fromHex('#333333'),
  362. ),
  363. onPressed: () => Navigator.maybePop(context),
  364. ),
  365. ),
  366. Column(
  367. crossAxisAlignment: CrossAxisAlignment.center,
  368. mainAxisAlignment: MainAxisAlignment.center,
  369. children: <Widget>[
  370. /// logo
  371. Container(
  372. margin: EdgeInsets.only(bottom: 12, top: MediaQuery.of(context).padding.top),
  373. decoration: BoxDecoration(
  374. borderRadius: BorderRadius.circular(14),
  375. boxShadow: [
  376. BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0), blurRadius: 10.0, spreadRadius: 1.0),
  377. BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0)),
  378. ],
  379. ),
  380. height: 80,
  381. width: 80,
  382. child: CachedNetworkImage(imageUrl: model?.logoImg ?? ''),
  383. ),
  384. /// logo 名字
  385. CachedNetworkImage(
  386. imageUrl: model?.main?.appNameImg ?? '',
  387. width: 90,
  388. ),
  389. ],
  390. ),
  391. ],
  392. ),
  393. );
  394. }
  395. /// 按钮
  396. Widget _buttonsWidget(LoginStyleModel model) {
  397. return Container(
  398. padding: const EdgeInsets.symmetric(horizontal: 27.5),
  399. child: Column(
  400. children: model.main.importanceLogin.map((item) {
  401. return Padding(
  402. padding: const EdgeInsets.only(bottom: 8),
  403. child: _customButton(
  404. height: 40,
  405. text: item?.btnText,
  406. iconUrl: item?.btnMobileIcon ?? '',
  407. textColor: item?.btnTextColor,
  408. bgColor: item?.btnBgColor,
  409. borderColor: item?.btnBorderColor,
  410. onTap: () => _loginClick(item?.type, model)),
  411. );
  412. }).toList(),
  413. ),
  414. );
  415. }
  416. /// 协议
  417. Widget _protocolWidget(LoginStyleModel model) {
  418. return Row(
  419. mainAxisAlignment: MainAxisAlignment.center,
  420. children: <Widget>[
  421. InkWell(
  422. borderRadius: BorderRadius.circular(20),
  423. onTap: () {
  424. checkBool = !checkBool;
  425. setState(() {});
  426. },
  427. child: Container(
  428. width: 32,
  429. height: 32,
  430. child: Icon(
  431. checkBool ? Icons.check_box : Icons.check_box_outline_blank,
  432. size: 16,
  433. color: checkBool?Colors.red:Colors.black12,
  434. ),
  435. ),
  436. ),
  437. RichText(
  438. text: TextSpan(
  439. text: '',
  440. children: model.main.agreements.map((item) {
  441. return TextSpan(
  442. text: item?.text,
  443. style: TextStyle(color: HexColor.fromHex(item?.textColor), fontSize: 10),
  444. recognizer: TapGestureRecognizer()
  445. ..onTap = () {
  446. _jumpUserAgreement(item?.url);
  447. });
  448. }).toList()),
  449. ),
  450. ],
  451. );
  452. }
  453. /// 其它登陆方式
  454. Widget _otherLoginWidget(LoginStyleModel model) {
  455. return Expanded(
  456. child: Column(
  457. mainAxisAlignment: MainAxisAlignment.end,
  458. children: <Widget>[
  459. _getOtherLoginTitle(model),
  460. _sizedHeight18,
  461. Visibility(visible: _showOther, child: _getOtherLoginIcons(model)),
  462. Visibility(visible: _showOther, child: _sizedHeight21),
  463. ],
  464. ),
  465. );
  466. }
  467. /// 其它登陆方式的title
  468. Widget _getOtherLoginTitle(LoginStyleModel model) {
  469. return GestureDetector(
  470. behavior: HitTestBehavior.opaque,
  471. onTap: () => _showOrCloseOtherLogin(),
  472. child: Row(
  473. mainAxisAlignment: MainAxisAlignment.center,
  474. crossAxisAlignment: CrossAxisAlignment.center,
  475. children: <Widget>[
  476. Text('${model?.main?.otherIconsTitle}', style: TextStyle(fontSize: 13, color: HexColor.fromHex(model?.main?.otherIconsTitleColor))),
  477. SizedBox(width: 5.5),
  478. RotatedBox(
  479. quarterTurns: _showOther ? 0 : 2,
  480. child: CachedNetworkImage(imageUrl: model?.main?.otherExpansionIcon ?? '', width: 12),
  481. ),
  482. ],
  483. ),
  484. );
  485. }
  486. /// 其它登陆方式的按钮
  487. Widget _getOtherLoginIcons(LoginStyleModel model) {
  488. return Row(
  489. mainAxisAlignment: MainAxisAlignment.center,
  490. children: model.main.bottomIcons.map((item) {
  491. return GestureDetector(
  492. behavior: HitTestBehavior.opaque,
  493. onTap: () => _otherLoginClick(item),
  494. child: Container(
  495. width: 30,
  496. margin: const EdgeInsets.symmetric(horizontal: 20),
  497. child: CachedNetworkImage(imageUrl: item?.img ?? ''),
  498. ),
  499. );
  500. }).toList(),
  501. );
  502. }
  503. /// 自定义按钮
  504. Widget _customButton({double height, String text, String iconUrl, String textColor, String bgColor, String borderColor, GestureTapCallback onTap}) {
  505. return GestureDetector(
  506. onTap: onTap,
  507. child: Container(
  508. width: double.infinity,
  509. height: height ?? 0,
  510. decoration: BoxDecoration(
  511. border: Border.all(color: HexColor.fromHex(borderColor), width: 0.5),
  512. borderRadius: BorderRadius.circular(height ?? 0 / 2),
  513. color: HexColor.fromHex(bgColor),
  514. ),
  515. child: Row(
  516. mainAxisAlignment: MainAxisAlignment.center,
  517. crossAxisAlignment: CrossAxisAlignment.center,
  518. children: <Widget>[
  519. // icon
  520. CachedNetworkImage(imageUrl: iconUrl, width: 12),
  521. SizedBox(width: 8),
  522. // text
  523. Text(text, style: TextStyle(color: HexColor.fromHex(textColor), fontSize: 15))
  524. ],
  525. ),
  526. ),
  527. );
  528. }
  529. }