148 lines
4.3 KiB
Dart
Executable File
148 lines
4.3 KiB
Dart
Executable File
import 'dart:io';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:url_launcher/url_launcher.dart';
|
||
import '../widgets/kr_toast.dart';
|
||
import '../common/app_config.dart';
|
||
import '../routes/app_pages.dart';
|
||
import '../widgets/dialogs/hi_dialog.dart';
|
||
import '../modules/kr_crisp_chat/controllers/kr_crisp_controller.dart';
|
||
|
||
class KRCommonUtil {
|
||
/// 是否正在打开客服(防重复点击)
|
||
static bool _kr_isOpeningCustomerService = false;
|
||
|
||
/// 预热客服(提前初始化控制器)
|
||
static void kr_warmUpCustomerService() {
|
||
if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {
|
||
if (!Get.isRegistered<KRCrispController>()) {
|
||
Get.put(KRCrispController(), permanent: true);
|
||
debugPrint('客服系统预热中(持久模式)...');
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 打开客服
|
||
static Future<void> kr_openCustomerService() async {
|
||
// 🔧 防重复点击
|
||
if (_kr_isOpeningCustomerService) {
|
||
return;
|
||
}
|
||
|
||
final websiteId = AppConfig.getInstance().kr_website_id;
|
||
if (websiteId.isEmpty) {
|
||
HIDialog.show(
|
||
title: '提示',
|
||
message: '加载失败',
|
||
);
|
||
return;
|
||
}
|
||
|
||
// 🔧 Windows 端直接跳转外部浏览器
|
||
if (Platform.isWindows) {
|
||
_kr_isOpeningCustomerService = true;
|
||
|
||
// 显示加载提示
|
||
kr_showToast('userInfo.openingCustomerService'.tr);
|
||
|
||
// 直接使用 zh
|
||
final Uri url = Uri.parse(
|
||
'https://go.crisp.chat/chat/embed/?website_id=$websiteId&locale=zh',
|
||
);
|
||
|
||
try {
|
||
if (await canLaunchUrl(url)) {
|
||
await launchUrl(url, mode: LaunchMode.externalApplication);
|
||
} else {
|
||
kr_showToast("common.cannotOpenBrowser".tr);
|
||
}
|
||
} catch (e) {
|
||
kr_showToast("common.openLinkFailed".tr);
|
||
} finally {
|
||
// 延迟重置状态
|
||
Future.delayed(const Duration(seconds: 2), () {
|
||
_kr_isOpeningCustomerService = false;
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 移动平台 (Android/iOS):直接调用原生 SDK,避免页面跳转闪烁
|
||
if (Platform.isAndroid || Platform.isIOS) {
|
||
_kr_isOpeningCustomerService = true;
|
||
|
||
// 预先显示加载提示(可选,原生 SDK 启动很快)
|
||
// kr_showToast('userInfo.openingCustomerService'.tr);
|
||
|
||
try {
|
||
// 优先使用已注册的控制器
|
||
KRCrispController crispController;
|
||
if (Get.isRegistered<KRCrispController>()) {
|
||
crispController = Get.find<KRCrispController>();
|
||
} else {
|
||
crispController = Get.put(KRCrispController(), permanent: true);
|
||
}
|
||
// 直接调用原生打开方法
|
||
await crispController.kr_openNativeCrispChat();
|
||
} catch (e) {
|
||
debugPrint('打开原生客服失败: $e');
|
||
// 如果原生失败,可以考虑降级到内置页面或报错
|
||
Get.toNamed(Routes.KR_CRISP);
|
||
} finally {
|
||
Future.delayed(const Duration(seconds: 2), () {
|
||
_kr_isOpeningCustomerService = false;
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
|
||
// macOS/桌面平台:跳转内置页面 (WebView 实现)
|
||
_kr_isOpeningCustomerService = true;
|
||
|
||
Get.toNamed(Routes.KR_CRISP);
|
||
|
||
// 延迟重置状态
|
||
Future.delayed(const Duration(seconds: 2), () {
|
||
_kr_isOpeningCustomerService = false;
|
||
});
|
||
}
|
||
|
||
/// 提示 meesage: 提示内容, toastPosition: 提示显示的位置, timeout: 显示时间(毫秒)
|
||
static kr_showToast(String message,
|
||
{KRToastPosition toastPosition = KRToastPosition.center,
|
||
int timeout = 2500}) {
|
||
KRToast.kr_showToast(
|
||
message,
|
||
position: toastPosition,
|
||
duration: Duration(milliseconds: timeout),
|
||
);
|
||
}
|
||
|
||
/// 显示加载动画
|
||
static kr_showLoading({String? message}) {
|
||
KRToast.kr_showLoading(message: message);
|
||
}
|
||
|
||
/// 隐藏加载动画
|
||
static kr_hideLoading() {
|
||
KRToast.kr_hideLoading();
|
||
}
|
||
|
||
/// 格式化字节数为可读字符串
|
||
/// [bytes] 字节数
|
||
static String kr_formatBytes(int bytes) {
|
||
if (bytes <= 0) return "0 B";
|
||
|
||
const List<String> suffixes = ["B", "KB", "MB", "GB", "TB"];
|
||
int i = 0;
|
||
double value = bytes.toDouble();
|
||
|
||
while (value >= 1024 && i < suffixes.length - 1) {
|
||
value /= 1024;
|
||
i++;
|
||
}
|
||
|
||
return "${value.toStringAsFixed(2)} ${suffixes[i]}";
|
||
}
|
||
}
|