package com.yidianling.im.helper import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.text.TextUtils import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.ydl.webview.H5Params import com.ydl.webview.NewH5Activity import com.ydl.ydlcommon.data.http.BaseAPIResponse import com.ydl.ydlcommon.data.http.BaseResponse import com.ydl.ydlcommon.data.http.RxUtils import com.ydl.ydlcommon.data.http.RxUtils.applySchedulers import com.ydl.ydlcommon.data.http.UpLoadLogUtils.upLoadLog import com.ydl.ydlcommon.modular.ModularServiceManager import com.ydl.ydlcommon.ui.LoadingDialogFragment import com.ydl.ydlcommon.ui.LoadingDialogFragment.Companion.newInstance import com.ydl.ydlcommon.utils.NetworkParamsUtils import com.ydl.ydlcommon.utils.SharedPreferencesEditor import com.ydl.ydlcommon.utils.UserInfoCache import com.ydl.ydlcommon.utils.log.AliYunLogConfig import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper import com.ydl.ydlcommon.utils.remind.HttpErrorUtils.Companion.handleError import com.ydl.ydlcommon.view.dialog.CommonDialog import com.yidianling.common.tools.LogUtil import com.yidianling.common.tools.ToastUtil import com.yidianling.im.R import com.yidianling.im.api.bean.IMExpertBuild import com.yidianling.im.bean.DoctorAssistantRespDtoBean import com.yidianling.im.bean.GetExpert import com.yidianling.im.bean.UserTypeBean import com.yidianling.im.bridge.P2PCustomActionHandlerImpl import com.yidianling.im.config.constants.ImConstants import com.yidianling.im.http.ImRetrofitApi import com.yidianling.im.http.ImRetrofitApi.Companion.getImJavaApi import com.yidianling.im.http.ImRetrofitApi.Companion.getImRetrofitApi import com.yidianling.im.router.ImIn import com.yidianling.im.router.ImIn.isLogin import com.yidianling.im.session.SessionHelper import com.yidianling.im.ui.activity.CmsExamQuestionPaperActivity import com.yidianling.im.ui.page.fragment.bean.ChatItemBean import com.yidianling.uikit.business.session.fragment.YDLMessageFragment import com.yidianling.uikit.business.session.helper.ChatStatusCacheHelper import com.yidianling.uikit.custom.bridge.ActionHandlerStorage import com.yidianling.uikit.custom.bridge.IP2PCustomActionHandler import com.yidianling.uikit.custom.http.ServiceImpl.Companion.instance import com.yidianling.uikit.custom.http.response.ChatStatusBean import com.yidianling.uikit.custom.http.response.RecommendExpertBean import com.yidianling.uikit.custom.widget.TitleBarBottom import com.yidianling.user.api.service.IUserService import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import retrofit2.HttpException import java.net.URLEncoder /** * 私聊页面相关接口封装 */ object IMChatUtil { private var loadingDialog: LoadingDialogFragment? = null private const val USER_TYPE_EXPERT = 2//专家 private const val USER_TYPE_ASSISTANT = 3//助理 private const val USER_TYPE_USER = 1//用户 //展示信息收集卡 private const val SHOW_EMS_POP = 1L lateinit var doctorId: String /** * 接口数据请求完成回调 */ interface ChatDataRequestListener { fun onSuccess(expertInfo: IMExpertBuild) } /** * 客服专用 */ fun startKefuChat(context: AppCompatActivity?) { SessionHelper.startP2PSession( context, -1, ImConstants.KEFUXIAOYI, null, P2PCustomActionHandlerImpl(ImConstants.KEFUXIAOYI, "客服小壹", ImConstants.KEFUXIAOYI) ) } /** * 跳转前置信息收集页 * 悬浮导医进来的 * */ @SuppressLint("CheckResult") fun startCms(context: Activity, location: Int, ffrom2: String?) { ImRetrofitApi.Companion.getImRetrofitApi() .getSystemConfigByKeyword("lx_collect_card_config") .compose(RxUtils.resultJavaData()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { val skipTime = it.value1.toLong() //0:不弹信息卡,1:弹信息卡 val isPopCms = it.value2.toLong() if (SHOW_EMS_POP != isPopCms || isJumpToIm(skipTime)) { // 请求接口获取咨询助理的uid getImJavaApi().getConsultAssistantUidRequest(location, ffrom2) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { uidBean -> /* * location=1首页,3问答列表页,4我的入口,5亲子在线咨询入口,6咨询列表页导医入口, * 7使用心理课进入,8使用心理课列表页进入,9测评解读页进入,10搜索页进入,11注册引导页 * 0小壹点击前往 * */ if (uidBean.code == "200" && uidBean.data != 0.toLong()) { startChat(context as AppCompatActivity, uidBean.data.toString(), 0) } else { ToastUtil.toastShort("咨询助理忙碌中,请稍后再试") } } } else { //没有时间限制,跳转到前置信息收集 CmsExamQuestionPaperActivity.start(context, location, ffrom2) } } } /*** * 判断今天是否展示过 * */ private fun isJumpToIm(skip_time: Long): Boolean { val time = System.currentTimeMillis() val skipTime = SharedPreferencesEditor.getString("skip_time_") if (skipTime == null || skipTime.isEmpty()) { return false } val timeDifference = (time - skipTime.toLong()) / 1000 return timeDifference < skip_time } /** * 私聊列表进入,后置数据请求 * * @param context * @param chatItemBean */ @SuppressLint("CheckResult") fun startChat(context: AppCompatActivity?, chatItemBean: ChatItemBean) { SessionHelper.startP2PSession( context, chatItemBean.utype, chatItemBean.toUid.toString(), null, P2PCustomActionHandlerImpl(chatItemBean) ) } /** * 直接和对方聊天,不判断是否有代运营 * @param context * @param chatItemBean */ @SuppressLint("CheckResult") fun startChatBySessionId(context: AppCompatActivity?, sessionId: String) { context?.let { prepareChatData(it, sessionId, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { startChatSession(sessionId, expertInfo, 0, context) } }) } } /** * 非私聊列表进入,前置数据请求 * */ @SuppressLint("CheckResult") fun startCms(context: AppCompatActivity, toUid: String, isFromQingShu: Int) { if (!isLogin(context, true)) { return } if (loadingDialog == null) { loadingDialog = newInstance(null) } if (context.supportFragmentManager != null && !context.isDestroyed) { loadingDialog?.show(context.supportFragmentManager, null) } ImRetrofitApi.Companion.getImRetrofitApi() .getSystemConfigByKeyword("lx_collect_card_config") .compose(RxUtils.resultJavaData()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { //请求接口获取 前置信息收集间隔时间 val skipTime = it.value1.toLong() //0:不弹信息卡,1:弹信息卡 val isPopCms = it.value2.toLong() if (SHOW_EMS_POP != isPopCms || isJumpToIm(skipTime)) { //时间内已收集过信息,直接跳转到聊天页 startChat(context, toUid, isFromQingShu) } else { getImJavaApi().getUserType(toUid) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ res: BaseResponse<UserTypeBean> -> if (res.code == 200 && res.data != null) { ChatStatusCacheHelper.setStatusCache("chatEvent", res.data!!.chatEvent) if (TextUtils.equals(res.data!!.userType, USER_TYPE_EXPERT.toString()) ) { //专家 //在uid用户类型确定为专家的情况下,根据uid调用接口判断是进入专家私聊还是助理私聊 getImJavaApi().getChatUid(toUid) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ resp: BaseAPIResponse<DoctorAssistantRespDtoBean> -> val bean = resp.data val toUid = bean.chatUid prepareChatData(context, toUid, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { if (resp.data != null && resp.data.role == 2) { //2 代运营 CmsExamQuestionPaperActivity.start(context, toUid, expertInfo, 0) } else { startChatSession(toUid, expertInfo, isFromQingShu, context) } } }) }) { t: Throwable? -> handleError(context, t!!) } } else { prepareAssistantChatData( context, toUid, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { startChatSession(toUid, expertInfo, isFromQingShu, context) } }) } } else { if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } ToastUtil.toastShort(res.msg) } }, { throwable: Throwable? -> if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } handleError(context, throwable!!) }) } } } /** * 非私聊列表进入,前置数据请求 * * @param context * @param toUid * @param isFromQingShu 用于判断是否从倾诉流程跳转私聊:1:是 其他:不是 从倾述流程跳转私聊,需要发送自定义消息 */ @SuppressLint("CheckResult") fun startChat(context: AppCompatActivity, toUid: String, isFromQingShu: Int) { if (!isLogin(context, true)) { return } if (loadingDialog == null) { loadingDialog = newInstance(null) } if (context.supportFragmentManager != null && !context.isDestroyed) { loadingDialog?.show(context.supportFragmentManager, null) } getImJavaApi().getUserType(toUid) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ res: BaseResponse<UserTypeBean> -> if (res.code == 200 && res.data != null) { ChatStatusCacheHelper.setStatusCache("chatEvent", res.data!!.chatEvent) if (TextUtils.equals(res.data!!.userType, USER_TYPE_EXPERT.toString())) { //专家 //在uid用户类型确定为专家的情况下,根据uid调用接口判断是进入专家私聊还是助理私聊 getImJavaApi().getChatUid(toUid) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ resp: BaseAPIResponse<DoctorAssistantRespDtoBean> -> val bean = resp.data val toUid = bean.chatUid prepareChatData(context, toUid, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { startChatSession(toUid, expertInfo, isFromQingShu, context) } }) }) { t: Throwable? -> handleError(context, t!!) } } else { prepareAssistantChatData(context, toUid, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { startChatSession(toUid, expertInfo, isFromQingShu, context) } }) } } else { if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } ToastUtil.toastShort(res.msg) } }, { throwable: Throwable? -> if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } handleError(context, throwable!!) } ) } fun startChatCloseReplaceChat(context: AppCompatActivity, toUid: String) { if (!isLogin(context, true)) { return } if (loadingDialog == null) { loadingDialog = newInstance(null) } if (context.supportFragmentManager != null && !context.isDestroyed) { loadingDialog?.show(context.supportFragmentManager, null) } prepareChatData(context, toUid, object : ChatDataRequestListener { override fun onSuccess(expertInfo: IMExpertBuild) { startChatSession(toUid, expertInfo, 0, context) } }) } /** * 开启聊天会话 */ private fun startChatSession( toUid: String, expertInfo: IMExpertBuild, isFromQingShu: Int, context: AppCompatActivity ) { AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.YUNXIN, "startChatSession 开启聊天会话") val p2PCustomActionHandlerImpl = P2PCustomActionHandlerImpl(toUid, expertInfo) p2PCustomActionHandlerImpl.isFromQingShu = isFromQingShu SessionHelper.startP2PSession( context, expertInfo.shareData.user_type, toUid, null, p2PCustomActionHandlerImpl ) } /** * 信息收集前置页调用方法 * */ open fun startChatSessionByCms( toUid: String, expertInfo: IMExpertBuild, isFromQingShu: Int, context: AppCompatActivity ) { startChatSession(toUid, expertInfo, isFromQingShu, context) } //====================准备私聊数据==================== /** * 初始化聊天数据 */ fun prepareChatData( context: AppCompatActivity, toUid: String, listener: ChatDataRequestListener ) { if (!isLogin(context, true)) { return } val dis = getImJavaApi().getUserType(toUid) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ res: BaseResponse<UserTypeBean> -> if (res.code == 200 && res.data != null) { ChatStatusCacheHelper.setStatusCache("chatEvent", res.data!!.chatEvent) if (TextUtils.equals(res.data!!.userType, "2")) { //接口返回值是专家,java接口 prepareExpertChatData(context, toUid, listener) } else { //非专家 php接口 prepareAssistantChatData(context, toUid, listener) } } else { if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } ToastUtil.toastShort(res.msg) } }, { throwable: Throwable? -> if (loadingDialog != null && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } handleError(context, throwable!!) } ) } /** * 专家私聊数据请求 */ fun prepareExpertChatData( context: AppCompatActivity, toUid: String?, listener: ChatDataRequestListener ) { val disposable = getImJavaApi().getPersonalChat(toUid!!) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ resp: BaseResponse<IMExpertBuild> -> if (null != loadingDialog && loadingDialog?.isVisible!!) { loadingDialog?.dismissAllowingStateLoss() } if (resp.code == 200) { val expert = resp.data UserInfoCache.getInstance().saveYDLUser( expert.shareData.toUid, expert.shareData.doctorName, expert.shareData.cover ) listener.onSuccess(expert) doctorId = expert.shareData.doctorId } else { upLoadLog("consult/get-expert", resp.code, resp.msg) if (resp.code == ImConstants.HTTP_CODE_UNLOGIN) { ImIn.loginByOneKeyLogin(context, true) ToastUtil.toastShort(resp.msg) } else if (resp.code == ImConstants.SILENCED_CODE) { //禁言 showSilencedDialog(context, resp.data.tips, resp.data.url) } else { ToastUtil.toastShort(resp.msg) } } } ) { throwable: Throwable -> if (null != loadingDialog && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } handleError(context, throwable) if (throwable is HttpException) { upLoadLog("consult/get-expert", throwable.code(), throwable.message!!) } } } /** * 助理私聊数据请求 */ fun prepareAssistantChatData( context: AppCompatActivity, toUid: String, listener: ChatDataRequestListener ) { val cmd = GetExpert(toUid.toInt(), 0) val disposable = getImRetrofitApi().getExpert(NetworkParamsUtils.getMaps(cmd)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ resp: BaseResponse<IMExpertBuild> -> if (null != loadingDialog && loadingDialog!!.isVisible) { loadingDialog?.dismissAllowingStateLoss() } if (resp.code == 0) { val expert = resp.data UserInfoCache.getInstance().saveYDLUser( expert.shareData.toUid, expert.shareData.doctorName, expert.shareData.cover ) listener.onSuccess(expert) } else { upLoadLog("consult/get-expert", resp.code, resp.msg) if (resp.code == ImConstants.HTTP_CODE_UNLOGIN) { ImIn.loginByOneKeyLogin(context, true) ToastUtil.toastShort(resp.msg) } else if (resp.code == ImConstants.SILENCED_CODE) { //禁言 showSilencedDialog(context, resp.data.tips, resp.data.url) } else { ToastUtil.toastShort(resp.msg) } } } ) { throwable: Throwable -> if (null != loadingDialog && loadingDialog?.isVisible!!) { loadingDialog?.dismissAllowingStateLoss() } handleError(context, throwable) if (throwable is HttpException) { upLoadLog("consult/get-expert", throwable.code(), throwable.message!!) } } } //====================私聊页面 初始化操作==================== /** * 初始化在线状态接口 * * 只有专家显示在线、离线标识,其他用户Type隐藏在线、离线标识 */ fun initChatOnlineState( tb: TitleBarBottom, context: Context, toUid: String, messageFragment: YDLMessageFragment ) { val actionHandler = ActionHandlerStorage.getL(toUid) //获取私聊对方在线状态 if (null != actionHandler) { val docInfo = actionHandler.info docInfo.doctorBriefInfoFeedbackRate if (null != docInfo && (ImConstants.KEFUXIAOYI == docInfo.toUid || "4108805" == docInfo.toUid)) { //小壹客服 不显示是否在线 tb.setmMinTitleVisiable(View.GONE) } else { //对方是用户,自己是助理 if (actionHandler.userType == USER_TYPE_USER && ModularServiceManager.provide( IUserService::class.java ) .getUserInfo()?.user_type == USER_TYPE_ASSISTANT ) { tb.setTitleTextRightIcon(R.drawable.user_info_icon) { messageFragment.showUserInfoDialog() } } if (actionHandler.userType == USER_TYPE_EXPERT) { // 专家 tb.setmMinTitleVisiable(View.VISIBLE) // 调取接口获取专家状态 val dis = instance .getDoctorChatStatus(actionHandler.info.toUid.toLong()) .compose(applySchedulers()) .subscribe( { chatStatusBean: BaseAPIResponse<ChatStatusBean> -> if (actionHandler != null) { val status = chatStatusBean.data.status actionHandler.setDoctorStatus(status) actionHandler.setDoctorBusyNum(chatStatusBean.data.busyTotal) //1.在线,2.离线,3.忙碌 4咨询中, 5倾述中 6咨询前准备 if (status == 2) { //离线 tb.setMinTitleText("离线") tb.setMinTitleColor( ContextCompat.getColor( context, R.color.platform_color_666666 ) ) tb.setMinTitleDrawable( ContextCompat.getDrawable( context, R.drawable.im_background_chat_top_status_off_line ) ) } else if (status == 4 || status == 5) { //服务中 tb.setMinTitleText("服务中") tb.setMinTitleColor( ContextCompat.getColor( context, R.color.platform_color_666666 ) ) tb.setMinTitleDrawable( ContextCompat.getDrawable( context, R.drawable.im_background_chat_top_status_online_server ) ) } else { //在线 1,3,6.. tb.setMinTitleText("在线") tb.setMinTitleColor( ContextCompat.getColor( context, R.color.platform_color_666666 ) ) tb.setMinTitleDrawable( ContextCompat.getDrawable( context, R.drawable.im_background_chat_top_status_online ) ) } initSystemMessage( chatStatusBean.data.promptRule, status, toUid, actionHandler ) } } ) { throwable: Throwable -> LogUtil.i("getDoctorChatStatus throwable:$throwable") } } else if (actionHandler.userType == USER_TYPE_ASSISTANT) { // 助理 tb.setmMinTitleVisiable(View.GONE) // 调取接口获取助理状态 instance.getAssistantChatStatus( actionHandler.info.toUid.toLong() ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ res: BaseAPIResponse<Int> -> if (actionHandler != null) { if (res.data == 1) { //在线 /*tb.setMinTitleText("在线") tb.setMinTitleColor(context.resources.getColor(R.color.platform_color_666666)) tb.setMinTitleDrawable(context.resources.getDrawable(R.drawable.im_background_chat_top_status_online))*/ } else { //离线 /* tb.setMinTitleText("离线") tb.setMinTitleColor(context.resources.getColor(R.color.platform_color_666666)) tb.setMinTitleDrawable(context.resources.getDrawable(R.drawable.im_background_chat_top_status_off_line))*/ } } } ) { throwable: Throwable? -> } } else { tb.setmMinTitleVisiable(View.GONE) } } } } // promptRule 判断是否推荐专家 4,5直接不走文本提示和推荐逻辑,1,3不走推荐逻辑 //初始化 根据专家在线状态来发送提示消息或者推荐消息 private fun initSystemMessage( promptRule: Int, status: Int, toUid: String, actionHandler: IP2PCustomActionHandler ) { if (!(promptRule == 4 || promptRule == 5)) { val showExpertList = !(promptRule == 1 || promptRule == 3) if (actionHandler.userType == USER_TYPE_EXPERT && status == 2) { //当该专家离线时 // sendRecommendExpertListMessage(1, showExpertList, toUid, actionHandler) } else if (actionHandler.userType == USER_TYPE_EXPERT && status >= 3) { //当该专家忙碌时 // sendRecommendExpertListMessage(2, showExpertList, toUid, actionHandler) } } } /** * 发送推荐专家列表 */ @SuppressLint("CheckResult") fun sendRecommendExpertListMessage( type: Int, showExpertList: Boolean, toUid: String, actionHandler: IP2PCustomActionHandler ) { // 调取接口获取推荐专家列表 instance.getRecommendExpertList( actionHandler.info.toUid.toLong(), URLEncoder.encode(actionHandler.info.tag1), 3 ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ res: BaseAPIResponse<ArrayList<RecommendExpertBean>> -> //发送推荐专家列表消息 actionHandler.sendRecommendExpertListMessage(toUid, res.data, type, showExpertList) }, { throwable: Throwable -> ToastUtil.toastShort(throwable.toString()) }) } //====================展示提示==================== fun showSilencedDialog(context: Context, tips: String?, url: String?) { CommonDialog.create(context) .setMessage(tips) .setCancelAble(false) .setLeftOnclick( context.getString(R.string.im_details) ) { val realUrl = if (TextUtils.isEmpty(url)) ImConstants.HELP_URL else url!! val params = H5Params(realUrl, "") NewH5Activity.start(context, params) } .setRightClick(context.getString(R.string.im_approval), null) .show() } }