基础库
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 

532 řádky
18 KiB

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