完善游客模式登录 并且新增设备管理

This commit is contained in:
2025-10-17 21:11:40 +08:00
parent 2333ad52a9
commit de9cf751f3
46 changed files with 4590 additions and 543 deletions
@@ -0,0 +1,294 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
import 'package:kaer_with_panels/app/utils/kr_device_util.dart';
import 'package:kaer_with_panels/app/services/api_service/kr_api.user.dart';
import 'package:kaer_with_panels/app/widgets/dialogs/kr_dialog.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
import 'package:kaer_with_panels/app/services/api_service/kr_auth_api.dart';
import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
import 'package:kaer_with_panels/app/services/kr_device_info_service.dart';
import 'package:kaer_with_panels/app/services/kr_subscribe_service.dart';
import 'package:kaer_with_panels/app/model/enum/kr_request_type.dart';
import 'dart:io';
import 'dart:math';
class KRDeviceManagementController extends GetxController {
// 设备列表
final RxList<Map<String, dynamic>> devices = <Map<String, dynamic>>[].obs;
// 加载状态
final RxBool isLoading = true.obs;
// 当前设备ID
String? currentDeviceId;
@override
void onInit() {
super.onInit();
_initDeviceId();
loadDeviceList();
}
/// 初始化当前设备ID
Future<void> _initDeviceId() async {
try {
currentDeviceId = await KRDeviceUtil().kr_getDeviceId();
KRLogUtil.kr_i('当前设备ID: $currentDeviceId', tag: 'DeviceManagement');
} catch (e) {
KRLogUtil.kr_e('获取设备ID失败: $e', tag: 'DeviceManagement');
}
}
/// 加载设备列表
Future<void> loadDeviceList() async {
try {
isLoading.value = true;
KRLogUtil.kr_i('开始加载设备列表', tag: 'DeviceManagement');
// 调用API获取设备列表
final result = await KRUserApi().kr_getUserDevices();
result.fold(
(error) {
KRLogUtil.kr_e('加载设备列表失败: ${error.msg}', tag: 'DeviceManagement');
Get.snackbar('错误', error.msg);
},
(deviceList) {
KRLogUtil.kr_i('获取到 ${deviceList.length} 个设备', tag: 'DeviceManagement');
// 转换设备数据格式
devices.value = deviceList.map((device) {
final identifier = device['identifier']?.toString() ?? '';
final isCurrent = identifier == currentDeviceId;
return {
'id': device['id']?.toString() ?? '',
'identifier': identifier,
'device_name': device['user_agent'] ?? '未知设备',
'ip': device['ip'] ?? '',
'last_login': device['updated_at'] ?? device['created_at'] ?? '',
'is_current': isCurrent,
'enabled': device['enabled'] ?? true,
'online': device['online'] ?? false,
};
}).toList();
},
);
} catch (e, stackTrace) {
KRLogUtil.kr_e('加载设备列表异常: $e', tag: 'DeviceManagement');
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
Get.snackbar('错误', '加载设备列表失败');
} finally {
isLoading.value = false;
}
}
/// 删除设备
Future<void> deleteDevice(String id) async {
try {
// 检查是否是本机设备
final device = devices.firstWhere(
(d) => d['id'] == id,
orElse: () => {},
);
if (device.isEmpty) return;
final isCurrent = device['is_current'] ?? false;
// 使用响应式变量来接收确认结果
bool? confirmed;
// 显示确认对话框
await KRDialog.show(
title: '确认删除',
message: isCurrent
? '确定要删除本机设备吗?删除后将使用设备登录自动重新登录。'
: '确定要删除此设备吗?删除后该设备将被强制下线。',
icon: Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
Icons.warning_rounded,
color: Colors.red,
size: 32,
),
),
confirmText: '删除',
cancelText: '取消',
onConfirm: () {
confirmed = true;
},
onCancel: () {
confirmed = false;
},
);
if (confirmed != true) return;
KRLogUtil.kr_i('开始解绑设备 - id: $id, isCurrent: $isCurrent', tag: 'DeviceManagement');
// 调用API解绑设备
final result = await KRUserApi().kr_unbindUserDevice(id);
result.fold(
(error) {
KRLogUtil.kr_e('删除设备失败: ${error.msg}', tag: 'DeviceManagement');
Get.snackbar('错误', '删除失败:${error.msg}');
},
(_) async {
KRLogUtil.kr_i('设备删除成功', tag: 'DeviceManagement');
if (isCurrent) {
// 如果删除的是本机设备,重新进行设备登录
KRLogUtil.kr_i('本机设备已删除,准备重新登录', tag: 'DeviceManagement');
// 先关闭当前设备管理页面
Get.back();
// 执行重新登录
await _reloginWithDevice();
} else {
// 删除其他设备,从列表中移除
devices.removeWhere((device) => device['id'] == id);
Get.snackbar('成功', '设备已删除');
}
},
);
} catch (e, stackTrace) {
KRLogUtil.kr_e('删除设备异常: $e', tag: 'DeviceManagement');
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
Get.snackbar('错误', '删除失败:$e');
}
}
/// 重新使用设备登录
Future<void> _reloginWithDevice() async {
try {
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'DeviceManagement');
KRLogUtil.kr_i('开始重新进行设备登录', tag: 'DeviceManagement');
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'DeviceManagement');
// 先清除当前的用户信息(但不调用 kr_loginOut,避免显示登录界面)
final appRunData = KRAppRunData.getInstance();
appRunData.kr_isLogin.value = false;
appRunData.kr_token = null;
appRunData.kr_account.value = null;
appRunData.kr_userId.value = null;
// 检查是否启用设备登录
final siteConfigService = KRSiteConfigService();
final isDeviceLoginEnabled = siteConfigService.isDeviceLoginEnabled();
if (!isDeviceLoginEnabled) {
KRLogUtil.kr_w('设备登录未启用,执行完整退出登录', tag: 'DeviceManagement');
Get.snackbar('提示', '设备登录未启用,请手动登录');
await appRunData.kr_loginOut();
return;
}
KRLogUtil.kr_i('设备登录已启用,开始调用设备登录接口', tag: 'DeviceManagement');
// 初始化设备信息服务(如果还没初始化)
await KRDeviceInfoService().initialize();
// 调用设备登录接口
final authApi = KRAuthApi();
final result = await authApi.kr_deviceLogin();
result.fold(
(error) {
// 设备登录失败
KRLogUtil.kr_e('设备登录失败: ${error.msg}', tag: 'DeviceManagement');
Get.snackbar('错误', '自动登录失败:${error.msg},请手动登录');
// 执行完整退出登录,显示登录界面
appRunData.kr_loginOut();
},
(token) async {
// 设备登录成功
KRLogUtil.kr_i('✅ 设备登录成功!', tag: 'DeviceManagement');
KRLogUtil.kr_i('🎫 Token: ${token.substring(0, min(20, token.length))}...', tag: 'DeviceManagement');
// 保存新的用户信息
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
await appRunData.kr_saveUserInfo(
token,
'device_$deviceId',
KRLoginType.kr_email,
null,
);
KRLogUtil.kr_i('✅ 设备重新登录成功,已更新用户信息', tag: 'DeviceManagement');
// 等待一小段时间,确保登录状态已经更新
await Future.delayed(const Duration(milliseconds: 300));
// 刷新订阅信息
KRLogUtil.kr_i('🔄 开始刷新订阅信息...', tag: 'DeviceManagement');
try {
await KRSubscribeService().kr_refreshAll();
KRLogUtil.kr_i('✅ 订阅信息刷新成功', tag: 'DeviceManagement');
} catch (e) {
KRLogUtil.kr_e('订阅信息刷新失败: $e', tag: 'DeviceManagement');
}
Get.snackbar('成功', '已自动重新登录');
},
);
} catch (e, stackTrace) {
KRLogUtil.kr_e('设备重新登录异常: $e', tag: 'DeviceManagement');
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
Get.snackbar('错误', '自动登录失败,请手动登录');
// 发生异常,执行完整退出登录
await KRAppRunData.getInstance().kr_loginOut();
}
}
/// 获取设备类型和图标
Map<String, dynamic> getDeviceTypeInfo(String userAgent) {
String deviceType = '未知设备';
String iconName = 'devices';
if (userAgent.contains('Android') || userAgent.toLowerCase().contains('android')) {
deviceType = '安卓设备';
iconName = 'phone_android';
} else if (userAgent.contains('iOS') || userAgent.contains('iPhone') || userAgent.toLowerCase().contains('ios')) {
deviceType = 'iOS 设备';
iconName = 'phone_iphone';
} else if (userAgent.contains('iPad')) {
deviceType = 'iPad';
iconName = 'tablet';
} else if (userAgent.contains('macOS') || userAgent.contains('Mac') || userAgent.toLowerCase().contains('mac')) {
deviceType = 'macOS';
iconName = 'desktop_mac';
} else if (userAgent.contains('Windows') || userAgent.toLowerCase().contains('windows')) {
deviceType = 'Windows';
iconName = 'computer';
} else if (userAgent.contains('Linux') || userAgent.toLowerCase().contains('linux')) {
deviceType = 'Linux';
iconName = 'computer';
}
return {
'type': deviceType,
'icon': iconName,
};
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {
super.onClose();
}
}