From 14f7542037351851d425f39faf20a7c03b9bb18b Mon Sep 17 00:00:00 2001 From: zhangxiao <1441011491@qq.com> Date: Thu, 16 Jul 2026 18:47:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(chat):=20=E6=B7=BB=E5=8A=A0=E7=BE=A4?= =?UTF-8?q?=E7=BB=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=E5=92=8C=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=88=86=E4=BA=AB=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 EmployeeBean、ExpertBean 和 GroupMemberBean 数据模型 - 实现群组成员管理接口和操作辅助类 - 添加微信 SDK 依赖并集成位置信息分享功能 - 在聊天界面中实现群成员列表显示和动态更新 - 增加急救员群组创建和管理的相关 API 接口 - 实现群组成员搜索、添加和移除功能 - 添加位置消息长按分享到微信的功能 --- app/build.gradle | 2 +- .../com/xjjk/healthyclients/MainActivity.kt | 43 +++++++- .../healthyclients/data/api/EmergencyApi.kt | 33 ++++++ .../data/repository/EmergencyRepository.kt | 56 ++++++++++ .../fragment/EmergencyFragment.kt | 101 +++++++++++++++++- .../ui/viewmodel/EmergencyViewModel.kt | 86 +++++++++++++++ 6 files changed, 318 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2636182..c0db6a5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -137,5 +137,5 @@ dependencies { //JSoup api 'org.jsoup:jsoup:1.12.1' - + implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+' } \ No newline at end of file diff --git a/app/src/main/java/com/xjjk/healthyclients/MainActivity.kt b/app/src/main/java/com/xjjk/healthyclients/MainActivity.kt index 21b051d..a6037ab 100644 --- a/app/src/main/java/com/xjjk/healthyclients/MainActivity.kt +++ b/app/src/main/java/com/xjjk/healthyclients/MainActivity.kt @@ -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(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(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 = { diff --git a/app/src/main/java/com/xjjk/healthyclients/data/api/EmergencyApi.kt b/app/src/main/java/com/xjjk/healthyclients/data/api/EmergencyApi.kt index 845957e..998e70b 100644 --- a/app/src/main/java/com/xjjk/healthyclients/data/api/EmergencyApi.kt +++ b/app/src/main/java/com/xjjk/healthyclients/data/api/EmergencyApi.kt @@ -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): ApiResponse + /** + * 获取急救员群组信息 + */ + @GET("/health-emergency/api/emergency/createGroupMagFirstAider") + suspend fun getParamedicGroupInfo(@QueryMap params: MutableMap): ApiResponse + /** + * 搜索专家(专业人员) + */ + @GET("/health-emergency/api/emergency/order/searchExpert") + suspend fun searchExpert(@QueryMap params: MutableMap): ApiResponse> + /** + * 搜索员工 + */ + @GET("/health-emergency/api/emergency/order/searchEmployee") + suspend fun searchEmployee(@QueryMap params: MutableMap): ApiResponse> + /** + * 实际群成员列表 + */ + @GET("/health-emergency/api/emergency/order/getActualGroupMemberList") + suspend fun getActualGroupMemberList(@QueryMap params: MutableMap): ApiResponse> + /** + * 邀请进群 + */ + @POST("/health-emergency/api/emergency/addGroupUser") + suspend fun addGroupUser(@Body requestBody: RequestBody): ApiResponse + /** + * 移除群成员 + */ + @POST("/health-emergency/api/emergency/removeGroupUser") + suspend fun removeGroupUser(@Body requestBody: RequestBody): ApiResponse /** * 获取一人一案 */ diff --git a/app/src/main/java/com/xjjk/healthyclients/data/repository/EmergencyRepository.kt b/app/src/main/java/com/xjjk/healthyclients/data/repository/EmergencyRepository.kt index a67a569..d2c88e8 100644 --- a/app/src/main/java/com/xjjk/healthyclients/data/repository/EmergencyRepository.kt +++ b/app/src/main/java/com/xjjk/healthyclients/data/repository/EmergencyRepository.kt @@ -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 { + var map = mutableMapOf() + 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> { + val map = mutableMapOf() + 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> { + val map = mutableMapOf() + 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> { + val map = mutableMapOf() + map["sessionId"] = sessionId + return apiCall { service.getActualGroupMemberList(map) } + } + + suspend fun addGroupUser(groupId: String, memberList: List, + memberType: Int): ApiResponse { + val map = mutableMapOf() + map["groupId"] = groupId + map["memberList"] = memberList + map["memberType"] = memberType + return apiCall { service.addGroupUser(map.toJson().toRequestBody()) } + } + + suspend fun removeGroupUser(groupId: String, memberList: List): ApiResponse { + val map = mutableMapOf() + map["groupId"] = groupId + map["memberList"] = memberList + return apiCall { service.removeGroupUser(map.toJson().toRequestBody()) } + } + suspend fun getProposalInfo(): ApiResponse { return apiCall { service.getProposalInfo() } } diff --git a/app/src/main/java/com/xjjk/healthyclients/fragment/EmergencyFragment.kt b/app/src/main/java/com/xjjk/healthyclients/fragment/EmergencyFragment.kt index dfe9aa7..4bdc878 100644 --- a/app/src/main/java/com/xjjk/healthyclients/fragment/EmergencyFragment.kt +++ b/app/src/main/java/com/xjjk/healthyclients/fragment/EmergencyFragment.kt @@ -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, memberType: Int) { + mViewModel.addGroupUser(groupId, memberList, memberType) + } + + override fun removeGroupUser(groupId: String, memberList: List) { + mViewModel.removeGroupUser(groupId, memberList) + } + + override fun searchEmployee( + realname: String?, + orgCode: String?, + workNo: String?, + phone: String?, + excludeSessionId: String?, + pageNo: Int, + pageSize: Int + ): List? { + 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() + + response.takeIf { it.success }?.result ?: emptyList() + } catch (e: Exception) { + emptyList() + } + } + } + + override fun searchExpert( + realname: String?, + centerId: String?, + excludeSessionId: String?, + pageNo: Int, + pageSize: Int + ): List? { + return runBlocking(Dispatchers.IO) { + try { + val deferred = async { + EmergencyRepository.searchExpert( + realname ?: "", + centerId ?: "", + excludeSessionId ?: "", + pageNo, + pageSize + ) + } + val response = withTimeoutOrNull(10000L) { deferred.await() } + ?: return@runBlocking emptyList() + + response.takeIf { it.success }?.result ?: emptyList() + } catch (e: Exception) { + emptyList() + } + } + } + + override fun getActualGroupMemberList(sessionId: String): List? { + return runBlocking(Dispatchers.IO) { + try { + val deferred = async { + EmergencyRepository.getActualGroupMemberList(sessionId) + } + val response = withTimeoutOrNull(10000L) { deferred.await() } + ?: return@runBlocking emptyList() + + 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, diff --git a/app/src/main/java/com/xjjk/healthyclients/ui/viewmodel/EmergencyViewModel.kt b/app/src/main/java/com/xjjk/healthyclients/ui/viewmodel/EmergencyViewModel.kt index 855b26d..8b23d62 100644 --- a/app/src/main/java/com/xjjk/healthyclients/ui/viewmodel/EmergencyViewModel.kt +++ b/app/src/main/java/com/xjjk/healthyclients/ui/viewmodel/EmergencyViewModel.kt @@ -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) -> 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) -> 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) -> Unit = {} + ) { + launch({ + handleRequest( + EmergencyRepository.getActualGroupMemberList(sessionId), + successBlock = { + it.result?.let { it1 -> + successCall.invoke(it1) + } + }) + }) + } + + fun addGroupUser(groupId: String, memberList: List, + 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, successCall: (Boolean) -> Unit = {} + ) { + launch({ + handleRequest( + EmergencyRepository.removeGroupUser(groupId, memberList), + successBlock = { + it.result?.let { it1 -> + successCall.invoke(it1) + } + }) + }) + } // // /** // * 附近医疗点