feat(chat): 优化群聊功能和界面组件

- 添加群成员头像基地址配置和统一管理
- 重构群成员列表布局和样式调整
- 添加群成员加入提示消息监听和处理机制
- 优化群聊头像加载和默认图标显示
- 重构群聊页面导航和界面元素
- 添加急救订单选择对话框功能
- 优化通话和定位分享功能实现
- 新增文件基地址辅助类和接口定义
- 重构群聊输入组件和布局配置
This commit is contained in:
2026-07-21 18:49:19 +08:00
parent aee280cf86
commit c504f23052
7 changed files with 242 additions and 16 deletions
@@ -28,7 +28,9 @@ import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tencent.qcloud.tuicore.TUICore import com.tencent.qcloud.tuicore.TUICore
import com.tencent.qcloud.tuikit.tuichat.TUIChatService import com.tencent.qcloud.tuikit.tuichat.TUIChatService
import com.tencent.qcloud.tuikit.tuichat.classicui.event.IMChatEvent import com.tencent.qcloud.tuikit.tuichat.classicui.event.IMChatEvent
import com.tencent.qcloud.tuikit.tuichat.interfaces.FileBaseUrlListener
import com.tencent.qcloud.tuikit.tuichat.interfaces.ShareToWeChatListener import com.tencent.qcloud.tuikit.tuichat.interfaces.ShareToWeChatListener
import com.tencent.qcloud.tuikit.tuichat.presenter.FileBaseUrlHelper
import com.tencent.qcloud.tuikit.tuichat.presenter.WeChatShareHelper import com.tencent.qcloud.tuikit.tuichat.presenter.WeChatShareHelper
import com.xjjk.healthyclients.base.BaseVMBActivity import com.xjjk.healthyclients.base.BaseVMBActivity
import com.xjjk.healthyclients.bean.CardInfoBean import com.xjjk.healthyclients.bean.CardInfoBean
@@ -40,6 +42,7 @@ import com.xjjk.healthyclients.fragment.EmergencyFragment
import com.xjjk.healthyclients.fragment.GuidanceFragment import com.xjjk.healthyclients.fragment.GuidanceFragment
import com.xjjk.healthyclients.fragment.HomeFragment import com.xjjk.healthyclients.fragment.HomeFragment
import com.xjjk.healthyclients.fragment.MonitorFragment import com.xjjk.healthyclients.fragment.MonitorFragment
import com.xjjk.healthyclients.retrofit.UrlConfig
import com.xjjk.healthyclients.superfuntion.loginIm import com.xjjk.healthyclients.superfuntion.loginIm
import com.xjjk.healthyclients.superfuntion.startAllDoctorActivity import com.xjjk.healthyclients.superfuntion.startAllDoctorActivity
import com.xjjk.healthyclients.superfuntion.startLoginActivity import com.xjjk.healthyclients.superfuntion.startLoginActivity
@@ -97,10 +100,13 @@ class MainActivity : BaseVMBActivity<MainViewModel, ActivityMainBinding>(R.layou
api?.sendReq(req) api?.sendReq(req)
} }
private val fileBaseUrlListener = FileBaseUrlListener { UrlConfig.IMAGE_BASE_URL }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
regToWx() regToWx()
WeChatShareHelper.getInstance().setListener(shareToWeChatListener) WeChatShareHelper.getInstance().setListener(shareToWeChatListener)
FileBaseUrlHelper.getInstance().setListener(fileBaseUrlListener)
} }
private fun regToWx() { private fun regToWx() {
@@ -1,6 +1,7 @@
package com.xjjk.healthyclients.fragment package com.xjjk.healthyclients.fragment
import android.Manifest import android.Manifest
import android.app.Dialog
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color import android.graphics.Color
@@ -9,7 +10,9 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import android.view.Gravity
import android.view.View import android.view.View
import android.view.WindowManager
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.util.Consumer import androidx.core.util.Consumer
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@@ -40,9 +43,12 @@ import com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper
import com.xjjk.healthyclients.R import com.xjjk.healthyclients.R
import com.xjjk.healthyclients.base.BaseVMBFragment import com.xjjk.healthyclients.base.BaseVMBFragment
import com.xjjk.healthyclients.bean.emergency.EmergencyDictBean import com.xjjk.healthyclients.bean.emergency.EmergencyDictBean
import com.xjjk.healthyclients.bean.emergency.GroupInfo
import com.xjjk.healthyclients.bean.emergency.LocationResourceBean import com.xjjk.healthyclients.bean.emergency.LocationResourceBean
import com.xjjk.healthyclients.data.repository.EmergencyRepository import com.xjjk.healthyclients.data.repository.EmergencyRepository
import com.xjjk.healthyclients.databinding.DialogGroupInfoListBinding
import com.xjjk.healthyclients.databinding.FragmentEmergencyBinding import com.xjjk.healthyclients.databinding.FragmentEmergencyBinding
import com.xjjk.healthyclients.fragment.adapter.GroupInfoAdapter
import com.xjjk.healthyclients.superfuntion.getMarkerInfo import com.xjjk.healthyclients.superfuntion.getMarkerInfo
import com.xjjk.healthyclients.superfuntion.startGroupChat import com.xjjk.healthyclients.superfuntion.startGroupChat
import com.xjjk.healthyclients.ui.viewmodel.EmergencyViewModel import com.xjjk.healthyclients.ui.viewmodel.EmergencyViewModel
@@ -50,6 +56,8 @@ import com.xjjk.healthyclients.utils.IMInputActionSettingUtils
import com.xjjk.healthyclients.utils.MapUtils import com.xjjk.healthyclients.utils.MapUtils
import com.xjjk.healthyclients.utils.SystemFuntion.goNavigation import com.xjjk.healthyclients.utils.SystemFuntion.goNavigation
import com.xjjk.healthyclients.utils.TUIUtils import com.xjjk.healthyclients.utils.TUIUtils
import androidx.recyclerview.widget.LinearLayoutManager
import com.tencent.qcloud.tuicore.util.ToastUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@@ -197,9 +205,9 @@ class EmergencyFragment :
ParamedicOperateHelper.getInstance().setListener(paramedicOperateListener) ParamedicOperateHelper.getInstance().setListener(paramedicOperateListener)
mViewModel.isLiaisonUser { result -> mViewModel.isLiaisonUser { result ->
/*if (!result) { if (result) {
mBinding.fragmentEmergencyParamedic.visibility = View.GONE mBinding.fragmentEmergencyParamedic.visibility = View.GONE
}*/ }
} }
} }
@@ -403,20 +411,37 @@ class EmergencyFragment :
} }
R.id.fragment_emergency_paramedic -> { R.id.fragment_emergency_paramedic -> {
mViewModel.getParamedicGroupInfo( mViewModel.getParticipatedOrders { result ->
getString(R.string.title_paramedic_group), if (result.records.isNullOrEmpty()) {
mCurrentLon, ToastUtil.toastLongMessage("暂无参与的应急就医工单")
mCurrentLat, } else if(result.records.size == 1){
successCall = { showChatListDialog(result.records,onChatSelected = {groupInfo ->
IMInputActionSettingUtils.createEmergencySetting() mViewModel.getActualGroupMemberList(groupInfo.sessionId, successCall = {groupMemberBeans->
activity?.startGroupChat( IMInputActionSettingUtils.createEmergencySetting()
it.groupId, activity?.startGroupChat(
getString(R.string.title_paramedic_group), groupInfo.sessionId,
false, getString(R.string.title_paramedic_group),
it.member, false,
workBean = WorkBean(it.id, TUIUtils.WORK_TYPE_EMERGENCY) groupMemberBeans.map { it1 -> it1.userId }.toList() as ArrayList<String>?,
) workBean = WorkBean(groupInfo.orderId, TUIUtils.WORK_TYPE_EMERGENCY)
}) )
})
})
}else{
showChatListDialog(result.records,onChatSelected = {groupInfo ->
mViewModel.getActualGroupMemberList(groupInfo.sessionId, successCall = {groupMemberBeans->
IMInputActionSettingUtils.createEmergencySetting()
activity?.startGroupChat(
groupInfo.sessionId,
getString(R.string.title_paramedic_group),
false,
groupMemberBeans.map { it1 -> it1.userId }.toList() as ArrayList<String>?,
workBean = WorkBean(groupInfo.orderId, TUIUtils.WORK_TYPE_EMERGENCY)
)
})
})
}
}
} }
R.id.fragment_emergency_marker_info -> { R.id.fragment_emergency_marker_info -> {
@@ -452,6 +477,41 @@ class EmergencyFragment :
} }
} }
/**
* 展示急救订单列表Dialog,供用户选择历史订单继续聊天
*/
private fun showChatListDialog(
records: List<GroupInfo>,
onChatSelected: (GroupInfo) -> Unit
) {
context?.let { ctx ->
val dialog = Dialog(ctx, com.xjjk.healthyclients.R.style.DialogTheme)
val binding = DialogGroupInfoListBinding.inflate(layoutInflater)
binding.rvGroupList.layoutManager = LinearLayoutManager(ctx)
binding.rvGroupList.adapter = GroupInfoAdapter(records) { groupInfo ->
onChatSelected(groupInfo)
dialog.dismiss()
}
binding.tvCancel.setOnClickListener { dialog.dismiss() }
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.setCancelable(true)
dialog.window?.let { window ->
window.setGravity(Gravity.BOTTOM)
window.setWindowAnimations(com.xjjk.healthyclients.R.style.main_menu_animStyle)
window.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
}
dialog.show()
}
}
fun setMarker(markerList: MutableList<LocationResourceBean>) { fun setMarker(markerList: MutableList<LocationResourceBean>) {
mAMap?.clear() //清除点位 mAMap?.clear() //清除点位
if (markerList.isNullOrEmpty()) { if (markerList.isNullOrEmpty()) {
@@ -0,0 +1,45 @@
package com.xjjk.healthyclients.fragment.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.xjjk.healthyclients.bean.emergency.GroupInfo
import com.xjjk.healthyclients.databinding.ItemGroupInfoBinding
/**
* 急救订单列表适配器
*/
class GroupInfoAdapter(
private val items: List<GroupInfo>,
private val onItemClick: (GroupInfo) -> Unit
) : RecyclerView.Adapter<GroupInfoAdapter.ViewHolder>() {
inner class ViewHolder(private val binding: ItemGroupInfoBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(groupInfo: GroupInfo) {
binding.tvUserName.text = groupInfo.salvageUserName
val sex = when (groupInfo.salvageUserSex) {
"1" -> ""
"2" -> ""
else -> "--"
}
binding.tvUserSex.text = sex
binding.tvOrgName.text = groupInfo.orgName
binding.root.setOnClickListener { onItemClick(groupInfo) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemGroupInfoBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int = items.size
}
@@ -5,7 +5,9 @@ import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean
import com.xjjk.healthyclients.base.viewmodel.BaseViewModel import com.xjjk.healthyclients.base.viewmodel.BaseViewModel
import com.xjjk.healthyclients.bean.emergency.EmergencyGroupInfo import com.xjjk.healthyclients.bean.emergency.EmergencyGroupInfo
import com.xjjk.healthyclients.bean.emergency.GroupInfo
import com.xjjk.healthyclients.bean.emergency.LocationResourceBean import com.xjjk.healthyclients.bean.emergency.LocationResourceBean
import com.xjjk.healthyclients.data.bean.PageBean
import com.xjjk.healthyclients.data.repository.EmergencyRepository import com.xjjk.healthyclients.data.repository.EmergencyRepository
import com.xjjk.healthyclients.superfuntion.handleRequest import com.xjjk.healthyclients.superfuntion.handleRequest
import com.xjjk.healthyclients.superfuntion.launch import com.xjjk.healthyclients.superfuntion.launch
@@ -59,6 +61,21 @@ class EmergencyViewModel : BaseViewModel() {
) )
} }
fun getParticipatedOrders(successCall: (PageBean<GroupInfo>) -> Unit = {}){
launch(
{
handleRequest(
EmergencyRepository.getParticipatedOrders(),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
}
)
}
fun getEmergencyCall( fun getEmergencyCall(
callType: String, callType: String,
resourceId: String, resourceId: String,
@@ -11,6 +11,8 @@ object ConstantUtils {
var mCurrentLon = 87.627704 var mCurrentLon = 87.627704
var mNutritionMonitor = false var mNutritionMonitor = false
var mIsCloseDialog = false var mIsCloseDialog = false
val APP_ID: String = "wxb33cd60beda0a212"
var mPrivacy = "本平台由西安联链科技有限公司开发和运维,平台深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。同时,我们承诺将采取相应的安全保护措施来保护您的个人信息。请在使用平台服务前,仔细阅读并了解本隐私权政策,我们将按照本政策收集、处理及披露您的信息。\n" + var mPrivacy = "本平台由西安联链科技有限公司开发和运维,平台深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。同时,我们承诺将采取相应的安全保护措施来保护您的个人信息。请在使用平台服务前,仔细阅读并了解本隐私权政策,我们将按照本政策收集、处理及披露您的信息。\n" +
"本政策将帮助您了解以下内容:\n" + "本政策将帮助您了解以下内容:\n" +
"1、定义\n" + "1、定义\n" +
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/rectangle_top_round_corner20_white">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dp_20"
android:text="请选择应急就医对话"
android:textColor="@color/text_black_33"
android:textSize="@dimen/txt16"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_group_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_18"
android:maxHeight="@dimen/dp_300"
tools:listitem="@layout/item_group_info" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0_5"
android:background="@color/theme_color" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingVertical="@dimen/dp_20"
android:text="取消"
android:textColor="@color/text_black_66"
android:textSize="@dimen/txt14"
android:background="?attr/selectableItemBackground" />
</LinearLayout>
</layout>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/dp_16"
android:paddingVertical="@dimen/dp_16"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground">
<TextView
android:id="@+id/tv_user_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:textColor="@color/text_black_33"
android:textSize="@dimen/txt14"
android:ellipsize="end"
android:maxLines="1"
tools:text="张三" />
<TextView
android:id="@+id/tv_user_sex"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:layout_marginHorizontal="@dimen/dp_12"
android:textColor="@color/text_black_66"
android:textSize="@dimen/txt13"
tools:text="男" />
<TextView
android:id="@+id/tv_org_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:textColor="@color/text_black_99"
android:textSize="@dimen/txt13"
android:maxLines="1"
android:ellipsize="end"
tools:text="某某科技有限公司" />
</LinearLayout>
</layout>