1. ✅ /lib/app/common/app_config.dart
- P0: 限制递归重试次数(最多5次)
- P1: 减少超时时间(3s→2s, 6s→4s)
- P1: 移除重复域名配置
2. ✅ /lib/app/services/kr_site_config_service.dart
- P1: 减少网络超时(10s→5s)
3. ✅ /lib/app/modules/kr_splash/controllers/kr_splash_controller.dart
- P0: 总体超时保护(30秒)
- P2: 非阻塞初始化
- P2: 后台任务超时保护(网站配置10s, 设备登录8s)
- P2: 完善错误处理(区分超时/网络/HTTP错误)
- P3: 跳过初始化功能
4. ✅ /lib/app/modules/kr_splash/views/kr_splash_view.dart
- P3: 添加"跳过"按钮
(cherry picked from commit 0a9fe429919fe9ae85b7769df123b72d7e33c6b1)
This commit is contained in:
parent
c5715f77e2
commit
442ea458b7
@ -53,8 +53,9 @@ class KRDomain {
|
|||||||
static Timer? _retryTimer;
|
static Timer? _retryTimer;
|
||||||
static const int kr_retryInterval = 2; // 基础重试间隔(秒)
|
static const int kr_retryInterval = 2; // 基础重试间隔(秒)
|
||||||
static const int kr_maxRetryCount = 2; // 最大重试次数
|
static const int kr_maxRetryCount = 2; // 最大重试次数
|
||||||
static const int kr_domainTimeout = 3; // 域名检测超时时间(秒)
|
// 🔧 P1修复:减少域名检测超时时间
|
||||||
static const int kr_totalTimeout = 6; // 总体超时时间(秒)
|
static const int kr_domainTimeout = 2; // 域名检测超时时间(秒)3→2
|
||||||
|
static const int kr_totalTimeout = 4; // 总体超时时间(秒)6→4
|
||||||
static Set<String> _triedDomains = {}; // 已尝试过的域名集合
|
static Set<String> _triedDomains = {}; // 已尝试过的域名集合
|
||||||
static Map<String, int> _domainResponseTimes = {}; // 域名响应时间记录
|
static Map<String, int> _domainResponseTimes = {}; // 域名响应时间记录
|
||||||
static Map<String, DateTime> _domainLastCheck = {}; // 域名最后检测时间
|
static Map<String, DateTime> _domainLastCheck = {}; // 域名最后检测时间
|
||||||
@ -1057,6 +1058,7 @@ class AppConfig {
|
|||||||
|
|
||||||
/// 请求域名地址
|
/// 请求域名地址
|
||||||
/// 基础url
|
/// 基础url
|
||||||
|
///
|
||||||
// static String baseUrl = "http://103.112.98.72:8088";
|
// static String baseUrl = "http://103.112.98.72:8088";
|
||||||
|
|
||||||
/// 请求域名地址
|
/// 请求域名地址
|
||||||
@ -1146,9 +1148,23 @@ class AppConfig {
|
|||||||
Future<void> _startAutoRetry(Future<void> Function()? onSuccess) async {
|
Future<void> _startAutoRetry(Future<void> Function()? onSuccess) async {
|
||||||
_retryTimer?.cancel();
|
_retryTimer?.cancel();
|
||||||
int currentRetryCount = 0;
|
int currentRetryCount = 0;
|
||||||
|
// 🔧 P0修复:添加总体尝试次数限制,防止无限递归
|
||||||
|
int totalAttempts = 0;
|
||||||
|
const int maxTotalAttempts = 5; // 最多5次尝试(包括域名切换后的重试)
|
||||||
|
|
||||||
Future<void> executeConfigRequest() async {
|
Future<void> executeConfigRequest() async {
|
||||||
try {
|
try {
|
||||||
|
// 🔧 P0修复:检查总体尝试次数
|
||||||
|
totalAttempts++;
|
||||||
|
if (totalAttempts > maxTotalAttempts) {
|
||||||
|
KRLogUtil.kr_e('❌ 超过最大总尝试次数($maxTotalAttempts),停止重试', tag: 'AppConfig');
|
||||||
|
// 使用默认配置继续启动
|
||||||
|
if (onSuccess != null) {
|
||||||
|
await onSuccess();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否超过最大重试次数
|
// 检查是否超过最大重试次数
|
||||||
if (currentRetryCount >= kr_maxRetryCount) {
|
if (currentRetryCount >= kr_maxRetryCount) {
|
||||||
KRLogUtil.kr_w('达到最大重试次数,尝试使用备用域名', tag: 'AppConfig');
|
KRLogUtil.kr_w('达到最大重试次数,尝试使用备用域名', tag: 'AppConfig');
|
||||||
@ -1158,8 +1174,16 @@ class AppConfig {
|
|||||||
KRDomain.kr_currentDomain = newDomain;
|
KRDomain.kr_currentDomain = newDomain;
|
||||||
await KRDomain.kr_saveCurrentDomain();
|
await KRDomain.kr_saveCurrentDomain();
|
||||||
KRLogUtil.kr_i('✅ 最终切换到备用域名: $newDomain', tag: 'AppConfig');
|
KRLogUtil.kr_i('✅ 最终切换到备用域名: $newDomain', tag: 'AppConfig');
|
||||||
|
// 重置当前重试计数,但保留总尝试次数
|
||||||
|
currentRetryCount = 0;
|
||||||
// 继续重试配置请求
|
// 继续重试配置请求
|
||||||
await executeConfigRequest();
|
await executeConfigRequest();
|
||||||
|
} else {
|
||||||
|
KRLogUtil.kr_e('❌ 备用域名切换失败,使用默认配置继续', tag: 'AppConfig');
|
||||||
|
// 使用默认配置继续启动
|
||||||
|
if (onSuccess != null) {
|
||||||
|
await onSuccess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform, SocketException;
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:kaer_with_panels/app/utils/kr_network_check.dart';
|
import 'package:kaer_with_panels/app/utils/kr_network_check.dart';
|
||||||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||||
@ -66,11 +68,14 @@ class KRSplashController extends GetxController {
|
|||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🎬 启动页控制器 onInit', tag: 'SplashController');
|
KRLogUtil.kr_i('[SPLASH_TIMING] 🎬 启动页控制器 onInit', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ═══════════════════════════════════════', tag: 'SplashController');
|
KRLogUtil.kr_i('[SPLASH_TIMING] ═══════════════════════════════════════', tag: 'SplashController');
|
||||||
|
|
||||||
// 异步初始化网站配置
|
// 🔧 P2优化:网站配置和设备登录在后台执行,不阻塞主流程
|
||||||
_kr_initSiteConfig().then((_) {
|
print('🌐 启动后台任务:网站配置加载...');
|
||||||
print('🔧 网站配置完成,开始调用 _kr_initialize...');
|
KRLogUtil.kr_i('🌐 后台任务:网站配置和设备登录', tag: 'SplashController');
|
||||||
_kr_initialize();
|
_kr_initSiteConfig(); // 不等待完成,在后台执行
|
||||||
});
|
|
||||||
|
// 立即开始主初始化流程
|
||||||
|
print('🔧 立即开始主初始化流程...');
|
||||||
|
_kr_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录步骤耗时的辅助方法
|
// 记录步骤耗时的辅助方法
|
||||||
@ -80,14 +85,14 @@ class KRSplashController extends GetxController {
|
|||||||
final totalDuration = now.difference(_startTime);
|
final totalDuration = now.difference(_startTime);
|
||||||
final stepMs = stepDuration.inMilliseconds;
|
final stepMs = stepDuration.inMilliseconds;
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
final totalMs = totalDuration.inMilliseconds;
|
||||||
|
|
||||||
print('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms');
|
print('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms', tag: 'SplashController');
|
KRLogUtil.kr_i('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms', tag: 'SplashController');
|
||||||
|
|
||||||
_stepStartTime = now; // 更新步骤开始时间
|
_stepStartTime = now; // 更新步骤开始时间
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 初始化网站配置(异步执行)
|
/// 初始化网站配置(后台执行,不阻塞主流程)
|
||||||
Future<void> _kr_initSiteConfig() async {
|
Future<void> _kr_initSiteConfig() async {
|
||||||
print('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
print('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||||
print('[SPLASH_TIMING] 🌐 开始初始化网站配置...');
|
print('[SPLASH_TIMING] 🌐 开始初始化网站配置...');
|
||||||
@ -98,23 +103,16 @@ class KRSplashController extends GetxController {
|
|||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
print('📞 准备调用 KRSiteConfigService().initialize()...');
|
// 🔧 P2优化:为后台任务添加10秒超时保护
|
||||||
final success = await KRSiteConfigService().initialize();
|
await Future.any([
|
||||||
final crispId = await KRSiteConfigService().getCrispId();
|
_executeSiteConfigInit(),
|
||||||
print('📞 KRSiteConfigService().initialize() 返回: $success');
|
Future.delayed(const Duration(seconds: 10), () {
|
||||||
|
throw TimeoutException('网站配置加载超时(10秒)');
|
||||||
if (success) {
|
}),
|
||||||
final config = AppConfig.getInstance();
|
]);
|
||||||
config.kr_website_id = crispId;
|
} on TimeoutException catch (e) {
|
||||||
print('📞 KRSiteConfigService().initialize() 返回: $crispId');
|
print('⏱️ 网站配置加载超时,应用将使用默认配置: $e');
|
||||||
print('AppConfig website_id 已更新为: ${config.kr_website_id}');
|
KRLogUtil.kr_w('⏱️ 网站配置加载超时: $e', tag: 'SplashController');
|
||||||
|
|
||||||
print('[SPLASH_TIMING] ✅ 网站配置初始化成功');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ✅ 网站配置初始化成功', tag: 'SplashController');
|
|
||||||
} else {
|
|
||||||
print('⚠️ 网站配置初始化失败,将使用默认配置');
|
|
||||||
KRLogUtil.kr_w('⚠️ 网站配置初始化失败,将使用默认配置', tag: 'SplashController');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('❌ 网站配置初始化异常: $e');
|
print('❌ 网站配置初始化异常: $e');
|
||||||
KRLogUtil.kr_e('❌ 网站配置初始化异常: $e', tag: 'SplashController');
|
KRLogUtil.kr_e('❌ 网站配置初始化异常: $e', tag: 'SplashController');
|
||||||
@ -124,94 +122,215 @@ class KRSplashController extends GetxController {
|
|||||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 执行网站配置初始化
|
||||||
|
Future<void> _executeSiteConfigInit() async {
|
||||||
|
print('📞 准备调用 KRSiteConfigService().initialize()...');
|
||||||
|
final success = await KRSiteConfigService().initialize();
|
||||||
|
final crispId = await KRSiteConfigService().getCrispId();
|
||||||
|
print('📞 KRSiteConfigService().initialize() 返回: $success');
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
final config = AppConfig.getInstance();
|
||||||
|
config.kr_website_id = crispId;
|
||||||
|
print('📞 KRSiteConfigService().initialize() 返回: $crispId');
|
||||||
|
print('AppConfig website_id 已更新为: ${config.kr_website_id}');
|
||||||
|
|
||||||
|
print('[SPLASH_TIMING] ✅ 网站配置初始化成功');
|
||||||
|
await _kr_checkAndPerformDeviceLogin();
|
||||||
|
} else {
|
||||||
|
print('⚠️ 网站配置初始化失败,将使用默认配置');
|
||||||
|
KRLogUtil.kr_w('⚠️ 网站配置初始化失败,将使用默认配置', tag: 'SplashController');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检查并执行设备登录(后台执行,有超时保护)
|
||||||
|
Future<void> _kr_checkAndPerformDeviceLogin() async {
|
||||||
|
try {
|
||||||
|
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||||
|
print('🔍 检查是否支持设备登录...');
|
||||||
|
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||||
|
|
||||||
|
final siteConfigService = KRSiteConfigService();
|
||||||
|
|
||||||
|
// 检查是否启用设备登录
|
||||||
|
final isDeviceLoginEnabled = siteConfigService.isDeviceLoginEnabled();
|
||||||
|
print('📱 设备登录状态: ${isDeviceLoginEnabled ? "已启用" : "未启用"}');
|
||||||
|
KRLogUtil.kr_i('📱 设备登录状态: $isDeviceLoginEnabled', tag: 'SplashController');
|
||||||
|
|
||||||
|
if (!isDeviceLoginEnabled) {
|
||||||
|
print('⚠️ 设备登录未启用,跳过自动登录');
|
||||||
|
KRLogUtil.kr_w('⚠️ 设备登录未启用', tag: 'SplashController');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print('✅ 设备登录已启用,开始初始化设备信息...');
|
||||||
|
|
||||||
|
// 🔧 P2优化:为设备登录添加8秒超时保护
|
||||||
|
await Future.any([
|
||||||
|
_executeDeviceLogin(),
|
||||||
|
Future.delayed(const Duration(seconds: 8), () {
|
||||||
|
throw TimeoutException('设备登录超时(8秒)');
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||||
|
} on TimeoutException catch (e) {
|
||||||
|
print('⏱️ 设备登录超时,应用将继续启动: $e');
|
||||||
|
KRLogUtil.kr_w('⏱️ 设备登录超时: $e', tag: 'SplashController');
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
print('❌ 设备登录检查异常: $e');
|
||||||
|
print('📚 堆栈跟踪: $stackTrace');
|
||||||
|
KRLogUtil.kr_e('❌ 设备登录检查异常: $e', tag: 'SplashController');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 执行设备登录
|
||||||
|
Future<void> _executeDeviceLogin() async {
|
||||||
|
// 初始化设备信息服务
|
||||||
|
await KRDeviceInfoService().initialize();
|
||||||
|
|
||||||
|
print('🔐 开始执行设备登录...');
|
||||||
|
KRLogUtil.kr_i('🔐 开始执行设备登录', tag: 'SplashController');
|
||||||
|
|
||||||
|
// 执行设备登录
|
||||||
|
final authApi = KRAuthApi();
|
||||||
|
final result = await authApi.kr_deviceLogin();
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(error) {
|
||||||
|
print('❌ 设备登录失败: ${error.msg}');
|
||||||
|
KRLogUtil.kr_e('❌ 设备登录失败: ${error.msg}', tag: 'SplashController');
|
||||||
|
},
|
||||||
|
(token) async {
|
||||||
|
print('✅ 设备登录成功!');
|
||||||
|
print('🎫 Token: ${token.substring(0, min(20, token.length))}...');
|
||||||
|
KRLogUtil.kr_i('✅ 设备登录成功', tag: 'SplashController');
|
||||||
|
|
||||||
|
// 使用 saveUserInfo 保存完整的用户信息
|
||||||
|
// 设备登录使用特殊的账号标识,登录类型设为邮箱(后续可以绑定真实账号)
|
||||||
|
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
|
||||||
|
await KRAppRunData.getInstance().kr_saveUserInfo(
|
||||||
|
token,
|
||||||
|
'device_$deviceId', // 使用设备ID作为临时账号
|
||||||
|
KRLoginType.kr_email, // 默认登录类型
|
||||||
|
null, // 设备登录无需区号
|
||||||
|
);
|
||||||
|
print('💾 用户信息已保存(包括Token)');
|
||||||
|
print('✅ 已标记为登录状态');
|
||||||
|
KRLogUtil.kr_i('✅ 设备登录流程完成', tag: 'SplashController');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _kr_initialize() async {
|
Future<void> _kr_initialize() async {
|
||||||
try {
|
try {
|
||||||
_logStepTiming('开始主要初始化流程');
|
KRLogUtil.kr_i('🔧 开始执行 _kr_initialize', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🔧 开始执行 _kr_initialize', tag: 'SplashController');
|
|
||||||
|
|
||||||
// 只在手机端检查网络权限
|
// 🔧 P0修复:添加总体超时保护(30秒)
|
||||||
if (Platform.isIOS || Platform.isAndroid) {
|
await Future.any([
|
||||||
_logStepTiming('开始网络权限检查');
|
_executeInitialization(),
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 📱 移动平台,检查网络权限...', tag: 'SplashController');
|
Future.delayed(const Duration(seconds: 30), () {
|
||||||
final bool hasNetworkPermission = await KRNetworkCheck.kr_initialize(
|
throw TimeoutException('初始化超时:30秒内未完成');
|
||||||
Get.context!,
|
}),
|
||||||
onPermissionGranted: () async {
|
]);
|
||||||
_logStepTiming('网络权限检查完成');
|
} on TimeoutException catch (e) {
|
||||||
await _kr_continueInitialization();
|
// 🔧 P2优化:超时错误提供更友好的提示
|
||||||
},
|
KRLogUtil.kr_e('⏱️ 初始化超时: $e', tag: 'SplashController');
|
||||||
);
|
print('⏱️ 初始化超时,直接跳转到主页');
|
||||||
|
// 超时后直接跳转到主页,让用户可以手动重试
|
||||||
if (!hasNetworkPermission) {
|
Get.offAllNamed(Routes.KR_MAIN);
|
||||||
// 计算网络权限失败时的总耗时
|
} on SocketException catch (e) {
|
||||||
final endTime = DateTime.now();
|
// 🔧 P2优化:网络连接错误
|
||||||
final totalDuration = endTime.difference(_startTime);
|
KRLogUtil.kr_e('❌ 网络连接错误: $e', tag: 'SplashController');
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
_handleError('网络连接失败', '请检查您的网络连接是否正常,然后重试。');
|
||||||
|
} on DioException catch (e) {
|
||||||
print('❌ 网络权限失败时间: ${endTime.toIso8601String()}');
|
// 🔧 P2优化:HTTP请求错误
|
||||||
print('🕐 网络权限失败总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
KRLogUtil.kr_e('❌ HTTP请求错误: ${e.type} - ${e.message}', tag: 'SplashController');
|
||||||
|
final errorMsg = _getDioErrorMessage(e);
|
||||||
kr_hasError.value = true;
|
_handleError('服务请求失败', errorMsg);
|
||||||
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkPermissionFailed;
|
|
||||||
KRLogUtil.kr_e('❌ 网络权限检查失败', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_e('⏰ 网络权限失败总耗时: ${totalMs}ms', tag: 'SplashController');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 非手机端直接继续初始化
|
|
||||||
_logStepTiming('桌面平台跳过权限检查');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 💻 桌面平台,直接执行初始化', tag: 'SplashController');
|
|
||||||
await _kr_continueInitialization();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 计算初始化异常时的总耗时
|
// 🔧 P2优化:其他未知错误
|
||||||
final endTime = DateTime.now();
|
KRLogUtil.kr_e('❌ 未知初始化异常: $e', tag: 'SplashController');
|
||||||
final totalDuration = endTime.difference(_startTime);
|
_handleError('初始化失败', '应用启动时发生错误,请尝试重启应用或清除缓存。');
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print('❌ 初始化异常时间: ${endTime.toIso8601String()}');
|
/// 处理错误并显示
|
||||||
print('🕐 初始化异常总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
void _handleError(String title, String message) {
|
||||||
|
kr_hasError.value = true;
|
||||||
|
kr_errorMessage.value = '$title\n\n$message';
|
||||||
|
}
|
||||||
|
|
||||||
KRLogUtil.kr_e('❌ _kr_initialize 异常: $e', tag: 'SplashController');
|
/// 获取Dio错误的友好提示
|
||||||
KRLogUtil.kr_e('⏰ 初始化异常总耗时: ${totalMs}ms', tag: 'SplashController');
|
String _getDioErrorMessage(DioException e) {
|
||||||
kr_hasError.value = true;
|
switch (e.type) {
|
||||||
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
|
case DioExceptionType.connectionTimeout:
|
||||||
|
case DioExceptionType.sendTimeout:
|
||||||
|
case DioExceptionType.receiveTimeout:
|
||||||
|
return '请求超时,请检查网络连接后重试。';
|
||||||
|
case DioExceptionType.badResponse:
|
||||||
|
final statusCode = e.response?.statusCode;
|
||||||
|
if (statusCode == 404) {
|
||||||
|
return '服务地址未找到(404),请联系管理员。';
|
||||||
|
} else if (statusCode == 500) {
|
||||||
|
return '服务器内部错误(500),请稍后重试。';
|
||||||
|
} else if (statusCode == 401 || statusCode == 403) {
|
||||||
|
return '访问被拒绝($statusCode),请检查配置。';
|
||||||
|
}
|
||||||
|
return '服务器返回错误($statusCode),请稍后重试。';
|
||||||
|
case DioExceptionType.cancel:
|
||||||
|
return '请求已取消';
|
||||||
|
case DioExceptionType.connectionError:
|
||||||
|
return '无法连接到服务器,请检查网络设置。';
|
||||||
|
default:
|
||||||
|
return '网络请求失败,请检查网络后重试。';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔧 P0修复:将原来的初始化逻辑提取到单独方法
|
||||||
|
Future<void> _executeInitialization() async {
|
||||||
|
// 只在手机端检查网络权限
|
||||||
|
if (Platform.isIOS || Platform.isAndroid) {
|
||||||
|
KRLogUtil.kr_i('📱 移动平台,检查网络权限...', tag: 'SplashController');
|
||||||
|
final bool hasNetworkPermission = await KRNetworkCheck.kr_initialize(
|
||||||
|
Get.context!,
|
||||||
|
onPermissionGranted: () async {
|
||||||
|
await _kr_continueInitialization();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasNetworkPermission) {
|
||||||
|
kr_hasError.value = true;
|
||||||
|
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkPermissionFailed;
|
||||||
|
KRLogUtil.kr_e('❌ 网络权限检查失败', tag: 'SplashController');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非手机端直接继续初始化
|
||||||
|
KRLogUtil.kr_i('💻 桌面平台,直接执行初始化', tag: 'SplashController');
|
||||||
|
await _kr_continueInitialization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _kr_continueInitialization() async {
|
Future<void> _kr_continueInitialization() async {
|
||||||
try {
|
try {
|
||||||
_logStepTiming('开始继续初始化流程');
|
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
KRLogUtil.kr_i('🚀 启动页主流程开始...', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🚀 启动页主流程开始...', tag: 'SplashController');
|
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
|
||||||
|
|
||||||
// 只在手机端检查网络连接
|
// 只在手机端检查网络连接
|
||||||
if (Platform.isIOS || Platform.isAndroid) {
|
if (Platform.isIOS || Platform.isAndroid) {
|
||||||
_logStepTiming('开始网络连接检查');
|
KRLogUtil.kr_i('📱 检查网络连接...', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 📱 检查网络连接...', tag: 'SplashController');
|
|
||||||
final bool isConnected = await KRNetworkCheck.kr_checkNetworkConnection();
|
final bool isConnected = await KRNetworkCheck.kr_checkNetworkConnection();
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
// 计算网络连接失败时的总耗时
|
|
||||||
final endTime = DateTime.now();
|
|
||||||
final totalDuration = endTime.difference(_startTime);
|
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
|
||||||
|
|
||||||
print('❌ 网络连接失败时间: ${endTime.toIso8601String()}');
|
|
||||||
print('🕐 网络连接失败总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
|
||||||
|
|
||||||
kr_hasError.value = true;
|
kr_hasError.value = true;
|
||||||
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkConnectionFailed;
|
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkConnectionFailed;
|
||||||
KRLogUtil.kr_e('❌ 网络连接失败', tag: 'SplashController');
|
KRLogUtil.kr_e('❌ 网络连接失败', tag: 'SplashController');
|
||||||
KRLogUtil.kr_e('⏰ 网络连接失败总耗时: ${totalMs}ms', tag: 'SplashController');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_logStepTiming('网络连接检查完成');
|
KRLogUtil.kr_i('✅ 网络连接正常', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ✅ 网络连接正常', tag: 'SplashController');
|
|
||||||
} else {
|
} else {
|
||||||
_logStepTiming('桌面平台跳过网络检查');
|
KRLogUtil.kr_i('💻 桌面平台,跳过网络连接检查', tag: 'SplashController');
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 💻 桌面平台,跳过网络连接检查', tag: 'SplashController');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网络检查完成后执行设备登录(始终支持)
|
// 网络检查完成后执行设备登录(始终支持)
|
||||||
@ -234,25 +353,17 @@ class KRSplashController extends GetxController {
|
|||||||
_logStepTiming('设备登录检查完成');
|
_logStepTiming('设备登录检查完成');
|
||||||
|
|
||||||
// 初始化配置
|
// 初始化配置
|
||||||
|
KRLogUtil.kr_i('⚙️ 开始初始化应用配置...', tag: 'SplashController');
|
||||||
await AppConfig().initConfig(
|
await AppConfig().initConfig(
|
||||||
onSuccess: () async {
|
onSuccess: () async {
|
||||||
// 配置初始化成功,没有配置
|
// 配置初始化成功,继续后续步骤
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ⚙️ 初始化应用配置...', tag: 'SplashController');
|
KRLogUtil.kr_i('✅ 应用配置初始化成功,继续后续步骤', tag: 'SplashController');
|
||||||
await _kr_continueAfterConfig();
|
await _kr_continueAfterConfig();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 计算配置初始化异常时的总耗时
|
|
||||||
final endTime = DateTime.now();
|
|
||||||
final totalDuration = endTime.difference(_startTime);
|
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
|
||||||
|
|
||||||
print('❌ 配置初始化异常时间: ${endTime.toIso8601String()}');
|
|
||||||
print('🕐 配置初始化异常总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
|
||||||
|
|
||||||
// 配置初始化失败,显示错误信息
|
// 配置初始化失败,显示错误信息
|
||||||
KRLogUtil.kr_e('❌ 启动页初始化异常: $e', tag: 'SplashController');
|
KRLogUtil.kr_e('❌ 启动页初始化异常: $e', tag: 'SplashController');
|
||||||
KRLogUtil.kr_e('⏰ 配置初始化异常总耗时: ${totalMs}ms', tag: 'SplashController');
|
|
||||||
kr_hasError.value = true;
|
kr_hasError.value = true;
|
||||||
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
|
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
|
||||||
}
|
}
|
||||||
@ -285,20 +396,11 @@ class KRSplashController extends GetxController {
|
|||||||
}
|
}
|
||||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||||
|
|
||||||
// 计算总耗时
|
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
final endTime = DateTime.now();
|
KRLogUtil.kr_i('🎯 准备进入主页', tag: 'SplashController');
|
||||||
final totalDuration = endTime.difference(_startTime);
|
KRLogUtil.kr_i('📊 最终登录状态: $loginStatus', tag: 'SplashController');
|
||||||
final totalMs = totalDuration.inMilliseconds;
|
KRLogUtil.kr_i('🎫 Token存在: $hasToken', tag: 'SplashController');
|
||||||
|
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||||
print('[SPLASH_TIMING] ⏰ 启动结束时间: ${endTime.toIso8601String()}');
|
|
||||||
print('[SPLASH_TIMING] 🕐 启动总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
|
||||||
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🎯 准备进入主页', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 📊 最终登录状态: $loginStatus', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🎫 Token存在: $hasToken', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ⏰ 启动总耗时: ${totalMs}ms', tag: 'SplashController');
|
|
||||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
|
||||||
|
|
||||||
// 直接导航到主页(无论是否登录,主页会根据登录状态显示不同内容)
|
// 直接导航到主页(无论是否登录,主页会根据登录状态显示不同内容)
|
||||||
_logStepTiming('开始页面导航');
|
_logStepTiming('开始页面导航');
|
||||||
@ -377,6 +479,20 @@ class KRSplashController extends GetxController {
|
|||||||
_kr_initialize();
|
_kr_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 P3优化:跳过初始化,直接进入主页
|
||||||
|
void kr_skipInitialization() {
|
||||||
|
KRLogUtil.kr_i('⏭️ 用户选择跳过初始化', tag: 'SplashController');
|
||||||
|
print('⏭️ 用户跳过初始化,直接进入主页');
|
||||||
|
|
||||||
|
// 重置状态
|
||||||
|
kr_hasError.value = false;
|
||||||
|
kr_errorMessage.value = '';
|
||||||
|
kr_isLoading.value = false;
|
||||||
|
|
||||||
|
// 直接跳转到主页
|
||||||
|
Get.offAllNamed(Routes.KR_MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onReady() {
|
void onReady() {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
@ -386,4 +502,4 @@ class KRSplashController extends GetxController {
|
|||||||
void onClose() {
|
void onClose() {
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,6 +89,25 @@ class KRSplashView extends GetView<KRSplashController> {
|
|||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
// 🔧 P3优化:添加跳过按钮
|
||||||
|
TextButton(
|
||||||
|
onPressed: controller.kr_skipInitialization,
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: Colors.grey,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 24.w,
|
||||||
|
vertical: 8.h,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'跳过',
|
||||||
|
style: KrAppTextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,10 +12,10 @@ class KRSiteConfigService extends ChangeNotifier {
|
|||||||
static final KRSiteConfigService _instance = KRSiteConfigService._internal();
|
static final KRSiteConfigService _instance = KRSiteConfigService._internal();
|
||||||
factory KRSiteConfigService() => _instance;
|
factory KRSiteConfigService() => _instance;
|
||||||
KRSiteConfigService._internal() {
|
KRSiteConfigService._internal() {
|
||||||
// 配置 Dio 默认超时设置
|
// 🔧 P1修复:减少超时时间 10秒 → 5秒
|
||||||
_dio.options.connectTimeout = const Duration(seconds: 10);
|
_dio.options.connectTimeout = const Duration(seconds: 5);
|
||||||
_dio.options.sendTimeout = const Duration(seconds: 10);
|
_dio.options.sendTimeout = const Duration(seconds: 5);
|
||||||
_dio.options.receiveTimeout = const Duration(seconds: 10);
|
_dio.options.receiveTimeout = const Duration(seconds: 5);
|
||||||
|
|
||||||
// 🔧 配置HttpClientAdapter使用sing-box的mixed代理
|
// 🔧 配置HttpClientAdapter使用sing-box的mixed代理
|
||||||
_dio.httpClientAdapter = IOHttpClientAdapter(
|
_dio.httpClientAdapter = IOHttpClientAdapter(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user