You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

541 lines
18 KiB

3 years ago
import 'dart:async';
// import 'dart:io';
import 'package:bytedesk_kefu/http/bytedesk_device_api.dart';
import 'package:bytedesk_kefu/http/bytedesk_thread_api.dart';
import 'package:bytedesk_kefu/model/app.dart';
import 'package:bytedesk_kefu/model/jsonResult.dart';
import 'package:bytedesk_kefu/model/thread.dart';
import 'package:bytedesk_kefu/model/userJsonResult.dart';
import 'package:bytedesk_kefu/model/wechatResult.dart';
import 'package:bytedesk_kefu/ui/channel/provider/channel_provider.dart';
import 'package:bytedesk_kefu/ui/chat/page/chat_webview_page.dart';
import 'package:bytedesk_kefu/ui/chat/provider/chat_im_provider.dart';
import 'package:bytedesk_kefu/ui/chat/provider/chat_thread_provider.dart';
import 'package:bytedesk_kefu/ui/faq/provider/help_provider.dart';
import 'package:bytedesk_kefu/ui/feedback/provider/feedback_provider.dart';
import 'package:bytedesk_kefu/ui/leavemsg/provider/leavemsg_provider.dart';
import 'package:bytedesk_kefu/ui/ticket/provider/ticket_provider.dart';
import 'package:flutter/services.dart';
import 'package:bytedesk_kefu/http/bytedesk_user_api.dart';
import 'package:bytedesk_kefu/ui/chat/provider/chat_kf_provider.dart';
import 'package:bytedesk_kefu/util/bytedesk_utils.dart';
import 'package:bytedesk_kefu/util/bytedesk_constants.dart';
import 'package:sp_util/sp_util.dart';
import 'package:flutter/material.dart';
import 'model/user.dart';
class BytedeskKefu {
//
static const MethodChannel _channel = const MethodChannel('bytedesk_kefu');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
// 下面为 自定义接口
static void init(String appKey, String subDomain) async {
anonymousLogin(appKey, subDomain);
}
// 支持自定义用户名方便跟APP业务系统对接
static void initWithUsername(
String username, String appKey, String subDomain) async {
initWithUsernameAndNickname(username, "", appKey, subDomain);
}
static void initWithUsernameAndNickname(
String username, String nickname, String appKey, String subDomain) async {
initWithUsernameAndNicknameAndAvatar(
username, nickname, "", appKey, subDomain);
}
static void initWithUsernameAndNicknameAndAvatar(String username,
String nickname, String avatar, String appKey, String subDomain) async {
/// sp初始化
await SpUtil.getInstance();
// 首先检测是否是第一次,如果是第一此启动
String? spusername = SpUtil.getString(BytedeskConstants.username);
3 years ago
String? sppassword = SpUtil.getString(BytedeskConstants.password);
if (spusername!.isNotEmpty) {
// 登录
userLogin(spusername, sppassword!, appKey, subDomain);
} else {
// 调用注册接口
// 默认密码同用户名
3 years ago
String password = username;
await BytedeskUserHttpApi()
.registerUser(username, nickname, password, avatar, subDomain);
3 years ago
// 注册成功之后,调用登录接口
String usernameCompose = username + "@" + subDomain;
userLogin(usernameCompose, password, appKey, subDomain);
3 years ago
}
}
// 访客匿名登录接口
static void anonymousLogin(String appKey, String subDomain) async {
/// sp初始化
await SpUtil.getInstance();
// 首先检测是否是第一次,如果是第一此启动
String? username = SpUtil.getString(BytedeskConstants.username);
String? unionid = SpUtil.getString(BytedeskConstants.unionid);
if (username!.isEmpty && unionid!.isEmpty) {
// 第一此启动, 则调用注册接口,否则调用登录接口
User user = await BytedeskUserHttpApi().registerAnonymous(subDomain);
visitorLogin(user.username!, appKey, subDomain);
} else if (username.isNotEmpty) {
// 用户名登录,非微信登录
visitorLogin(username, appKey, subDomain);
} else if (unionid!.isNotEmpty) {
// 微信登录
unionidOAuth(unionid);
} else {
// 验证码登录其他账号,非当前匿名登录账户
otherOAuth();
}
}
// 匿名访客登录
static void visitorLogin(String username, String appkey, String subDomain) {
String password = username;
login(
username, password, appkey, subDomain, BytedeskConstants.ROLE_VISITOR);
}
// 开发者自定义用户名登录接口
static void userLogin(
String username, String password, String appkey, String subDomain) {
login(
username, password, appkey, subDomain, BytedeskConstants.ROLE_VISITOR);
}
// 用户名登录
static void login(String username, String password, String appkey,
String subDomain, String role) async {
//
SpUtil.putString(BytedeskConstants.role, role);
if (role == BytedeskConstants.ROLE_ADMIN) {
if (!username.contains("@")) {
username = username + "@" + subDomain;
}
}
await BytedeskUserHttpApi().oauth(username, password);
// 登录成功之后,建立长连接
3 years ago
connect();
3 years ago
// if (role == BytedeskConstants.ROLE_ADMIN) {
// // TODO: 如果是客服账号,加载个人信息
// }
// 上传设备信息
await BytedeskDeviceHttpApi().setDeviceInfo();
}
// 微信unionid登录
static void unionidOAuth(String unionid) async {
//
await BytedeskUserHttpApi().unionIdOAuth(unionid);
// 登录成功之后,建立长连接
3 years ago
connect();
3 years ago
// 上传设备信息
await BytedeskDeviceHttpApi().setDeviceInfo();
}
// 直接建立长连接
static void otherOAuth() async {
// 登录成功之后,建立长连接
3 years ago
connect();
3 years ago
// 上传设备信息
await BytedeskDeviceHttpApi().setDeviceInfo();
}
// 建立长连接
static bool connect() {
return BytedeskUtils.mqttConnect();
}
// 重连
static bool reconnect() {
return BytedeskUtils.mqttReConnect();
}
3 years ago
// 断开
static void disconnect() {
BytedeskUtils.mqttDisconnect();
}
3 years ago
// 判断长连接状态
static bool isConnected() {
return BytedeskUtils.isMqttConnected();
}
// 技能组客服会话
static void startWorkGroupChat(
BuildContext context, String wid, String title) {
startChatDefault(
3 years ago
context, wid, BytedeskConstants.CHAT_TYPE_WORKGROUP, title, false);
}
static void startWorkGroupChatV2Robot(
BuildContext context, String wid, String title) {
startChatDefault(
context, wid, BytedeskConstants.CHAT_TYPE_WORKGROUP, title, true);
3 years ago
}
// 发送附言消息
static void startWorkGroupChatPostscript(
BuildContext context, String wid, String title, String postScript) {
startChat(context, wid, BytedeskConstants.CHAT_TYPE_WORKGROUP, title, '',
3 years ago
postScript, false, null);
3 years ago
}
// 电商接口,携带商品参数
// type/title/content/price/url/imageUrl/id/categoryCode
static void startWorkGroupChatShop(
BuildContext context, String wid, String title, String commodity) {
startChatShop(context, wid, BytedeskConstants.CHAT_TYPE_WORKGROUP, title,
commodity, null);
}
static void startWorkGroupChatShopCallback(BuildContext context, String wid,
String title, String commodity, ValueSetter<String> customCallback) {
startChatShop(context, wid, BytedeskConstants.CHAT_TYPE_WORKGROUP, title,
commodity, customCallback);
}
// 指定客服会话
static void startAppointedChat(
BuildContext context, String uid, String title) {
startChatDefault(
3 years ago
context, uid, BytedeskConstants.CHAT_TYPE_APPOINTED, title, false);
3 years ago
}
// 发送附言消息
static void startAppointedChatPostscript(
BuildContext context, String uid, String title, String postScript) {
startChat(context, uid, BytedeskConstants.CHAT_TYPE_APPOINTED, title, '',
3 years ago
postScript, false, null);
3 years ago
}
// 电商接口,携带商品参数
static void startAppointedChatShop(
BuildContext context, String uid, String title, String commodity) {
startChatShop(context, uid, BytedeskConstants.CHAT_TYPE_APPOINTED, title,
commodity, null);
}
static void startAppointedChatShopCallback(BuildContext context, String uid,
String title, String commodity, ValueSetter<String> customCallback) {
startChatShop(context, uid, BytedeskConstants.CHAT_TYPE_APPOINTED, title,
commodity, customCallback);
}
// 默认设置商品信息和附言为空
static void startChatDefault(
3 years ago
BuildContext context, String uuid, String type, String title, bool isV2Robot) {
startChat(context, uuid, type, title, '', '', isV2Robot, null);
3 years ago
}
// 电商对话-自定义类型(技能组、指定客服)
static void startChatShop(BuildContext context, String uuid, String type,
String title, String commodity, ValueSetter<String>? customCallback) {
3 years ago
startChat(context, uuid, type, title, commodity, '', false, customCallback);
3 years ago
}
// 发送附言消息-自定义类型(技能组、指定客服)
static void startChatPostscript(BuildContext context, String uuid,
String type, String title, String postScript) {
3 years ago
startChat(context, uuid, type, title, '', postScript, false, null);
3 years ago
}
// 客服会话-自定义类型(技能组、指定客服)
static void startChat(
BuildContext context,
String uuid,
String type,
String title,
String commodity,
String postScript,
3 years ago
bool isV2Robot,
3 years ago
ValueSetter<String>? customCallback) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatKFProvider(
wid: uuid,
aid: uuid,
type: type,
title: title,
custom: commodity,
postscript: postScript,
3 years ago
isV2Robot: isV2Robot,
3 years ago
customCallback: customCallback,
);
}));
}
// 从历史会话或者点击通知栏进入
static void startChatThread(BuildContext context, Thread thread,
{String title = ''}) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatThreadProvider(
thread: thread,
title: title,
);
}));
}
// 应用内打开H5客服页面
static void startH5Chat(BuildContext context, String url, String title) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatWebViewPage(
url: url,
title: title,
);
}));
}
// 应用内打开网页
static void openWebView(BuildContext context, String url, String title) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatWebViewPage(
url: url,
title: title,
);
}));
}
// TODO: 好友一对一聊天
static void startContactChat(BuildContext context, String cid, String title) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatIMProvider(
// cid: cid,
title: title,
);
}));
}
// TODO: 好友一对一,携带商品参数
// static void startContactChatShop(
// BuildContext context, String cid, String title, String commodity) {
// Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
// return new ChatIMProvider(
// // cid: cid,
// title: title,
// custom: commodity,
// );
// }));
// }
// TODO: 客服端-进入接待访客对话页面
static void startChatThreadIM(BuildContext context, Thread thread) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChatIMProvider(
thread: thread,
isThread: true,
);
}));
}
// 常见问题列表
static void showFaq(BuildContext context, String uid) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new HelpProvider(uid: uid);
}));
}
// 意见反馈
static void showFeedback(BuildContext context, String uid) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new FeedbackProvider(uid: uid);
}));
}
// TODO: 提交工单
static void showTicket(BuildContext context, String uid) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new TicketProvider(uid: uid);
}));
}
// TODO: 留言
static void showLeaveMessage(
BuildContext context, String uuid, String type, String tip) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new LeaveMsgProvider(
wid: uuid,
aid: uuid,
type: type,
tip: tip,
);
}));
}
// 频道消息
static void showChannel(BuildContext context, Thread thread) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new ChannelProvider(
thread: thread,
);
}));
}
// 获取个人资料
static Future<User> getProfile() async {
return BytedeskUserHttpApi().getProfile();
}
// 设置用户昵称
static Future<User> updateNickname(String nickname) async {
return BytedeskUserHttpApi().updateNickname(nickname);
}
// 设置用户头像
static Future<User> updateAvatar(String avatar) async {
return BytedeskUserHttpApi().updateAvatar(avatar);
}
// 设置用户备注
3 years ago
static Future<User> updateDescription(String description) async {
return BytedeskUserHttpApi().updateDescription(description);
}
// 一个接口,设置:昵称、头像、备注
static Future<User> updateProfile(String nickname, String avatar, String description) async {
return BytedeskUserHttpApi().updateProfile(nickname, avatar, description);
3 years ago
}
// 查询技能组在线状态
static Future<String> getWorkGroupStatus(String workGroupWid) async {
return BytedeskUserHttpApi().getWorkGroupStatus(workGroupWid);
}
// 查询客服在线状态
static Future<String> getAgentStatus(String agentUid) async {
return BytedeskUserHttpApi().getAgentStatus(agentUid);
}
// 查询当前用户-某技能组wid或指定客服未读消息数目
static Future<String> getUnreadCount(String wid) async {
return BytedeskUserHttpApi().getUnreadCount(wid);
}
// 访客端-查询访客所有未读消息数目
static Future<String> getUnreadCountVisitor() async {
return BytedeskUserHttpApi().getUnreadCountVisitor();
}
// 客服端-查询客服所有未读消息数目
static Future<String> getUnreadCountAgent() async {
return BytedeskUserHttpApi().getUnreadCountAgent();
}
// 访客历史会话
static Future<List<Thread>> getVisitorThreads(int page, int size) async {
return BytedeskThreadHttpApi().getVisitorThreads(page, size);
}
// 消息提示设置
static bool? getPlayAudioOnSendMessage() {
return SpUtil.getBool(BytedeskConstants.PLAY_AUDIO_ON_SEND_MESSAGE,
defValue: true);
}
static void setPlayAudioOnSendMessage(bool flag) {
SpUtil.putBool(BytedeskConstants.PLAY_AUDIO_ON_SEND_MESSAGE, flag);
}
static bool? getPlayAudioOnReceiveMessage() {
return SpUtil.getBool(BytedeskConstants.PLAY_AUDIO_ON_RECEIVE_MESSAGE,
defValue: true);
}
static void setPlayAudioOnReceiveMessage(bool flag) {
SpUtil.putBool(BytedeskConstants.PLAY_AUDIO_ON_RECEIVE_MESSAGE, flag);
}
static bool? getVibrateOnReceiveMessage() {
return SpUtil.getBool(BytedeskConstants.VIBRATE_ON_RECEIVE_MESSAGE,
defValue: true);
}
static void setVibrateOnReceiveMessage(bool flag) {
SpUtil.putBool(BytedeskConstants.VIBRATE_ON_RECEIVE_MESSAGE, flag);
}
// 上传ios devicetoken
static Future<void> uploadIOSDeviceToken(
String appkey, String deviceToken) async {
BytedeskDeviceHttpApi()
.updateIOSDeviceToken(appkey, BytedeskConstants.build, deviceToken);
}
// build的值只有两种情况测试设置为debug 或 线上设置为release
// static Future<void> uploadIOSDeviceToken(
// String appkey, String build, String deviceToken) async {
// BytedeskDeviceHttpApi().updateIOSDeviceToken(appkey, build, deviceToken);
// }
// build的值只有两种情况测试设置为debug 或 线上设置为release
static Future<void> deleteIOSDeviceToken(String build) async {
BytedeskDeviceHttpApi().deleteIOSDeviceToken(build);
}
// The package version. `CFBundleShortVersionString` on iOS, `versionName` on Android.
static Future<String> getAppVersion() {
return BytedeskDeviceHttpApi().getAppVersion();
}
// The build number. `CFBundleVersion` on iOS, `versionCode` on Android.
static Future<String> getAppBuildNumber() {
return BytedeskDeviceHttpApi().getAppBuildNumber();
}
// 从服务器检测当前APP是否有新版
static Future<App> checkAppVersion(String androidKey, String iosKey) {
if (BytedeskUtils.isWeb) {
// FIXME: 仅用于占位,待修改
return BytedeskUserHttpApi().checkAppVersion(iosKey);
} else if (BytedeskUtils.isAndroid) {
return BytedeskUserHttpApi().checkAppVersion(androidKey);
}
return BytedeskUserHttpApi().checkAppVersion(iosKey);
}
// 退出登录
static Future<void> logout() {
3 years ago
// 断开长链接
disconnect();
// 通知服务器,并清空本地数据
3 years ago
return BytedeskUserHttpApi().logout();
}
// 以下为专用接口,普通用户请忽略
// 通过token获取手机号-良师app-专用
static Future<String> getAliyunOneKeyLoginMobile(String token) async {
return BytedeskUserHttpApi().getAliyunOneKeyLoginMobile(token);
}
// 匿名登录之后,绑定手机号-良师app-专用
static Future<JsonResult> bindMobile(String mobile) async {
return BytedeskUserHttpApi().bindMobile(mobile);
}
// 微信登录之后,获取微信用户信息-良师app-专用
static Future<WeChatResult> getWechatUserinfo(String code) async {
return BytedeskUserHttpApi().getWechatUserinfo(code);
}
// 手机端注册微信登录用户-并绑定手机号-良师app-专用
static Future<UserJsonResult> registerWechatMobile(String mobile,
String nickname, String avatar, String unionid, String openid) async {
return BytedeskUserHttpApi()
.registerWechatMobile(mobile, nickname, avatar, unionid, openid);
}
// 将unionid绑定到已经存在的手机账号-良师app-专用
static Future<UserJsonResult> bindWeChatMobile(
String mobile, String unionid) async {
return BytedeskUserHttpApi().bindWeChatMobile(mobile, unionid);
}
}