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/services/kr_device_info_service.dart'; import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; import '../services/api_service/kr_api.user.dart'; import '../services/kr_announcement_service.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; /// 用户账号(使用响应式变量以便 UI 能监听变化) final Rx kr_account = Rx(null); /// 用户ID(使用响应式变量以便 UI 能监听变化) final Rx kr_userId = Rx(null); /// 登录类型 KRLoginType? kr_loginType; /// 区号 String? kr_areaCode; // 需要被监听的属性,用 obs 包装 final kr_isLogin = false.obs; KRAppRunData._internal(); factory KRAppRunData() => _instance; static KRAppRunData getInstance() { return _instance; } /// 判断是否是设备登录(游客模式) bool isDeviceLogin() { // 设备登录的账号格式为 "device_设备ID" return kr_account.value != null && kr_account.value!.startsWith('device_'); } /// 从JWT token中解析userId int? _kr_parseUserIdFromToken(String token) { try { // JWT格式: header.payload.signature final parts = token.split('.'); if (parts.length != 3) { KRLogUtil.kr_e('JWT token格式错误', tag: 'AppRunData'); return null; } // 解码payload部分(base64) String payload = parts[1]; // 手动添加必要的padding(base64要求长度是4的倍数) switch (payload.length % 4) { case 0: break; // 不需要padding case 2: payload += '=='; break; case 3: payload += '='; break; default: KRLogUtil.kr_e('JWT payload长度无效', tag: 'AppRunData'); return null; } final decodedBytes = base64.decode(payload); final decodedString = utf8.decode(decodedBytes); // 解析JSON final Map payloadMap = jsonDecode(decodedString); // 获取UserId if (payloadMap.containsKey('UserId')) { final userId = payloadMap['UserId']; KRLogUtil.kr_i('从JWT解析出userId: $userId', tag: 'AppRunData'); return userId is int ? userId : int.tryParse(userId.toString()); } return null; } catch (e) { KRLogUtil.kr_e('解析JWT token失败: $e', tag: 'AppRunData'); return null; } } /// 保存用户信息 Future kr_saveUserInfo( String token, String account, KRLoginType loginType, String? areaCode) async { KRLogUtil.kr_i('开始保存用户信息', tag: 'AppRunData'); try { // 更新内存中的数据 kr_token = token; kr_account.value = account; kr_loginType = loginType; kr_areaCode = areaCode; // 从JWT token中解析userId kr_userId.value = _kr_parseUserIdFromToken(token); KRLogUtil.kr_i('从JWT解析userId: ${kr_userId.value}', tag: 'AppRunData'); 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 连接将在需要时建立 KRLogUtil.kr_i('用户信息已保存,跳过用户信息接口调用', 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.value = null; kr_userId.value = null; kr_loginType = null; kr_areaCode = null; // 删除存储的用户信息 await KRSecureStorage().kr_deleteData(key: _keyUserInfo); // 重置公告显示状态 KRAnnouncementService().kr_reset(); // 重置主页面 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.value = userInfo['account']; final loginTypeValue = userInfo['loginType']; kr_loginType = KRLoginType.values.firstWhere( (e) => e.value == loginTypeValue, orElse: () => KRLoginType.kr_telephone, ); kr_areaCode = userInfo['areaCode'] ?? ""; // 从token中解析userId if (kr_token != null && kr_token!.isNotEmpty) { kr_userId.value = _kr_parseUserIdFromToken(kr_token!); } KRLogUtil.kr_i('解析用户信息成功: token=${kr_token != null}, account=${kr_account.value}', tag: 'AppRunData'); // 验证token有效性 if (kr_token != null && kr_token!.isNotEmpty) { KRLogUtil.kr_i('设置登录状态为true', tag: 'AppRunData'); kr_isLogin.value = true; // 设备登录模式不需要调用用户信息接口 // 用户ID将从订阅信息或其他途径获取 KRLogUtil.kr_i('已登录,跳过用户信息接口调用', 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 _kr_connectSocket(String userId) async { // 如果已存在连接,先断开 await _kr_disconnectSocket(); final deviceId = KRDeviceInfoService().deviceId ?? 'unknown'; 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(); } }