feat(chat): 添加群组管理功能和微信分享支持

- 新增 EmployeeBean、ExpertBean 和 GroupMemberBean 数据模型
- 实现群组成员管理接口和操作辅助类
- 添加微信 SDK 依赖并集成位置信息分享功能
- 在聊天界面中实现群成员列表显示和动态更新
- 增加急救员群组创建和管理的相关 API 接口
- 实现群组成员搜索、添加和移除功能
- 添加位置消息长按分享到微信的功能
This commit is contained in:
2026-07-16 18:47:03 +08:00
parent 7cca7e0b79
commit 14f7542037
6 changed files with 318 additions and 3 deletions
+1 -1
View File
@@ -137,5 +137,5 @@ dependencies {
//JSoup
api 'org.jsoup:jsoup:1.12.1'
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+'
}
@@ -6,6 +6,7 @@ import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import android.view.Gravity
import android.view.KeyEvent
import android.view.View
@@ -19,9 +20,16 @@ import com.permissionx.guolindev.PermissionX
import com.sw.healthyclients.data.local.DataStoreManager
import com.sw.healthyclients.utils.CustomActivityManager
import com.sw.healthyclients.view.CustomToast
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tencent.qcloud.tuicore.TUICore
import com.tencent.qcloud.tuikit.tuichat.TUIChatService
import com.tencent.qcloud.tuikit.tuichat.classicui.event.IMChatEvent
import com.tencent.qcloud.tuikit.tuichat.interfaces.ShareToWeChatListener
import com.tencent.qcloud.tuikit.tuichat.presenter.WeChatShareHelper
import com.xjjk.healthyclients.base.BaseVMBActivity
import com.xjjk.healthyclients.bean.CardInfoBean
import com.xjjk.healthyclients.bottomtab.HomeBottomTabLayout
@@ -68,6 +76,39 @@ class MainActivity : BaseVMBActivity<MainViewModel, ActivityMainBinding>(R.layou
Manifest.permission.POST_NOTIFICATIONS
)
val APP_ID: String = "wxb33cd60beda0a212"
private var api: IWXAPI? = null
private val shareToWeChatListener = ShareToWeChatListener { lat, lon, desc ->
val url = ("https://ditu.amap.com/regeo?lng=" + lon
+ "&lat=" + lat + "&name=" + desc + "&src=uriapi&innersrc=uriapi")
Log.i("TAGG", url)
val webpage = WXWebpageObject()
webpage.webpageUrl = url
val msg = WXMediaMessage(webpage)
msg.title = desc
msg.description = desc
val req = SendMessageToWX.Req()
req.transaction = System.currentTimeMillis().toString()
req.message = msg
req.scene = SendMessageToWX.Req.WXSceneSession
api?.sendReq(req)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
regToWx()
WeChatShareHelper.getInstance().setListener(shareToWeChatListener)
}
private fun regToWx() {
// 通过 WXAPIFactory 工厂,获取 IWXAPI 的实例
api = WXAPIFactory.createWXAPI(this, APP_ID, false);
// 将应用的 appId 注册到微信
api?.registerApp(APP_ID);
}
override fun initView(savedInstanceState: Bundle?) {
UpdateBuilder.create().check()// 启动更新任务
@@ -81,9 +122,9 @@ class MainActivity : BaseVMBActivity<MainViewModel, ActivityMainBinding>(R.layou
// main_tab_layout.setUnreadTip(TAG_INDEX, "99+")
// main_tab_layout.setUnreadTip(TAG_COLLECT, null, false)
}
}
override fun initData() {
// if(DataStoreManager.isLogin()){
// getAppViewModel().getIMSig(successCall = {
@@ -1,5 +1,8 @@
package com.xjjk.healthyclients.data.api
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean
import com.xjjk.healthyclients.bean.emergency.BigDiseaseBean
import com.xjjk.healthyclients.bean.emergency.BigDiseaseDetailsBean
import com.xjjk.healthyclients.bean.emergency.EmergencyGroupInfo
@@ -83,6 +86,36 @@ interface EmergencyApi {
*/
@GET("/health-emergency/api/emergency/createGroupMag")
suspend fun getIMGroupInfo(@QueryMap params: MutableMap<String, Any?>): ApiResponse<EmergencyGroupInfo>
/**
* 获取急救员群组信息
*/
@GET("/health-emergency/api/emergency/createGroupMagFirstAider")
suspend fun getParamedicGroupInfo(@QueryMap params: MutableMap<String, Any?>): ApiResponse<EmergencyGroupInfo>
/**
* 搜索专家(专业人员)
*/
@GET("/health-emergency/api/emergency/order/searchExpert")
suspend fun searchExpert(@QueryMap params: MutableMap<String, Any?>): ApiResponse<List<ExpertBean>>
/**
* 搜索员工
*/
@GET("/health-emergency/api/emergency/order/searchEmployee")
suspend fun searchEmployee(@QueryMap params: MutableMap<String, Any?>): ApiResponse<List<EmployeeBean>>
/**
* 实际群成员列表
*/
@GET("/health-emergency/api/emergency/order/getActualGroupMemberList")
suspend fun getActualGroupMemberList(@QueryMap params: MutableMap<String, Any?>): ApiResponse<List<GroupMemberBean>>
/**
* 邀请进群
*/
@POST("/health-emergency/api/emergency/addGroupUser")
suspend fun addGroupUser(@Body requestBody: RequestBody): ApiResponse<Boolean>
/**
* 移除群成员
*/
@POST("/health-emergency/api/emergency/removeGroupUser")
suspend fun removeGroupUser(@Body requestBody: RequestBody): ApiResponse<Boolean>
/**
* 获取一人一案
*/
@@ -1,5 +1,8 @@
package com.xjjk.healthyclients.data.repository
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean
import com.xjjk.healthyclients.base.repository.BaseRepository
import com.xjjk.healthyclients.bean.CommonSettingMenuBean
import com.xjjk.healthyclients.bean.emergency.AddBigDiseaseSubmitBean
@@ -117,6 +120,59 @@ object EmergencyRepository : BaseRepository() {
return apiCall { service.getIMGroupInfo(map) }
}
suspend fun getParamedicGroupInfo(groupName: String, longitude: Double,
latitude: Double): ApiResponse<EmergencyGroupInfo> {
var map = mutableMapOf<String, Any?>()
map["longitude"] = longitude
map["latitude"] = latitude
map["name"] = groupName //群聊名称改为后台生成
return apiCall { service.getParamedicGroupInfo(map) }
}
suspend fun searchExpert(realname: String, centerId: String, excludeSessionId: String, pageNo: Int, pageSize: Int): ApiResponse<List<ExpertBean>> {
val map = mutableMapOf<String, Any?>()
map["realname"] = realname
map["centerId"] = centerId
map["excludeSessionId"] = excludeSessionId
map["pageNo"] = pageNo
map["pageSize"] = pageSize
return apiCall { service.searchExpert(map) }
}
suspend fun searchEmployee(realname: String, orgCode: String, workNo: String, phone: String, excludeSessionId: String, pageNo: Int, pageSize: Int): ApiResponse<List<EmployeeBean>> {
val map = mutableMapOf<String, Any?>()
map["realname"] = realname
map["orgCode"] = orgCode
map["workNo"] = workNo
map["phone"] = phone
map["excludeSessionId"] = excludeSessionId
map["pageNo"] = pageNo
map["pageSize"] = pageSize
return apiCall { service.searchEmployee(map) }
}
suspend fun getActualGroupMemberList(sessionId: String): ApiResponse<List<GroupMemberBean>> {
val map = mutableMapOf<String, Any?>()
map["sessionId"] = sessionId
return apiCall { service.getActualGroupMemberList(map) }
}
suspend fun addGroupUser(groupId: String, memberList: List<String>,
memberType: Int): ApiResponse<Boolean> {
val map = mutableMapOf<String, Any?>()
map["groupId"] = groupId
map["memberList"] = memberList
map["memberType"] = memberType
return apiCall { service.addGroupUser(map.toJson().toRequestBody()) }
}
suspend fun removeGroupUser(groupId: String, memberList: List<String>): ApiResponse<Boolean> {
val map = mutableMapOf<String, Any?>()
map["groupId"] = groupId
map["memberList"] = memberList
return apiCall { service.removeGroupUser(map.toJson().toRequestBody()) }
}
suspend fun getProposalInfo(): ApiResponse<ProposalBean> {
return apiCall { service.getProposalInfo() }
}
@@ -30,11 +30,17 @@ import com.amap.api.maps.model.Marker
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.permissionx.guolindev.PermissionX
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean
import com.tencent.qcloud.tuikit.tuichat.bean.WorkBean
import com.tencent.qcloud.tuikit.tuichat.classicui.interfaces.OnParamedicOperateListener
import com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper
import com.xjjk.healthyclients.R
import com.xjjk.healthyclients.base.BaseVMBFragment
import com.xjjk.healthyclients.bean.emergency.EmergencyDictBean
import com.xjjk.healthyclients.bean.emergency.LocationResourceBean
import com.xjjk.healthyclients.data.repository.EmergencyRepository
import com.xjjk.healthyclients.databinding.FragmentEmergencyBinding
import com.xjjk.healthyclients.superfuntion.getMarkerInfo
import com.xjjk.healthyclients.superfuntion.startGroupChat
@@ -43,8 +49,12 @@ import com.xjjk.healthyclients.utils.IMInputActionSettingUtils
import com.xjjk.healthyclients.utils.MapUtils
import com.xjjk.healthyclients.utils.SystemFuntion.goNavigation
import com.xjjk.healthyclients.utils.TUIUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeoutOrNull
/**
@@ -76,6 +86,93 @@ class EmergencyFragment :
)
var mListener: LocationSource.OnLocationChangedListener? = null
private val paramedicOperateListener = object : OnParamedicOperateListener {
override fun addGroupUser(groupId: String, memberList: List<String>, memberType: Int) {
mViewModel.addGroupUser(groupId, memberList, memberType)
}
override fun removeGroupUser(groupId: String, memberList: List<String>) {
mViewModel.removeGroupUser(groupId, memberList)
}
override fun searchEmployee(
realname: String?,
orgCode: String?,
workNo: String?,
phone: String?,
excludeSessionId: String?,
pageNo: Int,
pageSize: Int
): List<EmployeeBean?>? {
return runBlocking(Dispatchers.IO) {
try {
val deferred = async {
EmergencyRepository.searchEmployee(
realname ?: "",
orgCode ?: "",
workNo ?: "",
phone ?: "",
excludeSessionId ?: "",
pageNo,
pageSize
)
}
val response = withTimeoutOrNull(10000L) { deferred.await() }
?: return@runBlocking emptyList<EmployeeBean>()
response.takeIf { it.success }?.result ?: emptyList()
} catch (e: Exception) {
emptyList()
}
}
}
override fun searchExpert(
realname: String?,
centerId: String?,
excludeSessionId: String?,
pageNo: Int,
pageSize: Int
): List<ExpertBean?>? {
return runBlocking(Dispatchers.IO) {
try {
val deferred = async {
EmergencyRepository.searchExpert(
realname ?: "",
centerId ?: "",
excludeSessionId ?: "",
pageNo,
pageSize
)
}
val response = withTimeoutOrNull(10000L) { deferred.await() }
?: return@runBlocking emptyList<ExpertBean>()
response.takeIf { it.success }?.result ?: emptyList()
} catch (e: Exception) {
emptyList()
}
}
}
override fun getActualGroupMemberList(sessionId: String): List<GroupMemberBean?>? {
return runBlocking(Dispatchers.IO) {
try {
val deferred = async {
EmergencyRepository.getActualGroupMemberList(sessionId)
}
val response = withTimeoutOrNull(10000L) { deferred.await() }
?: return@runBlocking emptyList<GroupMemberBean>()
response.takeIf { it.success }?.result ?: emptyList()
} catch (e: Exception) {
emptyList()
}
}
}
}
override fun initView(root: View?, savedInstanceState: Bundle?) {
// fitTransparentStatusBar(mBinding.tvTitle)
MapsInitializer.updatePrivacyShow(context, true, true)
@@ -88,6 +185,8 @@ class EmergencyFragment :
PermissionX.init(this@EmergencyFragment)
.permissions(mPermissionList)
.request { allGranted, grantedList, deniedList -> setUpMap() }
ParamedicOperateHelper.getInstance().setListener(paramedicOperateListener)
}
override fun initData() {
@@ -288,7 +387,7 @@ class EmergencyFragment :
}
R.id.fragment_emergency_paramedic -> {
mViewModel.getIMGroupInfo(
mViewModel.getParamedicGroupInfo(
getString(R.string.title_paramedic_group),
mCurrentLon,
mCurrentLat,
@@ -1,5 +1,8 @@
package com.xjjk.healthyclients.ui.viewmodel
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean
import com.xjjk.healthyclients.base.viewmodel.BaseViewModel
import com.xjjk.healthyclients.bean.emergency.EmergencyGroupInfo
import com.xjjk.healthyclients.bean.emergency.LocationResourceBean
@@ -99,6 +102,89 @@ class EmergencyViewModel : BaseViewModel() {
})
})
}
fun getParamedicGroupInfo(
groupName: String, longitude: Double,
latitude: Double, successCall: (EmergencyGroupInfo) -> Unit = {}
) {
launch({
handleRequest(
EmergencyRepository.getParamedicGroupInfo(groupName, longitude, latitude),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
fun searchExpert(
realname: String, centerId: String, excludeSessionId: String, pageNo: Int, pageSize: Int, successCall: (List<ExpertBean>) -> Unit = {}
) {
launch({
handleRequest(
EmergencyRepository.searchExpert(realname, centerId, excludeSessionId, pageNo, pageSize),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
fun searchEmployee(
realname: String, orgCode: String, workNo: String, phone: String, excludeSessionId: String, pageNo: Int, pageSize: Int,
successCall: (List<EmployeeBean>) -> Unit = {}) {
launch({
handleRequest(
EmergencyRepository.searchEmployee(realname, orgCode, workNo, phone, excludeSessionId, pageNo, pageSize),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
fun getActualGroupMemberList(sessionId: String, successCall: (List<GroupMemberBean>) -> Unit = {}
) {
launch({
handleRequest(
EmergencyRepository.getActualGroupMemberList(sessionId),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
fun addGroupUser(groupId: String, memberList: List<String>,
memberType: Int, successCall: (Boolean) -> Unit = {}
) {
launch({
handleRequest(
EmergencyRepository.addGroupUser(groupId, memberList, memberType),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
fun removeGroupUser(groupId: String, memberList: List<String>, successCall: (Boolean) -> Unit = {}
) {
launch({
handleRequest(
EmergencyRepository.removeGroupUser(groupId, memberList),
successBlock = {
it.result?.let { it1 ->
successCall.invoke(it1)
}
})
})
}
//
// /**
// * 附近医疗点