login_qr_cubit.dart 4.41 KB
import 'dart:convert';
import 'dart:typed_data';

import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/repositories/wechat_auth_repository.dart';
import 'package:crypto/crypto.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluwx/fluwx.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoginQrState extends Equatable {
  final int status;
  final Uint8List? image;
  final String tip;

  const LoginQrState({
    this.status = 0,
    this.image,
    this.tip = '',
  });

  @override
  List<Object?> get props => [
        status,
        image,
        tip,
      ];

  LoginQrState copyWith({
    int? status,
    Uint8List? image,
    String? tip,
  }) {
    return LoginQrState(
      status: status ?? this.status,
      image: image ?? this.image,
      tip: tip ?? this.tip,
    );
  }
}

class LoginQrCubit extends Cubit<LoginQrState> {
  late final Fluwx _fluwx;
  late final FluwxCancelable _fluwxCancelable;
  late final WechatAuthRepository _wechatAuthRepository;

  LoginQrCubit(super.initialState) {
    _fluwx = getIt.get<Fluwx>();
    _fluwxCancelable = _fluwx.addSubscriber(_responseListener);
    _wechatAuthRepository = getIt.get<WechatAuthRepository>();

    init();
  }

  Future<void> init() async {
    // sdk_ticket
    var result = await _wechatAuthRepository.getTicket();
    // 后续添加错误处理
    if (result['resultCode'] != '001') {
      return;
    }

    var sdkTicket = result['data'];

    // 当前时间戳
    var timestamp = DateTime.now().millisecondsSinceEpoch;
    var signature = _sig('wx8c32ea248f0c7765', '$timestamp', sdkTicket, '$timestamp');

    var authResult = await _fluwx.authBy(
      which: QRCode(
        appId: 'wx8c32ea248f0c7765',
        scope: 'snsapi_userinfo',
        nonceStr: '$timestamp',
        timestamp: '$timestamp',
        signature: signature,
      ),
    );
    print('AuthResult $authResult');
  }

  void _responseListener(WeChatResponse response) async {
    if (response is WeChatAuthGotQRCodeResponse) {
      int? errCode = response.errCode;
      if (errCode != null && errCode == 0) {
        emit(state.copyWith(status: 1, image: response.qrCode, tip: '打开微信,扫描二维码登录'));
      } else {
        emit(state.copyWith(tip: '错误 $errCode'));
      }
    } else if (response is WeChatQRCodeScannedResponse) {
      int? errCode = response.errCode;
      if (errCode != null && errCode == 0) {
        emit(state.copyWith(status: 2, tip: '在微信中轻触允许即可登录'));
      } else {
        emit(state.copyWith(tip: '错误 $errCode'));
      }
    } else if (response is WeChatAuthByQRCodeFinishedResponse) {
      int? errCode = response.errCode;
      if (errCode != null && errCode == 0) {
        _doLogin(response.authCode!);
      } else {
        emit(state.copyWith(status: 3, tip: '你已取消此次登录'));
      }
    }
  }

  String _sig(String appId, String nonceStr, String sdkTicket, String timestamp) {
    String str = 'appid=$appId&noncestr=$nonceStr&sdk_ticket=$sdkTicket&timestamp=$timestamp';
    return sha1.convert(utf8.encode(str)).toString();
  }

  Future<void> _doLogin(String code) async {
    dynamic resultData = await _wechatAuthRepository.codeToSk(code);
    // 后续添加错误处理
    if (resultData['resultCode'] != '001') {
      return;
    }

    var data = resultData['data'];
    var role = data['roles'][0];

    final sessionCode = data['sessionCode'];
    final userCode = data['userCode'];
    final classCode = role['classCode'];
    final userType = role['userType'];
    final stuId = role['stuId'];

    var sharedPreferences = getIt.get<SharedPreferences>();
    sharedPreferences.setString('auth_sessionCode', sessionCode);
    sharedPreferences.setString('auth_userCode', userCode);
    sharedPreferences.setString('auth_classCode', classCode);
    sharedPreferences.setInt('auth_userType', userType);
    sharedPreferences.setString('auth_stuId', stuId ?? '');

    router.go(
      '/web',
      extra: {
        'sessionCode': sessionCode,
        'userCode': userCode,
        'classCode': classCode,
        'userType': userType,
        'stuId': stuId,
      },
    );
  }

  void goLoginMain() {
    router.go('/loginMain');
  }

  @override
  Future<void> close() {
    _fluwxCancelable.cancel();
    _fluwx.stopAuthByQRCode();
    return super.close();
  }
}