fix: 修改客服

This commit is contained in:
2026-01-09 01:36:24 -08:00
parent eb4fad64cb
commit ac65aaa227
12 changed files with 435 additions and 191 deletions
@@ -1,95 +1,114 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:get/get.dart';
import 'package:crisp_sdk/crisp_sdk.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:io' show Platform;
import '../controllers/kr_crisp_controller.dart';
import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
import '../../../widgets/kr_simple_loading.dart';
import 'package:kaer_with_panels/app/widgets/hi_base_scaffold.dart';
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
// 桌面平台使用 WebView SDK
import 'package:crisp_sdk/crisp_sdk.dart' as webview_crisp;
/// Crisp 客服聊天视图
/// 🔧 P15 重构: Crisp 客服聊天视图
/// - 移动平台 (Android/iOS): 打开原生聊天界面后自动返回
/// - 桌面平台 (macOS/Windows): 在页面内嵌入 WebView
class KRCrispView extends GetView<KRCrispController> {
const KRCrispView({Key? key}) : super(key: key);
/// 是否为移动平台
bool get _isMobilePlatform => Platform.isAndroid || Platform.isIOS;
@override
Widget build(BuildContext context) {
return PopScope(
onPopInvokedWithResult: (didPop, result) async {
if (didPop) {
await controller.kr_cleanupResources();
}
},
child: Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: _kr_buildAppBar(context),
body: _kr_buildBody(context),
),
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: _kr_buildAppBar(context),
body: _kr_buildBody(context),
);
}
/// 构建导航栏
PreferredSizeWidget _kr_buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.transparent,
toolbarHeight: 0.0,
backgroundColor: Theme.of(context).cardColor,
elevation: 0,
automaticallyImplyLeading: false, // 1. 禁用自动生成的 leading
// title: Text(
// AppTranslations.kr_userInfo.customerService,
// style: KrAppTextStyle(
// color: Theme.of(context).textTheme.bodyMedium?.color,
// fontSize: 16,
// fontWeight: FontWeight.w500,
// ),
// ),
title: Text(
AppTranslations.kr_userInfo.customerService,
style: KrAppTextStyle(
color: Theme.of(context).textTheme.bodyMedium?.color,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 20.sp,
color: Theme.of(context).textTheme.bodyMedium?.color,
),
onPressed: () => Get.back(),
),
);
}
/// 构建主体内容
Widget _kr_buildBody(BuildContext context) {
return Stack(
children: [
// --- 第一层:WebView 内容 ---
// Obx 包裹的是 CrispView 和其他状态视图
Obx(() {
if (controller.kr_isLoading.value) {
return _kr_buildLoadingView(context, '正在初始化客服系统...');
return Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: Obx(() {
// ========== 移动平台 ==========
if (_isMobilePlatform) {
if (!controller.kr_isInitialized.value) {
return _kr_buildErrorView(context);
}
// 显示加载中界面,同时原生聊天界面在后台启动
return _kr_buildLoadingView(context, '正在加载客服');
}
if (controller.kr_isInitialized.value && controller.crispController != null) {
return CrispView(
crispController: controller.crispController!,
clearCache: true,
onSessionIdReceived: _kr_onSessionIdReceived,
);
}
// ========== 桌面平台 ==========
if (controller.kr_isLoading.value) {
return _kr_buildLoadingView(context, '正在初始化客服系统');
}
return _kr_buildErrorView(context);
}),
if (controller.kr_isInitialized.value && controller.crispController != null) {
// 桌面平台:嵌入 WebView
return webview_crisp.CrispView(
crispController: controller.crispController!,
clearCache: true,
onSessionIdReceived: _kr_onSessionIdReceived,
);
}
// --- 第二层:悬浮的返回按钮 ---
Positioned(
// 4. 使用 MediaQuery 获取状态栏高度,确保按钮不会与系统UI重叠
top: 40.w,
left: 20.w,
child: GestureDetector(
onTap: () => _kr_handleBack(),
behavior: HitTestBehavior.translucent,
child: KrLocalImage(
imageName: 'hi-back-icon',
width: 48.w,
height: 48.w,
imageType: ImageType.svg,
),
),
),
],
return _kr_buildErrorView(context);
}),
);
}
/// 打开原生 Crisp 聊天界面 (移动平台)
void _kr_openNativeCrispChat(BuildContext context) async {
if (!controller.kr_isInitialized.value) {
if (kDebugMode) {
print('[P15-Mobile] Crisp 未初始化,无法打开聊天');
}
return;
}
try {
if (kDebugMode) {
print('[P15-Mobile] 正在打开原生 Crisp 聊天界面...');
}
// 打开原生聊天界面
await controller.kr_openNativeCrispChat();
} catch (e) {
if (kDebugMode) {
print('[P15-Mobile] 打开 Crisp 聊天时出错: $e');
}
}
}
/// 构建加载视图
Widget _kr_buildLoadingView(BuildContext context, String message) {
return Center(
@@ -97,7 +116,7 @@ class KRCrispView extends GetView<KRCrispController> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
KRSimpleLoading(
color: Theme.of(context).primaryColor,
color: Colors.blue,
size: 50.0,
),
if (message.isNotEmpty) SizedBox(height: 16.sp),
@@ -127,7 +146,7 @@ class KRCrispView extends GetView<KRCrispController> {
),
SizedBox(height: 16.sp),
Text(
'客服系统初始化失败',
'crisp.initFailed'.tr,
style: KrAppTextStyle(
fontSize: 16,
color: Colors.red,
@@ -136,23 +155,21 @@ class KRCrispView extends GetView<KRCrispController> {
SizedBox(height: 24.sp),
ElevatedButton(
onPressed: () {
controller.kr_initializeCrisp();
if (_isMobilePlatform) {
_kr_openNativeCrispChat(context);
} else {
controller.kr_initializeDesktopCrisp();
}
},
child: Text('重试'),
child: Text('common.retry'.tr),
),
],
),
);
}
/// 处理返回事件
Future<void> _kr_handleBack() async {
await controller.kr_cleanupResources();
Get.back();
}
/// 处理会话 ID 接收事件
/// 处理会话 ID 接收事件 (桌面平台)
void _kr_onSessionIdReceived(String sessionId) {
debugPrint('Crisp 会话 ID: $sessionId');
debugPrint('[P15-Desktop] Crisp 会话 ID: $sessionId');
}
}