login_phone_cubit.dart 5.52 KB
import 'dart:async';

import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/repositories/phone_auth_repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoginPhoneState extends Equatable {
  final bool agreed;
  final bool showAgreed;

  final bool showSnackBar;
  final String snackBarMsg;
  final bool allowSend;
  final int seconds;

  const LoginPhoneState({
    this.agreed = false,
    this.showAgreed = false,
    this.showSnackBar = false,
    this.snackBarMsg = '',
    this.allowSend = true,
    this.seconds = 0,
  });

  LoginPhoneState copyWith({
    bool? agreed,
    bool? showAgreed,
    bool? showSnackBar,
    String? snackBarMsg,
    bool? allowSend,
    int? seconds,
  }) {
    return LoginPhoneState(
      agreed: agreed ?? this.agreed,
      showAgreed: showAgreed ?? this.showAgreed,
      showSnackBar: showSnackBar ?? this.showSnackBar,
      snackBarMsg: snackBarMsg ?? this.snackBarMsg,
      allowSend: allowSend ?? this.allowSend,
      seconds: seconds ?? this.seconds,
    );
  }

  @override
  List<Object?> get props => [
        agreed,
        showAgreed,
        showSnackBar,
        snackBarMsg,
        allowSend,
        seconds,
      ];
}

class LoginPhoneCubit extends Cubit<LoginPhoneState> {
  late TextEditingController _phoneController;
  late TextEditingController _codeController;
  Timer? _timer;
  int countdown = 60; // 倒计时秒数

  late final PhoneAuthRepository _phoneAuthRepository;

  TextEditingController get phoneController => _phoneController;

  TextEditingController get codeController => _codeController;

  LoginPhoneCubit(super.initialState) {
    _phoneController = TextEditingController();
    _codeController = TextEditingController();

    _phoneController.text = '';
    _codeController.text = '';

    _phoneAuthRepository = getIt.get<PhoneAuthRepository>();
  }

  /// 开始倒计时
  void startCountdown() {
    countdown = 60;
    emit(state.copyWith(allowSend: false, seconds: countdown));

    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      countdown--;
      if (countdown <= 0) {
        _timer?.cancel();
        emit(state.copyWith(allowSend: true, seconds: 60));
      } else {
        emit(state.copyWith(seconds: countdown));
      }
    });
  }

  /// 发送验证码
  Future<void> sendVerificationCode() async {
    if (state.allowSend) {
      // 验证手机号码
      String phone = _phoneController.text;
      if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(phone)) {
        emit(state.copyWith(showSnackBar: true, snackBarMsg: '请输入正确的手机号码'));
        emit(state.copyWith(showSnackBar: false));
        return;
      }

      // 发送验证码
      var result = await _phoneAuthRepository.verifyCode(phone, 0);
      if (result['code'] != 0) {
        emit(state.copyWith(showSnackBar: true, snackBarMsg: result['error']));
        emit(state.copyWith(showSnackBar: false));
        return;
      }

      emit(state.copyWith(allowSend: false, seconds: 60));

      // 开始倒计时
      startCountdown();
    }
  }

  Future<void> phoneAuth() async {
    String phone = _phoneController.text;
    String verifyCode = _codeController.text;

    if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(phone)) {
      emit(state.copyWith(showSnackBar: true, snackBarMsg: '请输入正确的手机号码'));
      emit(state.copyWith(showSnackBar: false));
      return;
    }

    if (!RegExp(r'^\d{4}$').hasMatch(verifyCode)) {
      emit(state.copyWith(showSnackBar: true, snackBarMsg: '请输入正确的验证码'));
      emit(state.copyWith(showSnackBar: false));
      return;
    }

    if (!state.agreed) {
      emit(state.copyWith(showAgreed: true));
      return;
    }

    var result = await _phoneAuthRepository.login(phone, verifyCode);
    if (result['code'] != 0) {
      emit(state.copyWith(showSnackBar: true, snackBarMsg: result['error']));
      emit(state.copyWith(showSnackBar: false));
      return;
    }

    var data = result['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 toggleAgreed(bool value) {
    emit(state.copyWith(agreed: value));
  }

  void confirmAgreed() {
    emit(state.copyWith(agreed: true, showAgreed: false));
    phoneAuth();
  }

  void cancelAgreed() {
    emit(state.copyWith(showAgreed: false));
  }

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

  void goLoginQr() {
    router.go('/loginQr');
  }

  @override
  Future<void> close() async {
    try {
      _phoneController.dispose();
    } catch (e) {
      print(e);
    }

    try {
      _codeController.dispose();
    } catch (e) {
      print(e);
    }

    await super.close();
  }
}