import 'dart:convert'; import 'dart:async'; import 'package:get/get.dart'; import 'package:kaer_with_panels/app/common/app_config.dart'; import 'package:kaer_with_panels/app/model/enum/kr_request_type.dart'; import 'package:kaer_with_panels/app/modules/kr_main/controllers/kr_main_controller.dart'; import 'package:kaer_with_panels/app/services/kr_socket_service.dart'; import 'package:kaer_with_panels/app/utils/kr_secure_storage.dart'; import 'package:kaer_with_panels/app/utils/kr_device_util.dart'; import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; import '../services/api_service/kr_api.user.dart'; import '../utils/kr_event_bus.dart'; class KRAppRunData { static final KRAppRunData _instance = KRAppRunData._internal(); static const String _keyUserInfo = 'USER_INFO'; /// 登录token String? kr_token; /// 用户账号 String? kr_account; /// 用户ID String? kr_userId; /// 登录类型 KRLoginType? kr_loginType; /// 区号 String? kr_areaCode; // 需要被监听的属性,用 obs 包装 final kr_isLogin = false.obs; KRAppRunData._internal(); factory KRAppRunData() => _instance; static KRAppRunData getInstance() { return _instance; } /// 保存用户信息 Future kr_saveUserInfo( String token, String account, KRLoginType loginType, String? areaCode) async { KRLogUtil.kr_i('开始保存用户信息', tag: 'AppRunData'); try { // 更新内存中的数据 kr_token = token; kr_account = account; kr_loginType = loginType; kr_areaCode = areaCode; final Map userInfo = { 'token': token, 'account': account, 'loginType': loginType.value, 'areaCode': areaCode ?? "", }; KRLogUtil.kr_i('准备保存用户信息到存储', tag: 'AppRunData'); await KRSecureStorage().kr_saveData( key: _keyUserInfo, value: jsonEncode(userInfo), ); // 验证保存是否成功 final savedData = await KRSecureStorage().kr_readData(key: _keyUserInfo); if (savedData == null || savedData.isEmpty) { KRLogUtil.kr_e('数据保存后无法读取,保存失败', tag: 'AppRunData'); kr_isLogin.value = false; return; } KRLogUtil.kr_i('用户信息保存成功,设置登录状态为true', tag: 'AppRunData'); // 只有在保存成功后才设置登录状态 kr_isLogin.value = true; // 异步获取用户信息并建立 Socket 连接,不等待结果 _iniUserInfo().catchError((error) { KRLogUtil.kr_e('获取用户信息失败: $error', tag: 'AppRunData'); // 即使获取用户信息失败,也保持登录状态 }); } catch (e) { KRLogUtil.kr_e('保存用户信息失败: $e', tag: 'AppRunData'); // 如果出错,重置登录状态 kr_isLogin.value = false; rethrow; // 重新抛出异常,让调用者知道保存失败 } } /// 退出登录 Future kr_loginOut() async { // 先将登录状态设置为 false,防止重连 kr_isLogin.value = false; // 断开 Socket 连接 await _kr_disconnectSocket(); // 清理用户信息 kr_token = null; kr_account = null; kr_userId = null; kr_loginType = null; kr_areaCode = null; // 删除存储的用户信息 await KRSecureStorage().kr_deleteData(key: _keyUserInfo); // 重置主页面 Get.find().kr_setPage(0); } /// 初始化用户信息 Future kr_initializeUserInfo() async { KRLogUtil.kr_i('开始初始化用户信息', tag: 'AppRunData'); try { final String? userInfoString = await KRSecureStorage().kr_readData(key: _keyUserInfo); if (userInfoString != null && userInfoString.isNotEmpty) { KRLogUtil.kr_i('找到存储的用户信息,开始解析', tag: 'AppRunData'); try { final Map userInfo = jsonDecode(userInfoString); kr_token = userInfo['token']; kr_account = userInfo['account']; final loginTypeValue = userInfo['loginType']; kr_loginType = KRLoginType.values.firstWhere( (e) => e.value == loginTypeValue, orElse: () => KRLoginType.kr_telephone, ); kr_areaCode = userInfo['areaCode'] ?? ""; KRLogUtil.kr_i('解析用户信息成功: token=${kr_token != null}, account=$kr_account', tag: 'AppRunData'); // 验证token有效性 if (kr_token != null && kr_token!.isNotEmpty) { KRLogUtil.kr_i('设置登录状态为true', tag: 'AppRunData'); kr_isLogin.value = true; // 异步获取用户信息,但不等待结果 _iniUserInfo().catchError((error) { KRLogUtil.kr_e('获取用户信息失败: $error', tag: 'AppRunData'); // 如果获取用户信息失败,不重置登录状态,让用户重试 }); } else { KRLogUtil.kr_w('Token为空,设置为未登录状态', tag: 'AppRunData'); kr_isLogin.value = false; } } catch (e) { KRLogUtil.kr_e('解析用户信息失败: $e', tag: 'AppRunData'); await kr_loginOut(); } } else { KRLogUtil.kr_i('未找到存储的用户信息,设置为未登录状态', tag: 'AppRunData'); kr_isLogin.value = false; } } catch (e) { KRLogUtil.kr_e('初始化用户信息过程出错: $e', tag: 'AppRunData'); kr_isLogin.value = false; } KRLogUtil.kr_i('用户信息初始化完成,登录状态: ${kr_isLogin.value}', tag: 'AppRunData'); } /// 初始化用户信息并建立 Socket 连接 Future _iniUserInfo() async { final either0 = await KRUserApi().kr_getUserInfo(); either0.fold( (error) { KRLogUtil.kr_e(error.msg, tag: 'AppRunData'); }, (userInfo) async { kr_userId = userInfo.id.toString(); _kr_connectSocket(kr_userId!); }, ); } /// 建立 Socket 连接 Future _kr_connectSocket(String userId) async { // 如果已存在连接,先断开 await _kr_disconnectSocket(); final deviceId = await KRDeviceUtil().kr_getDeviceId(); KRLogUtil.kr_i('设备ID: $deviceId', tag: 'AppRunData'); KrSocketService.instance.kr_init( baseUrl: AppConfig.getInstance().wsBaseUrl, userId: userId, deviceNumber: deviceId, token: kr_token ?? "", ); // 设置消息处理回调 KrSocketService.instance.setOnMessageCallback(_kr_handleMessage); // 设置连接状态回调 KrSocketService.instance.setOnConnectionStateCallback(_kr_handleConnectionState); // 建立连接 KrSocketService.instance.connect(); } /// 处理接收到的消息 void _kr_handleMessage(Map message) { try { final String method = message['method'] as String; switch (method) { case 'kicked_device': KRLogUtil.kr_i('超出登录设备限制', tag: 'AppRunData'); kr_loginOut(); break; case 'kicked_admin': KRLogUtil.kr_i('强制退出', tag: 'AppRunData'); kr_loginOut(); break; case 'subscribe_update': KRLogUtil.kr_i('订阅信息已更新', tag: 'AppRunData'); // 发送订阅更新事件 KREventBus().kr_sendMessage(KRMessageType.kr_subscribe_update); break; default: KRLogUtil.kr_w('收到未知类型的消息: $message', tag: 'AppRunData'); } } catch (e) { KRLogUtil.kr_e('处理消息失败: $e', tag: 'AppRunData'); } } /// 处理连接状态变化 void _kr_handleConnectionState(bool isConnected) { KRLogUtil.kr_i('WebSocket 连接状态: ${isConnected ? "已连接" : "已断开"}', tag: 'AppRunData'); } /// 断开 Socket 连接 Future _kr_disconnectSocket() async { await KrSocketService.instance.disconnect(); } }