Selaa lähdekoodia

门口机tcp callback修改

weizhengliang 2 vuotta sitten
vanhempi
commit
b5c86d0584
25 muutettua tiedostoa jossa 2132 lisäystä ja 1177 poistoa
  1. 4 1
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/activity/CallingdoorActivity.kt
  2. 0 2
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/di/CallingdoorComponent.kt
  3. 20 2
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/BaseCallFragment.kt
  4. 0 357
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/CallFragment.kt
  5. 93 15
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/SkyCallFragment.kt
  6. 2 0
      middleware/build.gradle
  7. 1 1
      middleware/src/main/code/com/wdkl/ncs/android/middleware/api/NetFactory.kt
  8. 589 32
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/InteractionDO.java
  9. 49 3
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/RoleDO.java
  10. 37 610
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/InteractionVO.java
  11. 244 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TaskSchedule.java
  12. 28 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TcpClient.java
  13. 135 12
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TcpClientHandler.java
  14. 4 26
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/DeviceChannel.java
  15. 1 1
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/DeviceUtil.java
  16. 40 2
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/EventUtil.java
  17. 30 6
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/ImUtil.java
  18. 22 14
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/OtherUtil.java
  19. 76 20
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/VoiceUtil.java
  20. 37 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpCallback.java
  21. 25 67
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpModel.java
  22. 49 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpSendModel.java
  23. 106 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/enums/RoleTypeEnum.java
  24. 57 6
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/enums/TcpAction.java
  25. 483 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/util/DateUtil.java

+ 4 - 1
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/activity/CallingdoorActivity.kt

@@ -1204,13 +1204,16 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
                                 var fragment = SkyCallFragment()
                                 var bundle = Bundle()
                                 bundle.putInt("call_state", 1)
+                                bundle.putString("tcp_tid", tcpModel.tid)
                                 bundle.putSerializable("tcp_model", tcpModel)
                                 fragment.arguments = bundle
                                 addCallFragment(fragment)
                             } else {
                                 showMessage(R.string.call_init_error)
                                 Constant.CALL_STATE = Constant.CALL_STANDBY
-                                VoiceUtil.rejectAudioCall(Constant.DEVICE_ID, Constant.fromId, Constant.interactionId)
+                                //VoiceUtil.rejectAudioCall(Constant.DEVICE_ID, Constant.fromId, Constant.interactionId)
+                                val rejectTcp = VoiceUtil.voiceReject(tcpModel.tid, Constant.DEVICE_ID, Constant.fromId, Constant.interactionId)
+                                TcpClient.getInstance().sendMsg(rejectTcp.toJson())
                             }
                         }
                     } else if (tcpModel.type == TcpType.SOS) {

+ 0 - 2
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/di/CallingdoorComponent.kt

@@ -14,8 +14,6 @@ interface CallingdoorComponent {
 
     fun inject(fragment: MainFragment)
 
-    fun inject(fragment: CallFragment)
-
     fun inject(fragment: QrCodeFragment)
 
     fun inject(fragment: TestFragment)

+ 20 - 2
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/BaseCallFragment.kt

@@ -15,6 +15,7 @@ import com.wdkl.app.ncs.callingdoor.settings.SettingConfig
 import com.wdkl.ncs.android.lib.utils.showMessage
 import com.wdkl.ncs.android.middleware.common.Constant
 import com.wdkl.ncs.android.middleware.common.MessageEvent
+import com.wdkl.ncs.android.middleware.tcp.TcpClient
 import com.wdkl.ncs.android.middleware.tcp.channel.VoiceUtil
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
 import org.greenrobot.eventbus.EventBus
@@ -29,6 +30,7 @@ abstract class BaseCallFragment: Fragment(), View.OnTouchListener {
     protected var callState : Int = 0
     protected var tcpModel: TcpModel? = null
     protected var bedId: Int = -1
+    protected var tid: String? = ""
 
     //计时器
     lateinit var countDownTimer: CountDownTimer
@@ -39,6 +41,7 @@ abstract class BaseCallFragment: Fragment(), View.OnTouchListener {
         retainInstance = true
         callState = arguments.getInt("call_state")
         bedId = arguments.getInt("bed_id")
+        tid = arguments.getString("tcp_tid")
         if (arguments.getSerializable("tcp_model") != null) {
             tcpModel = arguments.getSerializable("tcp_model") as TcpModel
         }
@@ -111,10 +114,12 @@ abstract class BaseCallFragment: Fragment(), View.OnTouchListener {
                 showMessage(R.string.no_response)
                 Constant.CALL_STATE = Constant.CALL_STANDBY
                 if (callState == 0) {
-                    VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
+                    //VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
+                    voiceCancel()
                 } else if (callState == 2) {
                     if (bedId != -1) {
-                        VoiceUtil.cancelAudioCallBed(Constant.DEVICE_ID, bedId)
+                        //VoiceUtil.cancelAudioCallBed(Constant.DEVICE_ID, bedId)
+                        voiceCancelBed()
                     }
                 }
                 //backToMain()
@@ -142,4 +147,17 @@ abstract class BaseCallFragment: Fragment(), View.OnTouchListener {
         EventBus.getDefault().post(MessageEvent("BackCall", Constant.EVENT_REMOVE_CALL_FRAGMENT))
     }
 
+    protected fun voiceCancel() {
+        if (Constant.DEVICE_ID != null && Constant.interactionId != null) {
+            val callTcp = VoiceUtil.voiceCancel(tid, Constant.DEVICE_ID, Constant.interactionId)
+            TcpClient.getInstance().sendMsg(callTcp.toJson())
+        }
+    }
+
+    protected fun voiceCancelBed() {
+        if (Constant.DEVICE_ID != null && Constant.interactionId != null) {
+            val callTcp = VoiceUtil.voiceCancelBed(tid, Constant.DEVICE_ID, bedId, Constant.interactionId)
+            TcpClient.getInstance().sendMsg(callTcp.toJson())
+        }
+    }
 }

+ 0 - 357
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/CallFragment.kt

@@ -1,357 +0,0 @@
-package com.wdkl.app.ncs.callingdoor.fragment
-
-import android.os.CountDownTimer
-import android.os.SystemClock
-import android.util.Log
-import android.view.View
-import com.enation.javashop.net.engine.model.NetState
-import com.google.gson.Gson
-import com.wdkl.app.ncs.callingdoor.R
-import com.wdkl.app.ncs.callingdoor.databinding.VoiceCallLayBinding
-import com.wdkl.app.ncs.callingdoor.helper.MediaPlayHelper
-import com.wdkl.app.ncs.callingdoor.launch.CallingdoorLaunch
-import com.wdkl.app.ncs.callingdoor.settings.SettingConfig
-//import com.wdkl.app.ncs.sip.event.AEvent
-//import com.wdkl.app.ncs.sip.event.IEventListener
-//import com.wdkl.app.ncs.sip.helper.StarRtcHelper
-import com.wdkl.ncs.android.lib.base.BaseFragment
-import com.wdkl.ncs.android.lib.utils.errorLog
-import com.wdkl.ncs.android.lib.utils.showMessage
-import com.wdkl.ncs.android.lib.vo.filter
-import com.wdkl.ncs.android.middleware.common.Constant
-import com.wdkl.ncs.android.middleware.common.MessageEvent
-import com.wdkl.ncs.android.middleware.logic.contract.callingdoor.CallFragmentContract
-import com.wdkl.ncs.android.middleware.logic.presenter.callingdoor.MainFragmentPresenter
-import com.wdkl.ncs.android.middleware.model.vo.InteractionVO
-import com.wdkl.ncs.android.middleware.tcp.channel.VoiceUtil
-import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
-import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction
-import kotlinx.android.synthetic.main.voice_call_lay.*
-import org.greenrobot.eventbus.EventBus
-import org.greenrobot.eventbus.Subscribe
-import org.greenrobot.eventbus.ThreadMode
-
-class CallFragment : BaseFragment<MainFragmentPresenter, VoiceCallLayBinding>(), CallFragmentContract.View/*, IEventListener*/ {
-    val TAG = "CallFragment"
-
-    //通话状态:0-去电, 1-来电, 2-接通, 3-挂断
-    var callState : Int = 0
-    //呼叫倒计时
-    lateinit var countDownTimer: CountDownTimer
-    //来电设备id
-    var fromId: Int = -1
-    //目的设备id
-    var toId: Int = -1
-    //Sip通话目标设备id
-    var sipTargetId: String = ""
-    //Interaction ID
-    var interactionId: Int = -1
-    //去电铃声id
-    //var outCallStreamId: Int = -1
-    //来电铃声id
-    //var inCallStreamId: Int = -1
-
-
-    override fun getLayId(): Int {
-        return R.layout.voice_call_lay
-    }
-
-    override fun bindDagger() {
-        CallingdoorLaunch.component.inject(this)
-    }
-
-    override fun init() {
-        initCountDownTimer()
-        //StarRtcHelper.getInstance().addAudioCallListeners(this)
-
-        when (callState) {
-            0 -> {
-                //去电
-                sendCall()
-                VoiceUtil.startAudioCall(Constant.DEVICE_ID)
-                //播放铃音
-                MediaPlayHelper.getInstance().playResMusic(R.raw.outgoing_call, 0.6f, true)
-            }
-
-            1 -> {
-                //来电
-                incomingCall()
-                //播放铃声
-                MediaPlayHelper.getInstance().playResMusic(R.raw.incoming_call, 1.0f, true)
-            }
-
-            2 -> {
-                //接通
-                //acceptCall()
-            }
-
-            3 -> {
-                //挂断
-                //rejectCall()
-            }
-        }
-    }
-
-    override fun bindEvent() {
-        //去电或正在通话界面挂断按钮
-        voice_call_hangup.setOnClickListener {
-            //挂断通话,返回首页
-            if (Constant.CALL_STATE == Constant.CALL_CALLING) {
-                Constant.CALL_STATE = Constant.CALL_STANDBY
-                //StarRtcHelper.getInstance().hangupAudioCall()
-                VoiceUtil.handoffAudioCall(Constant.DEVICE_ID, fromId, interactionId)
-                backToMain()
-            } else {
-                Constant.CALL_STATE = Constant.CALL_STANDBY
-                VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
-                cancelCall()
-            }
-        }
-        //来电界面挂断按钮
-        voice_call_ring_hangoff.setOnClickListener {
-            //挂断通话,返回首页
-            MediaPlayHelper.getInstance().stopMusic()
-            Constant.CALL_STATE = Constant.CALL_STANDBY
-            VoiceUtil.rejectAudioCall(Constant.DEVICE_ID, fromId, interactionId)
-            backToMain()
-        }
-        //来电界面接听按钮
-        voice_call_ring_pickup_audio.setOnClickListener {
-            //接收通话,向主叫方发出已接听的TCP消息,主叫方接收该消息后向我发起sip通话请求,我自动接听sip通话
-            Log.d("wzlll", "pickup call state: " + Constant.CALL_STATE + ", my id: " + Constant.DEVICE_ID + ", from id: " + fromId + ", interaction id: " + interactionId + ", target sip: " + sipTargetId)
-            MediaPlayHelper.getInstance().stopMusic()
-            //if (!TextUtils.isEmpty(sipTargetId)) {
-                Constant.CALL_STATE = Constant.CALL_INCOMING
-                VoiceUtil.acceptAudioCall(Constant.DEVICE_ID, fromId, interactionId)
-            //}
-        }
-    }
-
-    override fun onStart() {
-        EventBus.getDefault().register(this)
-        super.onStart()
-    }
-
-    override fun onStop() {
-        EventBus.getDefault().unregister(this)
-        super.onStop()
-    }
-
-    override fun destory() {
-        countDownTimer.cancel()
-        if (Constant.CALL_STATE == Constant.CALL_CALLING) {
-            //StarRtcHelper.getInstance().hangupAudioCall()
-            VoiceUtil.handoffAudioCall(Constant.DEVICE_ID, fromId, interactionId)
-        }
-        Constant.CALL_STATE = Constant.CALL_STANDBY
-        //StarRtcHelper.getInstance().removeAudioCallListeners(this)
-        MediaPlayHelper.getInstance().stopMusic()
-    }
-
-    override fun onError(message: String, type: Int) {
-        getUtils().dismissDialog()
-        errorLog("error",message)
-        showMessage(message)
-    }
-
-    override fun complete(message: String, type: Int) {
-        getUtils().dismissDialog()
-    }
-
-    override fun start() {
-        getUtils().showDialog()
-    }
-
-    override fun networkMonitor(state: NetState) {
-        state.filter(onWifi = {
-
-        },onMobile = {
-
-        },offline = {
-
-        })
-    }
-
-/*    override fun dispatchEvent(aEventID: String, success: Boolean, eventObj: Any) {
-        Log.d("wzlll", "call state: " + Constant.CALL_STATE)
-        Log.d("wzlll", "received sip event: " + aEventID + ", success: " + success + ", event obj: " + eventObj.toString())
-        when (aEventID) {
-            AEvent.AEVENT_VOIP_REV_CALLING_AUDIO -> {
-                //分机呼叫主机,主机接听,同时发送sip通话请求,分机自动接听
-                if (Constant.CALL_STATE != Constant.CALL_CALLING) {
-                    MediaPlayHelper.getInstance().stopMusic()
-                    StarRtcHelper.getInstance().pickupAudioCall(activity, eventObj.toString())
-                    activity.runOnUiThread {
-                        acceptCall()
-                    }
-                }
-            }
-            AEvent.AEVENT_VOIP_REV_CALLING -> {
-                //语音通话请求
-                //if (Constant.CALL_STATE != Constant.CALL_CALLING) {
-                //    StarRtcHelper.getInstance().pickupAudioCall(activity, eventObj.toString())
-                //    activity.runOnUiThread {
-                //                        acceptCall()
-                //                    }
-                //}
-            }
-            AEvent.AEVENT_VOIP_REV_BUSY -> {
-                //对方线路忙
-                activity.runOnUiThread {
-                    //rejectCall()
-                    showMessage("线路忙!")
-                }
-            }
-
-            AEvent.AEVENT_VOIP_REV_REFUSED -> {
-                //对方拒绝通话
-                activity.runOnUiThread {
-                    //rejectCall()
-                }
-            }
-
-            AEvent.AEVENT_VOIP_REV_HANGUP -> {
-                //对方已挂断
-                activity.runOnUiThread {
-                    if (Constant.CALL_STATE == Constant.CALL_CALLING) {
-                        rejectCall()
-                    }
-                }
-            }
-
-            AEvent.AEVENT_VOIP_REV_CONNECT -> {
-                //对方接受通话
-                activity.runOnUiThread {
-                    //showMessage("通话成功!")
-                    //acceptCall()
-                }
-            }
-
-            AEvent.AEVENT_VOIP_REV_ERROR -> {
-                //通话错误
-                activity.runOnUiThread {
-                    //showMessage("通话错误!")
-                    rejectCall()
-                }
-            }
-        }
-    }*/
-
-    fun initCountDownTimer() {
-        val overTime = SettingConfig.getSipOverTime(getActivity()) * 1000L
-        countDownTimer = object: CountDownTimer(overTime, 1000) {
-            override fun onTick(millisUntilFinished: Long) {
-                val time = millisUntilFinished/1000
-                voice_call_timeout?.setText("呼叫倒计时: " + time + " 秒")
-            }
-
-            override fun onFinish() {
-                //呼叫超时,返回到主界面
-                showMessage("无人应答...")
-                MediaPlayHelper.getInstance().stopMusic()
-                VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
-                backToMain()
-            }
-        }
-    }
-
-    @Subscribe(threadMode = ThreadMode.MAIN)
-    fun onMoonEvent(messageEvent: MessageEvent) {
-        when (messageEvent.getType()) {
-            Constant.EVENT_TCP_MSG -> {
-                val tcpModel = messageEvent.message as TcpModel
-                if (tcpModel.getAction() == TcpAction.VoiceAction.ACCEPT) { //我方呼出,对方接受
-                    //todo: 通话中界面更新;建立数据通话
-                    val interactionVO = Gson().fromJson(tcpModel.data.toString(), InteractionVO::class.java)
-                    interactionId = interactionVO.id
-                    fromId = tcpModel.fromId
-                    //acceptCall()
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.REJECT) { //我方呼出,对方拒绝
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方拒绝并停留3秒,结束至正常界面;更新左侧
-                    showMessage("对方已拒绝!")
-                    rejectCall()
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.CALLING) { //我方呼出,对方通话中
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方占线并停留3秒,结束至正常界面;更新左侧
-                    //对于分机来说,对方处于通话中应当还是可以正常呼叫,而不应该直接挂断
-                    //showMessage("对方处于通话中!")
-                    //rejectCall()
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.SUCCESS) { //呼叫成功
-                    val interactionVO = Gson().fromJson(tcpModel.data.toString(), InteractionVO::class.java)
-                    interactionId = interactionVO.id
-                    voice_call_calling_text.setText("呼叫成功,等待接听中...")
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.FAILED) { //我方呼出,对方不在线,设备离线或其它错误
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方离线并停留3秒,结束至正常界面;更新左侧
-                    showMessage("呼叫失败,对方可能不在线!")
-                    MediaPlayHelper.getInstance().stopMusic()
-                    rejectCall()
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.HANDOFF) { //对方挂断,不论我方呼出或呼入
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方已挂断并停留3秒,结束至正常界面;更新左侧
-                    //showMessage("通话结束!")
-                    MediaPlayHelper.getInstance().stopMusic()
-                    rejectCall()
-                } else if (tcpModel.getAction() == TcpAction.VoiceAction.CANCEL) {
-                    //对方呼叫时取消
-                    MediaPlayHelper.getInstance().stopMusic()
-                    cancelCall()
-                }
-            }
-        }
-    }
-
-    //呼叫
-    fun sendCall() {
-        Constant.CALL_STATE = Constant.CALL_OUTGOING
-        voice_call_calling_text.setText("正在呼叫...")
-        voice_call_hangup_view.visibility = View.VISIBLE
-        voice_call_ring_view.visibility = View.GONE
-        voice_call_timer.visibility = View.GONE
-        voice_call_timeout.visibility = View.VISIBLE
-        countDownTimer.start()
-    }
-
-    //来电
-    fun incomingCall() {
-        Constant.CALL_STATE = Constant.CALL_INCOMING
-        countDownTimer.cancel()
-        voice_call_calling_text.setText("有新的来电...")
-        voice_call_hangup_view.visibility = View.GONE
-        voice_call_ring_view.visibility = View.VISIBLE
-        voice_call_timer.visibility = View.GONE
-        voice_call_timeout.visibility = View.GONE
-    }
-
-    //接通
-    fun acceptCall() {
-        Constant.CALL_STATE = Constant.CALL_CALLING
-        countDownTimer.cancel()
-        voice_call_calling_text.setText("通话中...")
-        voice_call_hangup_view.visibility = View.VISIBLE
-        voice_call_ring_view.visibility = View.GONE
-        voice_call_timer.visibility = View.VISIBLE
-        voice_call_timeout.visibility = View.GONE
-        voice_call_timer.base = SystemClock.elapsedRealtime()
-        voice_call_timer.start()
-    }
-
-    //挂断通话
-    fun rejectCall() {
-        Constant.CALL_STATE = Constant.CALL_STANDBY
-        countDownTimer.cancel()
-        voice_call_timer.base = SystemClock.elapsedRealtime()
-        voice_call_timer.stop()
-        backToMain()
-    }
-
-    //呼叫取消
-    fun cancelCall() {
-        Constant.CALL_STATE = Constant.CALL_STANDBY
-        countDownTimer.cancel()
-        voice_call_timer.base = SystemClock.elapsedRealtime()
-        voice_call_timer.stop()
-        backToMain()
-    }
-
-    private fun backToMain() {
-        EventBus.getDefault().post(MessageEvent("BackToMain", Constant.EVENT_BACK_MAIN))
-    }
-}

+ 93 - 15
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/SkyCallFragment.kt

@@ -8,6 +8,7 @@ import android.text.TextUtils
 import android.util.Log
 import android.view.View
 import android.view.ViewGroup
+import com.alibaba.fastjson.JSONObject
 import com.google.gson.Gson
 import com.wdkl.app.ncs.callingdoor.R
 import com.wdkl.app.ncs.callingdoor.helper.DoorLightHelper
@@ -18,9 +19,12 @@ import com.wdkl.ncs.android.lib.utils.showMessage
 import com.wdkl.ncs.android.middleware.common.Constant
 import com.wdkl.ncs.android.middleware.common.MessageEvent
 import com.wdkl.ncs.android.middleware.model.vo.InteractionVO
+import com.wdkl.ncs.android.middleware.tcp.TcpClient
 import com.wdkl.ncs.android.middleware.tcp.channel.VoiceUtil
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpCallback
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
 import com.wdkl.ncs.android.middleware.tcp.enums.DeviceTypeEnum
+import com.wdkl.ncs.android.middleware.tcp.enums.RoleTypeEnum
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpType
 import com.wdkl.ncs.janus.client.CallSessionCallback
@@ -154,10 +158,12 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
             } else {
                 Constant.CALL_STATE = Constant.CALL_STANDBY
                 if (callState == 0) {
-                    VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
+                    //VoiceUtil.cancelAudioCall(Constant.DEVICE_ID)
+                    voiceCancel()
                 } else if (callState == 2) {
                     if (bedId != -1) {
-                        VoiceUtil.cancelAudioCallBed(Constant.DEVICE_ID, bedId)
+                        //VoiceUtil.cancelAudioCallBed(Constant.DEVICE_ID, bedId)
+                        voiceCancelBed()
                     }
                 }
                 cancelCall()
@@ -168,7 +174,8 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
         sky_voice_call_ring_reject.setOnClickListener {
             RingPlayHelper.stopRingTone()
             Constant.CALL_STATE = Constant.CALL_STANDBY
-            VoiceUtil.rejectAudioCall(Constant.DEVICE_ID, fromId, interactionVO?.id)
+            //VoiceUtil.rejectAudioCall(Constant.DEVICE_ID, fromId, interactionVO?.id)
+            voiceReject()
             callEnd(false)
         }
 
@@ -177,7 +184,8 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
             acceptCall()
             RingPlayHelper.stopRingTone()
             Constant.CALL_STATE = Constant.CALL_CALLING
-            VoiceUtil.acceptAudioCall(Constant.DEVICE_ID, fromId, interactionVO?.id)
+            //VoiceUtil.acceptAudioCall(Constant.DEVICE_ID, fromId, interactionVO?.id)
+            voiceAccept()
             janusClient!!.connect()
         }
     }
@@ -197,29 +205,101 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
         }
     }
 
+    private fun voiceAccept() {
+        val callTcp = VoiceUtil.voiceAccept(tid, Constant.DEVICE_ID, fromId, interactionVO?.id)
+        val transaction = object : TcpCallback(callTcp.tid) {
+            override fun onSuccess(jsonObject: JSONObject) {
+                //
+            }
+
+            override fun onFailed(jsonObject: JSONObject) {
+                // 这里写发送失败的方法
+                val callbackString = jsonObject.getString(CALLBACK)
+                handler.post {
+                    showMessage("accept fail: $callbackString")
+                }
+            }
+        }
+        TcpClient.getInstance().sendTcp(callTcp, false, transaction)
+    }
+
+    private fun voiceReject() {
+        val callTcp = VoiceUtil.voiceReject(tid, Constant.DEVICE_ID, fromId, interactionVO?.id)
+        TcpClient.getInstance().sendMsg(callTcp.toJson())
+    }
+
     private fun startOutgoing(): Boolean {
+        var outCallTcp: TcpModel?
         if (callState == 0) {
             if (Constant.CALL_TYPE == Constant.VIDEO_CALL) {
-                VoiceUtil.startVideoCall(Constant.DEVICE_ID)
+                //VoiceUtil.startVideoCall(Constant.DEVICE_ID)
+                outCallTcp = VoiceUtil.videoCall(Constant.DEVICE_ID, RoleTypeEnum.NURSE.name)
             } else {
-                VoiceUtil.startAudioCall(Constant.DEVICE_ID)
+                //VoiceUtil.startAudioCall(Constant.DEVICE_ID)
+                outCallTcp = VoiceUtil.voiceCall(Constant.DEVICE_ID, RoleTypeEnum.NURSE.name)
             }
+
             Constant.CALL_STATE = Constant.CALL_OUTGOING
+            sky_voice_call_outgoing.visibility = View.VISIBLE
+            sky_voice_call_incoming.visibility = View.GONE
             sky_voice_call_timeout.visibility = View.VISIBLE
             sky_voice_call_timer.visibility = View.GONE
             startTimer()
+
+            val transaction: TcpCallback = object : TcpCallback(outCallTcp!!.tid) {
+                override fun onSuccess(jsonObject: JSONObject) {
+                    Constant.CALL_STATE = Constant.CALL_OUTGOING
+                }
+
+                override fun onFailed(jsonObject: JSONObject) {
+                    // 这里写发送失败的方法
+                    val callbackString = jsonObject.getString(CALLBACK)
+                    RingPlayHelper.stopRingTone()
+
+                    handler.post {
+                        cancelCall()
+                        showMessage("outgoing call failed: $callbackString")
+                    }
+                }
+            }
+            TcpClient.getInstance().sendTcp(outCallTcp, false, transaction)
+
             return true
         } else if (callState == 2) {
             if (bedId != -1) {
                 if (Constant.CALL_TYPE == Constant.VIDEO_CALL) {
-                    VoiceUtil.startVideoCallBed(Constant.DEVICE_ID, bedId)
+                    //VoiceUtil.startVideoCallBed(Constant.DEVICE_ID, bedId)
+                    outCallTcp = VoiceUtil.videoCallBed(Constant.DEVICE_ID, bedId)
                 } else {
-                    VoiceUtil.startAudioCallBed(Constant.DEVICE_ID, bedId)
+                    //VoiceUtil.startAudioCallBed(Constant.DEVICE_ID, bedId)
+                    outCallTcp = VoiceUtil.voiceCallBed(Constant.DEVICE_ID, bedId)
                 }
+
                 Constant.CALL_STATE = Constant.CALL_OUTGOING
+                sky_voice_call_outgoing.visibility = View.VISIBLE
+                sky_voice_call_incoming.visibility = View.GONE
                 sky_voice_call_timeout.visibility = View.VISIBLE
                 sky_voice_call_timer.visibility = View.GONE
                 startTimer()
+
+                val transaction: TcpCallback = object : TcpCallback(outCallTcp!!.tid) {
+                    override fun onSuccess(jsonObject: JSONObject) {
+                        Constant.CALL_STATE = Constant.CALL_OUTGOING
+                    }
+
+                    override fun onFailed(jsonObject: JSONObject) {
+                        // 这里写发送失败的方法
+                        val callbackString = jsonObject.getString(CALLBACK)
+                        RingPlayHelper.stopRingTone()
+
+                        handler.post {
+                            cancelCall()
+                            showMessage("outgoing call failed: $callbackString")
+                        }
+                    }
+                }
+                TcpClient.getInstance().sendTcp(outCallTcp, false, transaction)
+
                 return true
             } else {
                 showMessage("bed_id null")
@@ -233,13 +313,7 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
 
     //去电界面
     private fun showOutgoingCall() {
-        Constant.CALL_STATE = Constant.CALL_OUTGOING
         sky_voice_call_calling_text.setText(R.string.call_success)
-        sky_voice_call_outgoing.visibility = View.VISIBLE
-        sky_voice_call_incoming.visibility = View.GONE
-        sky_voice_call_timeout.visibility = View.VISIBLE
-        sky_voice_call_timer.visibility = View.GONE
-        startTimer()
 
         if (!audioCall) {
             //显示视频画面
@@ -318,7 +392,9 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
             Log.e(TAG, "call end !!!!!!!!!!!!!!!!!!")
 
             if (handoff) {
-                VoiceUtil.handoffAudioCall(Constant.DEVICE_ID, fromId, Constant.interactionId)
+                //VoiceUtil.handoffAudioCall(Constant.DEVICE_ID, fromId, Constant.interactionId)
+                val callTcp = VoiceUtil.voiceHandoff(tid, Constant.DEVICE_ID, fromId, Constant.interactionId)
+                TcpClient.getInstance().sendMsg(callTcp.toJson())
             }
 
             if (janusClient!!.webSocketChannel != null) {
@@ -502,6 +578,8 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
                             //呼叫成功
                             //本机呼叫的时候tcpmodel为空,只有呼叫成功的时候才能获得对应tcp相关数据
                             interactionVO = curInteractionVO
+                            fromId = curTcpModel.fromId
+                            tid = curTcpModel.tid
                             Constant.interactionId = curInteractionVO.id
                             showOutgoingCall()
                             janusClient!!.connect()

+ 2 - 0
middleware/build.gradle

@@ -80,4 +80,6 @@ dependencies {
 
     compile 'com.fasterxml.jackson.core:jackson-databind:2.9.5'
     compile 'io.swagger:swagger-annotations:1.5.14'
+
+    compile 'org.mongodb:bson:3.6.3'
 }

+ 1 - 1
middleware/src/main/code/com/wdkl/ncs/android/middleware/api/NetFactory.kt

@@ -52,7 +52,7 @@ class NetFactory {
      * @Type  Long
      * @Note  默认超时
      */
-    private val DEFAULT_TIMEOUT: Long = 10
+    private val DEFAULT_TIMEOUT: Long = 15
 
     /**
      * @Name  context

+ 589 - 32
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/InteractionDO.java

@@ -1,17 +1,21 @@
 package com.wdkl.ncs.android.middleware.model.dos;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import com.google.common.base.Strings;
 import com.wdkl.ncs.android.middleware.model.annotation.Column;
 import com.wdkl.ncs.android.middleware.model.annotation.Id;
 import com.wdkl.ncs.android.middleware.model.annotation.PrimaryKeyField;
 import com.wdkl.ncs.android.middleware.model.annotation.Table;
 
+import java.io.Serializable;
+import java.util.ArrayList;
+
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-import java.io.Serializable;
-
 @Table(name = "ncs_interaction")
 @ApiModel
 @JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
@@ -43,6 +47,12 @@ public class InteractionDO implements Serializable {
     @ApiModelProperty(value = "科室Id", required = false)
     private Integer partId;
     /**
+     * 科室名称
+     */
+    @Column(name = "part_name")
+    @ApiModelProperty(value = "科室名称", required = false)
+    private String partName;
+    /**
      * 交互类型(1:语音通话,2:视频通话,3:卫生间紧急呼叫,4:语音留言,5:文本消息,6:按键事件)
      */
     @Column(name = "action_type")
@@ -54,6 +64,7 @@ public class InteractionDO implements Serializable {
     @Column(name = "action_result")
     @ApiModelProperty(value = "0失败,1成功", required = false)
     private Integer actionResult;
+
     /**
      * 交互发起设备Id
      */
@@ -61,23 +72,63 @@ public class InteractionDO implements Serializable {
     @ApiModelProperty(value = "交互发起设备Id", required = false)
     private Integer fromDeviceId;
     /**
-     * 交互对象设备Id
+     * null
      */
-    @Column(name = "to_device_id")
-    @ApiModelProperty(value = "交互对象设备Id", required = false)
-    private Integer toDeviceId;
+    @Column(name = "from_eth_mac")
+    @ApiModelProperty(value = "发起端设备的有线以太网卡MAC地址", required = false)
+    private String fromEthMac;
+
+    @Column(name = "from_eth_ip")
+    @ApiModelProperty(value = "发起端设备的有线以太网卡分配的IP地址", required = false)
+    private String fromEthIp;
+    /**
+     * null
+     */
+    @Column(name = "from_sip_id")
+    @ApiModelProperty(value = "发起端设备的SIP账号", required = false)
+    private String fromSipId;
+    /**
+     * null
+     */
+    @Column(name = "from_device_type")
+    @ApiModelProperty(value = "发起端设备的设备类型", required = false)
+    private Integer fromDeviceType;
+
+    @Column(name = "from_device_name")
+    @ApiModelProperty(value = "发起端设备的名称", required = false)
+    private String fromDeviceName;
+    /**
+     * null
+     */
+    @Column(name = "from_device_phone_number")
+    @ApiModelProperty(value = "发起端设备号码", required = false)
+    private String fromDevicePhoneNumber;
     /**
      * 发起设备所在空间结构
      */
     @Column(name = "from_device_frame_id")
     @ApiModelProperty(value = "发起设备所在空间结构", required = false)
     private Integer fromDeviceFrameId;
+
+    @Column(name = "from_frame_type")
+    @ApiModelProperty(value = "发起端空间结构类型:0楼、1病房、2床位", required = false)
+    private Integer fromFrameType;
     /**
-     * 交互对象所在空间结果
+     * null
      */
-    @Column(name = "to_device_frame_id")
-    @ApiModelProperty(value = "交互对象所在空间结果", required = false)
-    private Integer toDeviceFrameId;
+    @Column(name = "from_frame_name")
+    @ApiModelProperty(value = "发起端空间结构名称", required = false)
+    private String fromFrameName;
+    /**
+     * null
+     */
+    @Column(name = "from_frame_full_name")
+    @ApiModelProperty(value = "发起端空间结构全名", required = false)
+    private String fromFrameFullName;
+
+    @Column(name = "from_frame_parent_id")
+    @ApiModelProperty(value = "发起端空间父级id", required = false)
+    private Integer fromFrameParentId;
     /**
      * 交互发起设备使用者member_id
      */
@@ -85,11 +136,132 @@ public class InteractionDO implements Serializable {
     @ApiModelProperty(value = "交互发起设备使用者member_id", required = false)
     private Integer fromDeviceMemberId;
     /**
+     * 用户
+     **/
+    @Column(name = "from_customer_id")
+    @ApiModelProperty(value = "发起端用户CustomId", required = false)
+    private Integer fromCustomerId;
+    /**
+     * null
+     */
+    @Column(name = "from_member_name")
+    @ApiModelProperty(value = "发起端用户姓名", required = false)
+    private String fromMemberName;
+    /**
+     * null
+     */
+    @Column(name = "from_member_face")
+    @ApiModelProperty(value = "发起端用户头像", required = false)
+    private String fromMemberFace;
+
+    @Column(name = "from_clerk_id")
+    @ApiModelProperty(value = "发起端用户成员Id,发起端为护士主机,腕表,医生机时才有", required = false)
+    private Integer fromClerkId;
+    /**
+     * null
+     */
+    @Column(name = "from_role_name")
+    @ApiModelProperty(value = "发起端用户角色名(医生、护士、护工)", required = false)
+    private String fromRoleName;
+
+
+    /**
+     * 交互对象设备Id
+     */
+    @Column(name = "to_device_id")
+    @ApiModelProperty(value = "交互对象设备Id", required = false)
+    private Integer toDeviceId;
+    /**
+     * null
+     */
+    @Column(name = "to_eth_mac")
+    @ApiModelProperty(value = "目的端设备的有线以太网卡MAC地址", required = false)
+    private String toEthMac;
+
+    @Column(name = "to_eth_ip")
+    @ApiModelProperty(value = "目的端设备的有线以太网卡分配的IP地址", required = false)
+    private String toEthIp;
+    /**
+     * null
+     */
+    @Column(name = "to_sip_id")
+    @ApiModelProperty(value = "目的端设备的SIP账号", required = false)
+    private String toSipId;
+    /**
+     * null
+     */
+    @Column(name = "to_device_type")
+    @ApiModelProperty(value = "目的端设备的设备类型", required = false)
+    private Integer toDeviceType;
+
+    @Column(name = "to_device_name")
+    @ApiModelProperty(value = "目的端设备的名称", required = false)
+    private String toDeviceName;
+    /**
+     * null
+     */
+    @Column(name = "to_device_phone_number")
+    @ApiModelProperty(value = "目的端设备号码", required = false)
+    private String toDevicePhoneNumber;
+    /**
+     * 交互对象所在空间结果
+     */
+    @Column(name = "to_device_frame_id")
+    @ApiModelProperty(value = "交互对象所在空间结果", required = false)
+    private Integer toDeviceFrameId;
+
+    @Column(name = "to_frame_type")
+    @ApiModelProperty(value = "目的端空间结构类型:0楼、1病房、2床位", required = false)
+    private Integer toFrameType;
+    /**
+     * null
+     */
+    @Column(name = "to_frame_name")
+    @ApiModelProperty(value = "目的端空间结构名称", required = false)
+    private String toFrameName;
+    /**
+     * null
+     */
+    @Column(name = "to_frame_full_name")
+    @ApiModelProperty(value = "目的端空间结构全名", required = false)
+    private String toFrameFullName;
+
+    @Column(name = "to_frame_parent_id")
+    @ApiModelProperty(value = "目的端空间父级id", required = false)
+    private Integer toFrameParentId;
+    /**
      * 交互对象设备使用者member_id
      */
     @Column(name = "to_device_member_id")
     @ApiModelProperty(value = "交互对象设备使用者member_id", required = false)
     private Integer toDeviceMemberId;
+
+    @Column(name = "to_customer_id")
+    @ApiModelProperty(value = "目的端用户CustomId", required = false)
+    private Integer toCustomerId;
+
+    /**
+     * null
+     */
+    @Column(name = "to_member_name")
+    @ApiModelProperty(value = "目的端用户姓名", required = false)
+    private String toMemberName;
+    /**
+     * null
+     */
+    @Column(name = "to_member_face")
+    @ApiModelProperty(value = "目的端用户头像", required = false)
+    private String toMemberFace;
+
+    @Column(name = "to_clerk_id")
+    @ApiModelProperty(value = "目的端用户成员Id,目的端为护士主机,腕表,医生机时才有", required = false)
+    private Integer toClerkId;
+    /**
+     * null
+     */
+    @Column(name = "to_role_name")
+    @ApiModelProperty(value = "目的端用户角色名(医生、护士、护工)", required = false)
+    private String toRoleName;
     /**
      * 是否为呼叫系统内部交互(如果是外部电话呼叫为true,否则为false)
      */
@@ -133,6 +305,24 @@ public class InteractionDO implements Serializable {
     @ApiModelProperty(value = "交互结束时间(通话时指通话挂断时间,通话挂断后要更新此字段)。事件响应时间、语音已读时间", required = false)
     private Long actionEnd;
     /**
+     * 交互处理者的member_id
+     */
+    @Column(name = "action_end_member_id")
+    @ApiModelProperty(value = "交互处理者的member_id", required = false)
+    private Integer actionEndMemberId;
+    /**
+     * null
+     */
+    @Column(name = "action_end_member_name")
+    @ApiModelProperty(value = "交互处理者的用户姓名", required = false)
+    private String actionEndMemberName;
+    /**
+     * 交互完成时间
+     */
+    @Column(name = "action_completed")
+    @ApiModelProperty(value = "交互完成时间", required = false)
+    private Long actionCompleted;
+    /**
      * 交互数据(类型1,2,3为空)(类型4为音频文件地址)(5为文本内容)(类型6为具体按键类型)
      */
     @Column(name = "data")
@@ -152,9 +342,51 @@ public class InteractionDO implements Serializable {
     private String errorMessage;
 
     @Column(name = "action_direction_type")
-    @ApiModelProperty(value = "交互方向类型(1:分机到主机、腕表、医生机,2:主机、腕表、医生机到分机,3主机、腕表、医生机之间互通,4:分机到分机)",required = false)
+    @ApiModelProperty(value = "交互方向类型(1:分机到主机、腕表、医生机,2:主机、腕表、医生机到分机,3主机、腕表、医生机之间互通,4:分机到分机)", required = false)
     private Integer actionDirectionType;
 
+    @Column(name = "action_status")
+    @ApiModelProperty(value = "事件类型的交互状态(包括:发出,响应,取消,完成)", required = false)
+    private String actionStatus;
+    /**
+     * null
+     */
+    @Column(name = "relative_id")
+    @ApiModelProperty(value = "亲属id,外部来电时,from_member亲属的memberId", required = false)
+    private Integer relativeId;
+    /**
+     * null
+     */
+    @Column(name = "relative_name")
+    @ApiModelProperty(value = "外部来电时,from_member亲属关系", required = false)
+    private String relativeName;
+
+
+    /**
+     *交互接收者的顺序,一个JS数组,一个交互可能同时给同一角色的多个用户,用JS数组可以个分多个层级
+     */
+    @Column(name = "spread_member_path")
+    @ApiModelProperty(value = "交互接收者的顺序", required = false)
+    private String spreadMemberPath;
+
+
+    /**
+     *交互接收的memberId,用逗号隔开,可以不考虑顺序,方便查询用户交互记录,把spread_member_path字段打散后用逗号连接
+     */
+    @Column(name = "spread_member_ids")
+    @ApiModelProperty(value = "交互接收的memberId,", required = false)
+    private String spreadMemberIds;
+
+
+    /**
+     *交互已触达的memberIds,交互被多人接收后,有任意一人处理,需要通知其他已触达的用户取消处理
+     */
+    @Column(name = "reached_member_ids")
+    @ApiModelProperty(value = "交互已触达的memberIds", required = false)
+    private String reachedMemberIds;
+
+    private ArrayList<Integer[]> spreadMemberPathArray;
+
 
     @PrimaryKeyField
     public Integer getId() {
@@ -165,7 +397,6 @@ public class InteractionDO implements Serializable {
         this.id = id;
     }
 
-
     public String getUnionId() {
         return unionId;
     }
@@ -174,7 +405,6 @@ public class InteractionDO implements Serializable {
         this.unionId = unionId;
     }
 
-
     public Long getCreateDate() {
         return createDate;
     }
@@ -183,7 +413,6 @@ public class InteractionDO implements Serializable {
         this.createDate = createDate;
     }
 
-
     public Integer getPartId() {
         return partId;
     }
@@ -192,6 +421,13 @@ public class InteractionDO implements Serializable {
         this.partId = partId;
     }
 
+    public String getPartName() {
+        return partName;
+    }
+
+    public void setPartName(String partName) {
+        this.partName = partName;
+    }
 
     public String getActionType() {
         return actionType;
@@ -201,7 +437,6 @@ public class InteractionDO implements Serializable {
         this.actionType = actionType;
     }
 
-
     public Integer getActionResult() {
         return actionResult;
     }
@@ -210,7 +445,6 @@ public class InteractionDO implements Serializable {
         this.actionResult = actionResult;
     }
 
-
     public Integer getFromDeviceId() {
         return fromDeviceId;
     }
@@ -219,15 +453,53 @@ public class InteractionDO implements Serializable {
         this.fromDeviceId = fromDeviceId;
     }
 
+    public String getFromEthMac() {
+        return fromEthMac;
+    }
 
-    public Integer getToDeviceId() {
-        return toDeviceId;
+    public void setFromEthMac(String fromEthMac) {
+        this.fromEthMac = fromEthMac;
     }
 
-    public void setToDeviceId(Integer toDeviceId) {
-        this.toDeviceId = toDeviceId;
+    public String getFromEthIp() {
+        return fromEthIp;
+    }
+
+    public void setFromEthIp(String fromEthIp) {
+        this.fromEthIp = fromEthIp;
+    }
+
+    public String getFromSipId() {
+        return fromSipId;
+    }
+
+    public void setFromSipId(String fromSipId) {
+        this.fromSipId = fromSipId;
     }
 
+    public Integer getFromDeviceType() {
+        return fromDeviceType;
+    }
+
+    public void setFromDeviceType(Integer fromDeviceType) {
+        this.fromDeviceType = fromDeviceType;
+    }
+
+    public String getFromDeviceName() {
+        return fromDeviceName;
+    }
+
+    public void setFromDeviceName(String fromDeviceName) {
+        this.fromDeviceName = fromDeviceName;
+    }
+
+    public String getFromDevicePhoneNumber() {
+        return fromDevicePhoneNumber;
+    }
+
+    public void setFromDevicePhoneNumber(String fromDevicePhoneNumber) {
+        this.fromDevicePhoneNumber = fromDevicePhoneNumber;
+    }
 
     public Integer getFromDeviceFrameId() {
         return fromDeviceFrameId;
@@ -237,15 +509,37 @@ public class InteractionDO implements Serializable {
         this.fromDeviceFrameId = fromDeviceFrameId;
     }
 
+    public Integer getFromFrameType() {
+        return fromFrameType;
+    }
 
-    public Integer getToDeviceFrameId() {
-        return toDeviceFrameId;
+    public void setFromFrameType(Integer fromFrameType) {
+        this.fromFrameType = fromFrameType;
     }
 
-    public void setToDeviceFrameId(Integer toDeviceFrameId) {
-        this.toDeviceFrameId = toDeviceFrameId;
+    public String getFromFrameName() {
+        return fromFrameName;
     }
 
+    public void setFromFrameName(String fromFrameName) {
+        this.fromFrameName = fromFrameName;
+    }
+
+    public String getFromFrameFullName() {
+        return fromFrameFullName;
+    }
+
+    public void setFromFrameFullName(String fromFrameFullName) {
+        this.fromFrameFullName = fromFrameFullName;
+    }
+
+    public Integer getFromFrameParentId() {
+        return fromFrameParentId;
+    }
+
+    public void setFromFrameParentId(Integer fromFrameParentId) {
+        this.fromFrameParentId = fromFrameParentId;
+    }
 
     public Integer getFromDeviceMemberId() {
         return fromDeviceMemberId;
@@ -255,6 +549,141 @@ public class InteractionDO implements Serializable {
         this.fromDeviceMemberId = fromDeviceMemberId;
     }
 
+    public Integer getFromCustomerId() {
+        return fromCustomerId;
+    }
+
+    public void setFromCustomerId(Integer fromCustomerId) {
+        this.fromCustomerId = fromCustomerId;
+    }
+
+    public String getFromMemberName() {
+        return fromMemberName;
+    }
+
+    public void setFromMemberName(String fromMemberName) {
+        this.fromMemberName = fromMemberName;
+    }
+
+    public String getFromMemberFace() {
+        return fromMemberFace;
+    }
+
+    public void setFromMemberFace(String fromMemberFace) {
+        this.fromMemberFace = fromMemberFace;
+    }
+
+    public Integer getFromClerkId() {
+        return fromClerkId;
+    }
+
+    public void setFromClerkId(Integer fromClerkId) {
+        this.fromClerkId = fromClerkId;
+    }
+
+    public String getFromRoleName() {
+        return fromRoleName;
+    }
+
+    public void setFromRoleName(String fromRoleName) {
+        this.fromRoleName = fromRoleName;
+    }
+
+    public Integer getToDeviceId() {
+        return toDeviceId;
+    }
+
+    public void setToDeviceId(Integer toDeviceId) {
+        this.toDeviceId = toDeviceId;
+    }
+
+    public String getToEthMac() {
+        return toEthMac;
+    }
+
+    public void setToEthMac(String toEthMac) {
+        this.toEthMac = toEthMac;
+    }
+
+    public String getToEthIp() {
+        return toEthIp;
+    }
+
+    public void setToEthIp(String toEthIp) {
+        this.toEthIp = toEthIp;
+    }
+
+    public String getToSipId() {
+        return toSipId;
+    }
+
+    public void setToSipId(String toSipId) {
+        this.toSipId = toSipId;
+    }
+
+    public Integer getToDeviceType() {
+        return toDeviceType;
+    }
+
+    public void setToDeviceType(Integer toDeviceType) {
+        this.toDeviceType = toDeviceType;
+    }
+
+    public String getToDeviceName() {
+        return toDeviceName;
+    }
+
+    public void setToDeviceName(String toDeviceName) {
+        this.toDeviceName = toDeviceName;
+    }
+
+    public String getToDevicePhoneNumber() {
+        return toDevicePhoneNumber;
+    }
+
+    public void setToDevicePhoneNumber(String toDevicePhoneNumber) {
+        this.toDevicePhoneNumber = toDevicePhoneNumber;
+    }
+
+    public Integer getToDeviceFrameId() {
+        return toDeviceFrameId;
+    }
+
+    public void setToDeviceFrameId(Integer toDeviceFrameId) {
+        this.toDeviceFrameId = toDeviceFrameId;
+    }
+
+    public Integer getToFrameType() {
+        return toFrameType;
+    }
+
+    public void setToFrameType(Integer toFrameType) {
+        this.toFrameType = toFrameType;
+    }
+
+    public String getToFrameName() {
+        return toFrameName;
+    }
+
+    public void setToFrameName(String toFrameName) {
+        this.toFrameName = toFrameName;
+    }
+
+    public String getToFrameFullName() {
+        return toFrameFullName;
+    }
+
+    public void setToFrameFullName(String toFrameFullName) {
+        this.toFrameFullName = toFrameFullName;
+    }
+
+    public Integer getToFrameParentId() {
+        return toFrameParentId;
+    }
+
+    public void setToFrameParentId(Integer toFrameParentId) {
+        this.toFrameParentId = toFrameParentId;
+    }
 
     public Integer getToDeviceMemberId() {
         return toDeviceMemberId;
@@ -264,6 +693,45 @@ public class InteractionDO implements Serializable {
         this.toDeviceMemberId = toDeviceMemberId;
     }
 
+    public Integer getToCustomerId() {
+        return toCustomerId;
+    }
+
+    public void setToCustomerId(Integer toCustomerId) {
+        this.toCustomerId = toCustomerId;
+    }
+
+    public String getToMemberName() {
+        return toMemberName;
+    }
+
+    public void setToMemberName(String toMemberName) {
+        this.toMemberName = toMemberName;
+    }
+
+    public String getToMemberFace() {
+        return toMemberFace;
+    }
+
+    public void setToMemberFace(String toMemberFace) {
+        this.toMemberFace = toMemberFace;
+    }
+
+    public Integer getToClerkId() {
+        return toClerkId;
+    }
+
+    public void setToClerkId(Integer toClerkId) {
+        this.toClerkId = toClerkId;
+    }
+
+    public String getToRoleName() {
+        return toRoleName;
+    }
+
+    public void setToRoleName(String toRoleName) {
+        this.toRoleName = toRoleName;
+    }
 
     public Boolean getOuteriorAction() {
         return outeriorAction;
@@ -273,7 +741,6 @@ public class InteractionDO implements Serializable {
         this.outeriorAction = outeriorAction;
     }
 
-
     public String getOuteriorActionNumber() {
         return outeriorActionNumber;
     }
@@ -282,7 +749,6 @@ public class InteractionDO implements Serializable {
         this.outeriorActionNumber = outeriorActionNumber;
     }
 
-
     public Long getOuteriorActionMemberId() {
         return outeriorActionMemberId;
     }
@@ -291,7 +757,6 @@ public class InteractionDO implements Serializable {
         this.outeriorActionMemberId = outeriorActionMemberId;
     }
 
-
     public Integer getRemarkId() {
         return remarkId;
     }
@@ -300,7 +765,6 @@ public class InteractionDO implements Serializable {
         this.remarkId = remarkId;
     }
 
-
     public Long getActionStart() {
         return actionStart;
     }
@@ -309,7 +773,6 @@ public class InteractionDO implements Serializable {
         this.actionStart = actionStart;
     }
 
-
     public Long getActionAccept() {
         return actionAccept;
     }
@@ -318,7 +781,6 @@ public class InteractionDO implements Serializable {
         this.actionAccept = actionAccept;
     }
 
-
     public Long getActionEnd() {
         return actionEnd;
     }
@@ -327,6 +789,29 @@ public class InteractionDO implements Serializable {
         this.actionEnd = actionEnd;
     }
 
+    public Integer getActionEndMemberId() {
+        return actionEndMemberId;
+    }
+
+    public void setActionEndMemberId(Integer actionEndMemberId) {
+        this.actionEndMemberId = actionEndMemberId;
+    }
+
+    public String getActionEndMemberName() {
+        return actionEndMemberName;
+    }
+
+    public void setActionEndMemberName(String actionEndMemberName) {
+        this.actionEndMemberName = actionEndMemberName;
+    }
+
+    public Long getActionCompleted() {
+        return actionCompleted;
+    }
+
+    public void setActionCompleted(Long actionCompleted) {
+        this.actionCompleted = actionCompleted;
+    }
 
     public String getData() {
         return data;
@@ -336,7 +821,6 @@ public class InteractionDO implements Serializable {
         this.data = data;
     }
 
-
     public String getErrorCode() {
         return errorCode;
     }
@@ -345,7 +829,6 @@ public class InteractionDO implements Serializable {
         this.errorCode = errorCode;
     }
 
-
     public String getErrorMessage() {
         return errorMessage;
     }
@@ -361,4 +844,78 @@ public class InteractionDO implements Serializable {
     public void setActionDirectionType(Integer actionDirectionType) {
         this.actionDirectionType = actionDirectionType;
     }
+
+    public String getActionStatus() {
+        return actionStatus;
+    }
+
+    public void setActionStatus(String actionStatus) {
+        this.actionStatus = actionStatus;
+    }
+
+    public Integer getRelativeId() {
+        return relativeId;
+    }
+
+    public void setRelativeId(Integer relativeId) {
+        this.relativeId = relativeId;
+    }
+
+    public String getRelativeName() {
+        return relativeName;
+    }
+
+    public void setRelativeName(String relativeName) {
+        this.relativeName = relativeName;
+    }
+
+
+    public String getSpreadMemberPath() {
+        return spreadMemberPath;
+    }
+
+    public void setSpreadMemberPath(String spreadMemberPath) {
+        this.spreadMemberPath = spreadMemberPath;
+    }
+
+    public String getSpreadMemberIds() {
+        return spreadMemberIds;
+    }
+
+    public void setSpreadMemberIds(String spreadMemberIds) {
+        this.spreadMemberIds = spreadMemberIds;
+    }
+
+    public String getReachedMemberIds() {
+        return reachedMemberIds;
+    }
+
+    public void setReachedMemberIds(String reachedMemberIds) {
+        this.reachedMemberIds = reachedMemberIds;
+    }
+
+    public ArrayList<Integer[]> getSpreadMemberPathArray() {
+        if (spreadMemberPathArray != null) {
+            return spreadMemberPathArray;
+        }
+        if (!Strings.isNullOrEmpty(spreadMemberPath)){
+            ArrayList<Integer[]> arrayList = new ArrayList<>();
+            JSONArray jsonArray = JSON.parseArray(spreadMemberPath);
+            for(Object item:jsonArray){
+                JSONArray itemJsonArray = (JSONArray)item;
+                Integer[] itemArray = new Integer[itemJsonArray.size()];
+                for(int i=0;i<itemJsonArray.size();i++){
+                    itemArray[i] = itemJsonArray.getInteger(i);
+                }
+                arrayList.add(itemArray);
+            }
+            spreadMemberPathArray = arrayList;
+            return spreadMemberPathArray;
+        }
+        return null;
+    }
+
+    public void setSpreadMemberPathArray(ArrayList<Integer[]> spreadMemberPathArray) {
+        this.spreadMemberPathArray = spreadMemberPathArray;
+    }
 }

+ 49 - 3
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/RoleDO.java

@@ -2,8 +2,6 @@ package com.wdkl.ncs.android.middleware.model.dos;
 
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 import com.wdkl.ncs.android.middleware.model.annotation.Column;
 import com.wdkl.ncs.android.middleware.model.annotation.Id;
 import com.wdkl.ncs.android.middleware.model.annotation.PrimaryKeyField;
@@ -11,6 +9,9 @@ import com.wdkl.ncs.android.middleware.model.annotation.Table;
 
 import java.io.Serializable;
 
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
 @Table(name = "ncs_role")
 @ApiModel
 @JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
@@ -19,7 +20,7 @@ public class RoleDO implements Serializable {
     /**
      * 角色主键
      */
-    @Column(name = "role_id")
+    @Id(name = "role_id")
     @ApiModelProperty(value = "角色主键", required = false)
     private Integer roleId;
     /**
@@ -58,6 +59,27 @@ public class RoleDO implements Serializable {
     @Column(name = "hidden_in_seller")
     @ApiModelProperty(value = "是否为隐藏角色,不可见,管理端可见", required = false)
     private Boolean hiddenInSeller;
+    /**
+     * 是否处理呼叫,唯一,相斥
+     */
+    @Column(name = "bool_main")
+    @ApiModelProperty(value = "是否处理呼叫,唯一,相斥", required = false)
+    private Boolean boolMain;
+
+    /**
+     * 上级领导角色Id
+     */
+    @Column(name = "leader_role_id",allowNullUpdate = true)
+    @ApiModelProperty(value = "上级领导角色Id", required = false)
+    private Integer leaderRoleId;
+
+
+    /**
+     * 角色类型,内置逻辑设置 RoleTypeEnum 名称
+     */
+    @Column(name = "role_type")
+    @ApiModelProperty(value = "角色描述", required = false)
+    private String roleType;
 
 
     @PrimaryKeyField
@@ -123,4 +145,28 @@ public class RoleDO implements Serializable {
         this.hiddenInSeller = hiddenInSeller;
     }
 
+    public Boolean getBoolMain() {
+        return boolMain;
+    }
+
+    public void setBoolMain(Boolean boolMain) {
+        this.boolMain = boolMain;
+    }
+
+
+    public Integer getLeaderRoleId() {
+        return leaderRoleId;
+    }
+
+    public void setLeaderRoleId(Integer leaderRoleId) {
+        this.leaderRoleId = leaderRoleId;
+    }
+
+    public String getRoleType() {
+        return roleType;
+    }
+
+    public void setRoleType(String roleType) {
+        this.roleType = roleType;
+    }
 }

+ 37 - 610
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/InteractionVO.java

@@ -2,12 +2,7 @@ package com.wdkl.ncs.android.middleware.model.vo;
 
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import com.wdkl.ncs.android.middleware.model.annotation.Column;
-import com.wdkl.ncs.android.middleware.model.annotation.Id;
-
-import java.io.Serializable;
-
-import io.swagger.annotations.ApiModelProperty;
+import com.wdkl.ncs.android.middleware.model.dos.InteractionDO;
 
 /**
  * @program nc
@@ -16,609 +11,41 @@ import io.swagger.annotations.ApiModelProperty;
  * @create: 2021/04/02 15:27
  */
 @JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
-public class InteractionVO implements Serializable {
-
-    /**
-     * id
-     */
-    @Column(name = "id")
-    @ApiModelProperty(value = "id", required = false)
-    @Id(name = "id")
-    private Integer id;
-    /**
-     * 创建时间
-     */
-    @Column(name = "create_date")
-    @ApiModelProperty(value = "创建时间", required = false)
-    private Long createDate;
-    /**
-     * 科室Id
-     */
-    @Column(name = "part_id")
-    @ApiModelProperty(value = "科室Id", required = false)
-    private Integer partId;
-    /**
-     * 交互类型(1:语音通话,2:视频通话,3:卫生间紧急呼叫,4:语音留言,5:文本消息,6:按键事件)
-     */
-    @Column(name = "action_type")
-    @ApiModelProperty(value = "交互类型(1:语音通话,2:视频通话,3:卫生间紧急呼叫,4:语音留言,5:文本消息,6:按键事件)", required = false)
-    private String actionType;
-    /**
-     * SUCCESS、FAILED
-     */
-    @Column(name = "action_result")
-    @ApiModelProperty(value = "0失败,1成功", required = false)
-    private Integer actionResult;
-    /**
-     * 交互发起设备Id
-     */
-    @Column(name = "from_device_id")
-    @ApiModelProperty(value = "交互发起设备Id", required = false)
-    private Integer fromDeviceId;
-    /**
-     * 交互对象设备Id
-     */
-    @Column(name = "to_device_id")
-    @ApiModelProperty(value = "交互对象设备Id", required = false)
-    private Integer toDeviceId;
-    /**
-     * 发起设备所在空间结构
-     */
-    @Column(name = "from_device_frame_id")
-    @ApiModelProperty(value = "发起设备所在空间结构", required = false)
-    private Integer fromDeviceFrameId;
-    /**
-     * 交互对象所在空间结果
-     */
-    @Column(name = "to_device_frame_id")
-    @ApiModelProperty(value = "交互对象所在空间结果", required = false)
-    private Integer toDeviceFrameId;
-    /**
-     * 交互发起设备使用者member_id
-     */
-    @Column(name = "from_device_member_id")
-    @ApiModelProperty(value = "交互发起设备使用者member_id", required = false)
-    private Integer fromDeviceMemberId;
-    /**
-     * 交互对象设备使用者member_id
-     */
-    @Column(name = "to_device_member_id")
-    @ApiModelProperty(value = "交互对象设备使用者member_id", required = false)
-    private Integer toDeviceMemberId;
-    /**
-     * 交互开始时间(通话时指通话接通时间,与create_time相同)
-     */
-    @Column(name = "action_start")
-    @ApiModelProperty(value = "交互开始时间(通话时指通话接通时间,与create_time相同)", required = false)
-    private Long actionStart;
-    /**
-     * 应答时间
-     */
-    @Column(name = "action_accept")
-    @ApiModelProperty(value = "应答时间", required = false)
-    private Long actionAccept;
-    /**
-     * 交互结束时间(通话时指通话挂断时间,通话挂断后要更新此字段)。事件响应时间、语音已读时间
-     */
-    @Column(name = "action_end")
-    @ApiModelProperty(value = "交互结束时间(通话时指通话挂断时间,通话挂断后要更新此字段)。事件响应时间、语音已读时间", required = false)
-    private Long actionEnd;
-    /**
-     * 交互处理者的member_id
-     */
-    @Column(name = "action_end_member_id")
-    @ApiModelProperty(value = "交互处理者的member_id", required = false)
-    private Integer actionEndMemberId;
-    /**
-     * 交互数据(类型1,2,3为空)(类型4为音频文件地址)(5为文本内容)(类型6为具体按键类型)
-     */
-    @Column(name = "data")
-    @ApiModelProperty(value = "交互数据(类型1,2,3为空)(类型4为音频文件地址)(5为文本内容)(类型6为具体按键类型)", required = false)
-    private String data;
-
-    @Column(name = "action_direction_type")
-    @ApiModelProperty(value = "交互方向类型(1:分机到主机、腕表、医生机,2:主机、腕表、医生机到分机,3主机、腕表、医生机之间互通,4:分机到分机)",required = false)
-    private Integer actionDirectionType;
-
-    /** 用户 **/
-    @Column(name = "from_customer_id")
-    @ApiModelProperty(value = "发起端用户CustomId", required = false)
-    private Integer fromCustomerId;
-
-    @Column(name = "from_member_name")
-    @ApiModelProperty(value = "发起端用户姓名", required = false)
-    private String fromMemberName;
-
-    @Column(name = "from_member_face")
-    @ApiModelProperty(value = "发起端用户头像", required = false)
-    private String fromMemberFace;
-
-    @Column(name = "from_clerk_id")
-    @ApiModelProperty(value = "发起端用户成员Id,发起端为护士主机,腕表,医生机时才有", required = false)
-    private Integer fromClerkId;
-
-    @Column(name = "from_role_name")
-    @ApiModelProperty(value = "发起端用户角色名(医生、护士、护工)", required = false)
-    private String fromRoleName;
-
-
-    @Column(name = "to_customer_id")
-    @ApiModelProperty(value = "目的端用户CustomId", required = false)
-    private Integer toCustomerId;
-
-    @Column(name = "to_member_name")
-    @ApiModelProperty(value = "目的端用户姓名", required = false)
-    private String toMemberName;
-
-    @Column(name = "to_member_face")
-    @ApiModelProperty(value = "目的端用户头像", required = false)
-    private String toMemberFace;
-
-    @Column(name = "to_clerk_id")
-    @ApiModelProperty(value = "目的端用户成员Id,目的端为护士主机,腕表,医生机时才有", required = false)
-    private Integer toClerkId;
-
-    @Column(name = "to_role_name")
-    @ApiModelProperty(value = "目的端用户角色名(医生、护士、护工)", required = false)
-    private String toRoleName;
-
-
-    /** 设备 **/
-    @Column(name = "from_eth_mac")
-    @ApiModelProperty(value = "发起端设备的有线以太网卡MAC地址", required = false)
-    private String fromEthMac;
-
-    @Column(name = "from_eth_ip")
-    @ApiModelProperty(value = "发起端设备的有线以太网卡分配的IP地址", required = false)
-    private String fromEthIp;
-
-
-    @Column(name = "from_sip_id")
-    @ApiModelProperty(value = "发起端设备的SIP账号", required = false)
-    private String fromSipId;
-
-    @Column(name = "from_device_type")
-    @ApiModelProperty(value = "发起端设备的设备类型", required = false)
-    private Integer fromDeviceType;
-
-    @Column(name = "from_device_name")
-    @ApiModelProperty(value = "发起端设备的名称", required = false)
-    private String fromDeviceName;
-
-
-    @Column(name = "to_eth_mac")
-    @ApiModelProperty(value = "目的端设备的有线以太网卡MAC地址", required = false)
-    private String toEthMac;
-
-    @Column(name = "to_eth_ip")
-    @ApiModelProperty(value = "目的端设备的有线以太网卡分配的IP地址", required = false)
-    private String toEthIp;
-
-
-    @Column(name = "to_sip_id")
-    @ApiModelProperty(value = "目的端设备的SIP账号", required = false)
-    private String toSipId;
-
-    @Column(name = "to_device_type")
-    @ApiModelProperty(value = "目的端设备的设备类型", required = false)
-    private Integer toDeviceType;
-
-
-    @Column(name = "to_device_name")
-    @ApiModelProperty(value = "目的端设备的名称", required = false)
-    private String toDeviceName;
-
-
-    /** 空间结构 **/
-
-    @Column(name = "from_frame_type")
-    @ApiModelProperty(value = "发起端空间结构类型:0楼、1病房、2床位", required = false)
-    private Integer fromFrameType;
-
-
-    @Column(name = "from_frame_name")
-    @ApiModelProperty(value = "发起端空间结构名称", required = false)
-    private String fromFrameName;
-
-    @Column(name = "from_frame_full_name")
-    @ApiModelProperty(value = "发起端空间结构全名", required = false)
-    private String fromFrameFullName;
-
-
-    @Column(name = "to_frame_type")
-    @ApiModelProperty(value = "目的端空间结构类型:0楼、1病房、2床位", required = false)
-    private Integer toFrameType;
-
-
-    @Column(name = "to_frame_name")
-    @ApiModelProperty(value = "目的端空间结构名称", required = false)
-    private String toFrameName;
-
-    @Column(name = "to_frame_full_name")
-    @ApiModelProperty(value = "发起端空间结构全名", required = false)
-    private String toFrameFullName;
-
-
-    @Column(name = "relative_id")
-    @ApiModelProperty(value = "亲属id,外部来电时,from_member亲属的memberId", required = false)
-    private Integer relativeId;
-
-    @Column(name = "relative_name")
-    @ApiModelProperty(value = "外部来电时,from_member亲属关系", required = false)
-    private String relativeName;
-
-    @Column(name = "action_end_member_name")
-    @ApiModelProperty(value = "交互处理者的用户姓名", required = false)
-    private String actionEndMemberName;
-
-
-
-
-    public Integer getId() {
-        return id;
-    }
-
-    public void setId(Integer id) {
-        this.id = id;
-    }
-
-    public Long getCreateDate() {
-        return createDate;
-    }
-
-    public void setCreateDate(Long createDate) {
-        this.createDate = createDate;
-    }
-
-    public Integer getPartId() {
-        return partId;
-    }
-
-    public void setPartId(Integer partId) {
-        this.partId = partId;
-    }
-
-    public String getActionType() {
-        return actionType;
-    }
-
-    public void setActionType(String actionType) {
-        this.actionType = actionType;
-    }
-
-    public Integer getActionResult() {
-        return actionResult;
-    }
-
-    public void setActionResult(Integer actionResult) {
-        this.actionResult = actionResult;
-    }
-
-    public Integer getFromDeviceId() {
-        return fromDeviceId;
-    }
-
-    public void setFromDeviceId(Integer fromDeviceId) {
-        this.fromDeviceId = fromDeviceId;
-    }
-
-    public Integer getToDeviceId() {
-        return toDeviceId;
-    }
-
-    public void setToDeviceId(Integer toDeviceId) {
-        this.toDeviceId = toDeviceId;
-    }
-
-    public Integer getFromDeviceFrameId() {
-        return fromDeviceFrameId;
-    }
-
-    public void setFromDeviceFrameId(Integer fromDeviceFrameId) {
-        this.fromDeviceFrameId = fromDeviceFrameId;
-    }
-
-    public Integer getToDeviceFrameId() {
-        return toDeviceFrameId;
-    }
-
-    public void setToDeviceFrameId(Integer toDeviceFrameId) {
-        this.toDeviceFrameId = toDeviceFrameId;
-    }
-
-    public Integer getFromDeviceMemberId() {
-        return fromDeviceMemberId;
-    }
-
-    public void setFromDeviceMemberId(Integer fromDeviceMemberId) {
-        this.fromDeviceMemberId = fromDeviceMemberId;
-    }
-
-    public Integer getToDeviceMemberId() {
-        return toDeviceMemberId;
-    }
-
-    public void setToDeviceMemberId(Integer toDeviceMemberId) {
-        this.toDeviceMemberId = toDeviceMemberId;
-    }
-
-    public Long getActionStart() {
-        return actionStart;
-    }
-
-    public void setActionStart(Long actionStart) {
-        this.actionStart = actionStart;
-    }
-
-    public Long getActionAccept() {
-        return actionAccept;
-    }
-
-    public void setActionAccept(Long actionAccept) {
-        this.actionAccept = actionAccept;
-    }
-
-    public Long getActionEnd() {
-        return actionEnd;
-    }
-
-    public void setActionEnd(Long actionEnd) {
-        this.actionEnd = actionEnd;
-    }
-
-    public Integer getActionEndMemberId() {
-        return actionEndMemberId;
-    }
-
-    public void setActionEndMemberId(Integer actionEndMemberId) {
-        this.actionEndMemberId = actionEndMemberId;
-    }
-
-    public String getData() {
-        return data;
-    }
-
-    public void setData(String data) {
-        this.data = data;
-    }
-
-    public Integer getActionDirectionType() {
-        return actionDirectionType;
-    }
-
-    public void setActionDirectionType(Integer actionDirectionType) {
-        this.actionDirectionType = actionDirectionType;
-    }
-
-    public Integer getFromCustomerId() {
-        return fromCustomerId;
-    }
-
-    public void setFromCustomerId(Integer fromCustomerId) {
-        this.fromCustomerId = fromCustomerId;
-    }
-
-    public String getFromMemberName() {
-        return fromMemberName;
-    }
-
-    public void setFromMemberName(String fromMemberName) {
-        this.fromMemberName = fromMemberName;
-    }
-
-    public String getFromMemberFace() {
-        return fromMemberFace;
-    }
-
-    public void setFromMemberFace(String fromMemberFace) {
-        this.fromMemberFace = fromMemberFace;
-    }
-
-    public Integer getFromClerkId() {
-        return fromClerkId;
-    }
-
-    public void setFromClerkId(Integer fromClerkId) {
-        this.fromClerkId = fromClerkId;
-    }
-
-    public String getFromRoleName() {
-        return fromRoleName;
-    }
-
-    public void setFromRoleName(String fromRoleName) {
-        this.fromRoleName = fromRoleName;
-    }
-
-    public Integer getToCustomerId() {
-        return toCustomerId;
-    }
-
-    public void setToCustomerId(Integer toCustomerId) {
-        this.toCustomerId = toCustomerId;
-    }
-
-    public String getToMemberName() {
-        return toMemberName;
-    }
-
-    public void setToMemberName(String toMemberName) {
-        this.toMemberName = toMemberName;
-    }
-
-    public String getToMemberFace() {
-        return toMemberFace;
-    }
-
-    public void setToMemberFace(String toMemberFace) {
-        this.toMemberFace = toMemberFace;
-    }
-
-    public Integer getToClerkId() {
-        return toClerkId;
-    }
-
-    public void setToClerkId(Integer toClerkId) {
-        this.toClerkId = toClerkId;
-    }
-
-    public String getToRoleName() {
-        return toRoleName;
-    }
-
-    public void setToRoleName(String toRoleName) {
-        this.toRoleName = toRoleName;
-    }
-
-    public String getFromEthMac() {
-        return fromEthMac;
-    }
-
-    public void setFromEthMac(String fromEthMac) {
-        this.fromEthMac = fromEthMac;
-    }
-
-    public String getFromEthIp() {
-        return fromEthIp;
-    }
-
-    public void setFromEthIp(String fromEthIp) {
-        this.fromEthIp = fromEthIp;
-    }
-
-    public String getFromSipId() {
-        return fromSipId;
-    }
-
-    public void setFromSipId(String fromSipId) {
-        this.fromSipId = fromSipId;
-    }
-
-    public Integer getFromDeviceType() {
-        return fromDeviceType;
-    }
-
-    public void setFromDeviceType(Integer fromDeviceType) {
-        this.fromDeviceType = fromDeviceType;
-    }
-
-    public String getFromDeviceName() {
-        return fromDeviceName;
-    }
-
-    public void setFromDeviceName(String fromDeviceName) {
-        this.fromDeviceName = fromDeviceName;
-    }
-
-    public String getToEthMac() {
-        return toEthMac;
-    }
-
-    public void setToEthMac(String toEthMac) {
-        this.toEthMac = toEthMac;
-    }
-
-    public String getToEthIp() {
-        return toEthIp;
-    }
-
-    public void setToEthIp(String toEthIp) {
-        this.toEthIp = toEthIp;
-    }
-
-    public String getToSipId() {
-        return toSipId;
-    }
-
-    public void setToSipId(String toSipId) {
-        this.toSipId = toSipId;
-    }
-
-    public Integer getToDeviceType() {
-        return toDeviceType;
-    }
-
-    public void setToDeviceType(Integer toDeviceType) {
-        this.toDeviceType = toDeviceType;
-    }
-
-    public String getToDeviceName() {
-        return toDeviceName;
-    }
-
-    public void setToDeviceName(String toDeviceName) {
-        this.toDeviceName = toDeviceName;
-    }
-
-    public Integer getFromFrameType() {
-        return fromFrameType;
-    }
-
-    public void setFromFrameType(Integer fromFrameType) {
-        this.fromFrameType = fromFrameType;
-    }
-
-    public String getFromFrameName() {
-        return fromFrameName;
-    }
-
-    public void setFromFrameName(String fromFrameName) {
-        this.fromFrameName = fromFrameName;
-    }
-
-    public String getFromFrameFullName() {
-        return fromFrameFullName;
-    }
-
-    public void setFromFrameFullName(String fromFrameFullName) {
-        this.fromFrameFullName = fromFrameFullName;
-    }
-
-    public Integer getToFrameType() {
-        return toFrameType;
-    }
-
-    public void setToFrameType(Integer toFrameType) {
-        this.toFrameType = toFrameType;
-    }
-
-    public String getToFrameName() {
-        return toFrameName;
-    }
-
-    public void setToFrameName(String toFrameName) {
-        this.toFrameName = toFrameName;
-    }
-
-    public String getToFrameFullName() {
-        return toFrameFullName;
-    }
-
-    public void setToFrameFullName(String toFrameFullName) {
-        this.toFrameFullName = toFrameFullName;
-    }
-
-    public Integer getRelativeId() {
-        return relativeId;
-    }
-
-    public void setRelativeId(Integer relativeId) {
-        this.relativeId = relativeId;
-    }
-
-    public String getRelativeName() {
-        return relativeName;
-    }
-
-    public void setRelativeName(String relativeName) {
-        this.relativeName = relativeName;
-    }
-
-    public String getActionEndMemberName() {
-        return actionEndMemberName;
-    }
-
-    public void setActionEndMemberName(String actionEndMemberName) {
-        this.actionEndMemberName = actionEndMemberName;
+public class InteractionVO extends InteractionDO {
+
+    @Override
+    public String toString() {
+        return "InteractionVO{" +
+                "fromCustomerId=" + getFromCustomerId() +
+                ", fromMemberName='" + getFromDeviceType() + '\'' +
+                ", fromMemberFace='" + getFromMemberFace() + '\'' +
+                ", fromClerkId=" + getFromClerkId() +
+                ", fromRoleName='" + getFromRoleName() + '\'' +
+                ", toCustomerId=" + getToCustomerId() +
+                ", toMemberName='" + getToMemberName() + '\'' +
+                ", toMemberFace='" + getToMemberFace() + '\'' +
+                ", toClerkId=" + getToClerkId() +
+                ", toRoleName='" + getToRoleName() + '\'' +
+                ", fromEthMac='" + getFromEthMac() + '\'' +
+                ", fromEthIp='" + getFromEthIp() + '\'' +
+                ", fromSipId='" + getFromSipId() + '\'' +
+                ", fromDeviceType=" + getFromDeviceType() +
+                ", toEthMac='" + getToEthMac() + '\'' +
+                ", toEthIp='" + getToEthIp() + '\'' +
+                ", toSipId='" + getToSipId() + '\'' +
+                ", toDeviceType=" + getToDeviceType() +
+                ", fromFrameType=" + getFromFrameType() +
+                ", fromFrameName='" + getFromFrameName() + '\'' +
+                ", fromFrameFullName='" + getFromFrameFullName() + '\'' +
+                ", toFrameType=" + getToFrameType() +
+                ", toFrameName='" + getToFrameName() + '\'' +
+                ", toFrameFullName='" + getToFrameFullName() + '\'' +
+                ", relativeId=" + getRelativeId() +
+                ", relativeName='" + getRelativeName() + '\'' +
+                ", actionStatus='" + getActionStatus() + '\'' +
+                ", actionEndMemberId=" + getActionEndMemberId() +
+                ", actionEndMemberName='" + getActionEndMemberName() + '\'' +
+                '}';
     }
 }
+

+ 244 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TaskSchedule.java

@@ -0,0 +1,244 @@
+package com.wdkl.ncs.android.middleware.tcp;
+
+import com.wdkl.ncs.android.middleware.tcp.util.DateUtil;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 描述
+ *
+ * @author allen
+ * 2022-11-28 10:15
+ */
+public class TaskSchedule {
+    private final String TAG = getClass().getSimpleName();
+
+    private ScheduledThreadPoolExecutor pool;
+    //任务池
+    private final ConcurrentHashMap<String, ScheduledFuture<?>> taskFutures = new ConcurrentHashMap<>();
+
+    private TaskSchedule() {
+        pool = (ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(5);
+        pool.setRemoveOnCancelPolicy(true);
+    }
+
+    //单例
+    private static class TaskScheduleHolder {
+        private static final TaskSchedule instance = new TaskSchedule();
+    }
+
+    public static TaskSchedule getInstance() {
+        return TaskScheduleHolder.instance;
+    }
+
+    /**
+     * Submits a one-shot task that becomes enabled after the given delay.
+     *
+     * @param command the task to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @return a ScheduledFuture representing pending completion of
+     *         the task and whose {@code get()} method will return
+     *         {@code null} upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     */
+    public ScheduledFuture<?> runDelay(Runnable command,
+                                       long delay, TimeUnit unit){
+        if (pool!=null){
+            return pool.schedule(command, delay, unit);
+        }
+        return null;
+    }
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given period;
+     * that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param period the period between successive executions
+     * @param unit the time unit of the initialDelay and period parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     * @throws IllegalArgumentException if period less than or equal to zero
+     */
+    public ScheduledFuture<?> runAtFixedRate(Runnable command,
+                                  long initialDelay,
+                                  long period,
+                                  TimeUnit unit){
+        if (pool != null){
+            return pool.scheduleAtFixedRate(command, initialDelay, period, unit);
+        }
+        return null;
+    }
+
+    public ScheduledFuture<?> scheduleTask(@NotNull String taskName, @NotNull Runnable task, @NotNull Long startTime, Long period) {
+        if (pool != null){
+            ScheduledFuture<?> future = pool.scheduleAtFixedRate(task, startTime, period, TimeUnit.MILLISECONDS);
+            cancelTask(taskName);
+            this.taskFutures.put(taskName, future);
+            return future;
+        }
+        return null;
+    }
+
+    /**
+     * 取消任务
+     *
+     * @param taskName
+     */
+    public void cancelTask(String taskName) {
+        if (pool != null) {
+            ScheduledFuture<?> future = this.taskFutures.get(taskName);
+            if (future != null) {
+                future.cancel(true);
+            }
+            this.taskFutures.remove(taskName);
+        }
+    }
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given delay
+     * between the termination of one execution and the commencement of
+     * the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param delay the delay between the termination of one
+     * execution and the commencement of the next
+     * @param unit the time unit of the initialDelay and delay parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     * @throws IllegalArgumentException if delay less than or equal to zero
+     */
+    public ScheduledFuture<?> runWithFixedDelay(Runnable command,
+                                             long initialDelay,
+                                             long delay,
+                                             TimeUnit unit){
+        if (pool != null){
+            return pool.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+        }
+        return null;
+    }
+
+    public void shutDown(Integer seconds) {
+        if (pool != null) {
+            try {
+                pool.awaitTermination(seconds, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            pool.shutdown();
+        }
+    }
+
+    //测试
+    public static void main(String[] args) {
+        System.out.println(DateUtil.getDateline() + "     main " + Thread.currentThread().getId());
+        Runnable task1 = new Runnable() {
+            @Override
+            public void run() {
+                System.out.println(DateUtil.getDateline() + "     1 " + Thread.currentThread().getId());
+            }
+        };
+
+        Runnable task2 = new Runnable() {
+            @Override
+            public void run() {
+                System.out.println(DateUtil.getDateline() + "     2 " + Thread.currentThread().getId());
+            }
+        };
+
+        Runnable task3 = new Runnable() {
+            @Override
+            public void run() {
+                System.out.println(DateUtil.getDateline() + "     3 " + Thread.currentThread().getId());
+            }
+        };
+
+        ScheduledFuture<?> task1Result = TaskSchedule.getInstance().runAtFixedRate(task1,0, 1000, TimeUnit.MILLISECONDS);
+        ScheduledFuture<?> task2Result = TaskSchedule.getInstance().runAtFixedRate(task2,0, 1000, TimeUnit.MILLISECONDS);
+        ScheduledFuture<?> task3Result = TaskSchedule.getInstance().runAtFixedRate(task3,0, 1000, TimeUnit.MILLISECONDS);
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try{
+                    Thread.sleep(1000);
+                    task1Result.cancel(true);
+
+                    Thread.sleep(2000);
+                    task2Result.cancel(true);
+
+                    Thread.sleep(3000);
+                    task3Result.cancel(true);
+
+                    TaskSchedule.getInstance().runAtFixedRate(task1,0, 1000, TimeUnit.MILLISECONDS);
+
+                    Thread.currentThread().interrupt();
+                } catch (Exception ex){}
+            }
+        }).start();
+
+        TaskSchedule.getInstance().shutDown(10);
+    }
+}

+ 28 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TcpClient.java

@@ -1,7 +1,12 @@
 package com.wdkl.ncs.android.middleware.tcp;
 
+import com.alibaba.fastjson.JSONObject;
 import com.wdkl.ncs.android.middleware.common.Constant;
 import com.wdkl.ncs.android.middleware.common.MessageEvent;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpCallback;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpSendModel;
+import com.wdkl.ncs.android.middleware.tcp.util.DateUtil;
 
 import org.greenrobot.eventbus.EventBus;
 
@@ -149,6 +154,29 @@ public class TcpClient {
     }
 
     //发送消息,线程安全
+    public void sendTcp(TcpModel tcpModel, Boolean reSend, TcpCallback transaction) {
+        String tcpString = JSONObject.toJSONString(tcpModel);
+
+        if (reSend){
+            TcpSendModel model = new TcpSendModel();
+            model.setMsg(tcpString);
+            model.setTid(tcpModel.getTid());
+            model.setTs(DateUtil.getDateline());
+            //启动定时任务
+            tcpClientHandler.handleReSend(model);
+        }
+        sendMsg(tcpString, transaction);
+    }
+
+    //发送消息,线程安全
+    public synchronized void sendMsg(String content, TcpCallback transaction) {
+        //System.out.println("send tcp msg = [" + content + "]");
+        if (tcpClientHandler != null) {
+            tcpClientHandler.sendMsg(content, transaction);
+        }
+    }
+
+    //发送消息,线程安全
     public synchronized void sendMsg(String content){
         if (tcpClientHandler != null) {
             tcpClientHandler.sendMsg(content);

+ 135 - 12
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/TcpClientHandler.java

@@ -2,14 +2,21 @@ package com.wdkl.ncs.android.middleware.tcp;
 
 import android.util.Log;
 
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.base.Strings;
 import com.wdkl.ncs.android.middleware.common.Constant;
 import com.wdkl.ncs.android.middleware.common.MessageEvent;
 import com.wdkl.ncs.android.middleware.tcp.channel.DeviceChannel;
 import com.wdkl.ncs.android.middleware.tcp.channel.DeviceUtil;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpCallback;
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
+import com.wdkl.ncs.android.middleware.tcp.dto.TcpSendModel;
+import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
+import com.wdkl.ncs.android.middleware.tcp.util.DateUtil;
 
 import org.greenrobot.eventbus.EventBus;
 
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
 import io.netty.buffer.Unpooled;
@@ -34,6 +41,13 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
     //是否连接成功
     private static Boolean connected = false;
 
+    private Integer stopSendSeconds = 20;
+
+    //存储回调 callback, key: tid
+    private static ConcurrentHashMap<String, TcpCallback> trantCache = new ConcurrentHashMap<>();
+    //key: tid。用于重发
+    static ConcurrentHashMap<String, TcpSendModel> tcpSendCache = new ConcurrentHashMap<>();
+
     //连接成功执行的方法
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
@@ -52,6 +66,7 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
     @Override
     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
         super.channelInactive(ctx);
+        this.ctx = null;
         connected = false;
         Constant.TCP_CONNECTED = false;
         EventBus.getDefault().post(new MessageEvent(0, Constant.EVENT_TCP_STATE));
@@ -62,19 +77,74 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
     //读取String消息
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, String source) throws Exception {
-        if(source.equals("1")){
-            Log.i(TAG,"收到服务器返回的心跳 "+source);
-        }else {
-            TcpModel tcpModel = TcpModel.getModelByJson(source);
-
-            TcpModel responseTcpModel = DeviceChannel.handleTcpReceived(tcpModel);
-            if (responseTcpModel!=null){
-                ctx.writeAndFlush(responseTcpModel.toJson());
+
+        try {
+            //System.out.println("tcp msg = [" + source + "]");
+
+            if (source.equals("1")) {
+                Log.e(TAG, "收到服务器返回的心跳" + "source " + source);
             } else {
-                ReferenceCountUtil.release(source);
+                Log.i(TAG, "received msg: " + source);
+                TcpModel tcpModel = TcpModel.getModelByJson(source);
+                if (tcpModel != null) {
+                    //Log.i(TAG, "received type==" + tcpModel.getType() + ", action==" + tcpModel.getAction() + ", tid===" + tcpModel.getTid());
+                    switch (tcpModel.getType()) {
+                        case CALLBACK:
+                            //收到ack说明消息已到达服务器,可以取消重发,收到success说明消息正常处理
+                            if (tcpModel.getAction() == TcpAction.CallbackAction.ACK) {
+                                //服务器已收到tcp消息 收到ack不能删除缓存
+                                if (!Strings.isNullOrEmpty(tcpModel.getTid())) {
+                                    // 取消定时任务
+                                    tcpSendCache.remove(tcpModel.getTid());
+                                    TcpCallback transaction = trantCache.get(tcpModel.getTid());
+                                    if (transaction != null) {
+                                        transaction.onAck();
+                                    }
+                                }
+                            } else if (tcpModel.getAction() == TcpAction.CallbackAction.SUCCESS) {
+                                //回调成功
+                                if (!Strings.isNullOrEmpty(tcpModel.getTid())) {
+                                    TcpCallback transaction = trantCache.get(tcpModel.getTid());
+                                    if (transaction != null) {
+                                        JSONObject jsonObject = new JSONObject();
+                                        jsonObject.put(TcpCallback.CALLBACK, TcpCallback.CALLBACK_SUCCESS);
+                                        transaction.onSuccess(jsonObject);
+                                        trantCache.remove(tcpModel.getTid());
+                                    }
+                                }
+                            } else if (tcpModel.getAction() == TcpAction.CallbackAction.FAILED) {
+
+                                //回调失败
+                                if (!Strings.isNullOrEmpty(tcpModel.getTid())) {
+                                    TcpCallback transaction = trantCache.get(tcpModel.getTid());
+                                    if (transaction != null) {
+                                        JSONObject jsonObject = new JSONObject();
+                                        if (tcpModel.getData() != null) {
+                                            jsonObject.put(TcpCallback.CALLBACK, tcpModel.getData().toString());
+                                        } else {
+                                            jsonObject.put(TcpCallback.CALLBACK, TcpCallback.CALLBACK_FAIL);
+                                        }
+                                        transaction.onFailed(jsonObject);
+                                        trantCache.remove(tcpModel.getTid());
+                                    }
+                                }
+                            }
+                            break;
+
+                        default:
+                            //原来的方式处理
+                            TcpModel responseTcpModel = DeviceChannel.handleTcpReceived(tcpModel);
+                            if (responseTcpModel != null) {
+                                ctx.writeAndFlush(responseTcpModel.toJson());
+                            } else {
+                                ReferenceCountUtil.release(source);
+                            }
+                    }
+                }
             }
+        } catch (Exception ex) {
+            ex.printStackTrace();
         }
-
     }
 
     //写心跳包。没有消息发送时,每间隔一定时间会由此方法向服务端发送心跳
@@ -105,11 +175,64 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
 
     //发送消息,不直接调用些方法,调用TcpClient中的发送消息
     public void sendMsg(String msg){
-        if (ctx==null){
+        if (ctx == null) {
             System.out.println("ctx is null");
             return;
         }
-        System.out.println("wzlll: tcp msg====" + msg);
+
+        Log.i(TAG, "send tcp msg ==> " + msg);
         ctx.writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
     }
+
+    //使用带callback和tid方式发送消息
+    public synchronized boolean sendMsg(String msg, TcpCallback transaction){
+        if (ctx == null){
+            return false;
+        }
+
+        Log.i(TAG, "send tcp msg ==> " + msg + ", transaction ==> " + transaction);
+        //ctx.writeAndFlush(msg);
+        ctx.writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
+        if (transaction!=null) {
+            trantCache.put(transaction.getTid(), transaction);
+        }
+        return true;
+    }
+
+    //发送消息时缓存定时任务
+    public void handleReSend(TcpSendModel model){
+        tcpSendCache.put(model.getTid(), model);
+        TaskSchedule.getInstance().scheduleTask("TCP_MESSAGE_REPEAT" + model.getTid(), new Runnable() {
+            @Override
+            public void run() {
+                TcpSendModel m = tcpSendCache.get(model.getTid());
+                if (m != null){
+                    System.out.println("定时任务:" + m.getTid() + "...........");
+                    long time = DateUtil.getDateline() - m.getTs();
+                    //比对时间
+                    if (time < stopSendSeconds){
+                        //因为是重发,所以不需要再缓存 callback
+                        System.out.println("重发消息");
+                        sendMsg(model.getMsg(), null);
+                    } else { //超时处理
+                        //关闭定时任务,提示掉线?
+                        System.out.println("取消定时任务,提示掉线");
+                        TaskSchedule.getInstance().cancelTask("TCP_MESSAGE_REPEAT" + model.getTid());
+                        //这里可以执行失败的方法
+                        TcpCallback transaction = trantCache.get(model.getTid());
+                        if (transaction!=null){
+                            JSONObject jsonObject = new JSONObject();
+                            jsonObject.put(TcpCallback.CALLBACK, TcpCallback.CALLBACK_FAIL);
+                            transaction.onFailed(jsonObject);
+                        }
+                        trantCache.remove(model.getTid());
+                        tcpSendCache.remove(model.getTid());
+                    }
+                } else {    //缓存不存在,取消定时
+                    System.out.println("缓存不存在,取消定时");
+                    TaskSchedule.getInstance().cancelTask("TCP_MESSAGE_REPEAT" + model.getTid());
+                }
+            }
+        },5000L, 5000L);
+    }
 }

+ 4 - 26
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/DeviceChannel.java

@@ -22,43 +22,21 @@ public class DeviceChannel {
     public static TcpModel handleTcpReceived(TcpModel tcpModel){
         TcpModel responseTcpModel = null;
 
-        Log.d("wzlll", "received tcp model: " + tcpModel.toJson());
         switch (tcpModel.getType()){
-            case CALLBACK:
-                if(tcpModel.getAction()== TcpAction.CallbackAction.SUCCESS){
-                    //todo: 刷新呼叫记录列表
-                    EventBus.getDefault().post(new MessageEvent(tcpModel, EVENT_TCP_MSG));
-                }else if(tcpModel.getAction()== TcpAction.CallbackAction.FAILED){
-                    EventBus.getDefault().post(new MessageEvent(tcpModel, EVENT_TCP_MSG));
-                }
-                break;
             case VOICE:
                 if (tcpModel.getAction()==TcpAction.VoiceAction.CALL){ //语音呼入
                     //todo: 判断当前是否通话
                     // 当前正在通话中或有新的来电或正在呼叫,直接返回该状态给服务器
+                    InteractionVO interactionVO = new Gson().fromJson(tcpModel.getData().toString(), InteractionVO.class);
                     if (Constant.CALL_STATE != Constant.CALL_STANDBY){
-                        InteractionVO interactionVO = new Gson().fromJson(tcpModel.getData().toString(), InteractionVO.class);
-                        responseTcpModel = VoiceUtil.voiceCalling(Constant.DEVICE_ID, tcpModel.getFromId(), interactionVO.getId());
+                        responseTcpModel = VoiceUtil.voiceCalling(tcpModel.getTid(), tcpModel.getToId(), tcpModel.getFromId(), interactionVO.getId());
                         return responseTcpModel;
                     } else {
-                        //todo: 通话界面展现,data中服务器传过来呼入名称;从接口重新获取左侧数据
-                        // 当前待机状态,返回呼叫成功,并切换到呼叫界面
                         EventBus.getDefault().post(new MessageEvent(tcpModel, EVENT_TCP_MSG));
-                        //responseTcpModel = VoiceUtil.voiceSuccess(Constant.DEVICE_ID, tcpModel.getFromId());
-                        //return responseTcpModel;
+                        responseTcpModel = VoiceUtil.voiceSuccess(tcpModel.getTid(), tcpModel.getToId(), tcpModel.getFromId(), interactionVO);
+                        return responseTcpModel;
                     }
                 } else {
-                    //tcpModel.getAction()==TcpAction.VoiceAction.ACCEPT
-                    //todo: 通话中界面更新;建立数据通话
-                    //tcpModel.getAction()==TcpAction.VoiceAction.REJECT
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方拒绝并停留3秒,结束至正常界面;更新左侧
-                    //tcpModel.getAction()==TcpAction.VoiceAction.CALLING
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方占线并停留3秒,结束至正常界面;更新左侧
-                    //tcpModel.getAction()==TcpAction.VoiceAction.FAILED
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方离线并停留3秒,结束至正常界面;更新左侧
-                    //tcpModel.getAction()==TcpAction.VoiceAction.HANDOFF
-                    //todo: 清掉呼出的TcpModel,通话中界面更新 --- 显示对方已挂断并停留3秒,结束至正常界面;更新左侧
-
                     //交由后续处理
                     EventBus.getDefault().post(new MessageEvent(tcpModel, EVENT_TCP_MSG));
                 }

+ 1 - 1
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/DeviceUtil.java

@@ -10,7 +10,7 @@ import com.wdkl.ncs.android.middleware.tcp.enums.TcpType;
 
 public class DeviceUtil {
     public static TcpModel deviceConnect(String mac){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         DeviceConnectDTO connectDTO = new DeviceConnectDTO();
         connectDTO.setIdentification(mac);
         connectDTO.setHardware_version(Build.PRODUCT.toLowerCase());

+ 40 - 2
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/EventUtil.java

@@ -1,5 +1,7 @@
 package com.wdkl.ncs.android.middleware.tcp.channel;
 
+import com.google.common.base.Strings;
+import com.wdkl.ncs.android.middleware.model.vo.InteractionVO;
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpType;
@@ -13,7 +15,7 @@ public class EventUtil {
         Map map = new HashMap();
         map.put("id", keyId);
 
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.EVENT);
         tcpModel.setAction(TcpAction.EventAction.KEY_CLICK);
         tcpModel.setFromId(fromId);
@@ -22,7 +24,7 @@ public class EventUtil {
     }
 
     public static TcpModel eventResponse(Integer fromId, Integer toId, Integer eventId){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.EVENT);
         tcpModel.setAction(TcpAction.EventAction.RESPONSE);
         tcpModel.setFromId(fromId);
@@ -30,4 +32,40 @@ public class EventUtil {
         tcpModel.setData(eventId);
         return tcpModel;
     }
+
+    public static TcpModel eventReceived(TcpModel model){
+        //回复收到需要使用同一个tid
+        TcpModel tcpModel = new TcpModel();
+        if (!Strings.isNullOrEmpty(model.getTid())) {
+            tcpModel.setTid(model.getTid());
+        }
+        tcpModel.setType(TcpType.EVENT);
+        tcpModel.setAction(TcpAction.EventAction.RECEIVED);
+        tcpModel.setFromId(model.getFromId());
+        tcpModel.setToId(model.getToId());
+        tcpModel.setData(model.getData());
+        return tcpModel;
+    }
+
+
+    public static TcpModel cancelEvent(InteractionVO interactionVO){
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.EVENT);
+        tcpModel.setAction(TcpAction.EventAction.CANCEL);
+        tcpModel.setFromId(interactionVO.getFromDeviceId());
+        //tcpModel.setToId(model.getToId());
+        tcpModel.setData(interactionVO);
+        return tcpModel;
+    }
+
+    public static TcpModel eventCompleted(InteractionVO interactionVO){
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.EVENT);
+        tcpModel.setAction(TcpAction.EventAction.COMPLETED);
+        tcpModel.setFromId(interactionVO.getFromDeviceId());
+        tcpModel.setToId(interactionVO.getToDeviceId());
+        tcpModel.setData(interactionVO);
+        return tcpModel;
+    }
+
 }

+ 30 - 6
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/ImUtil.java

@@ -1,26 +1,50 @@
 package com.wdkl.ncs.android.middleware.tcp.channel;
 
+import com.google.common.base.Strings;
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpType;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class ImUtil {
-    public static TcpModel imMsg(Integer fromId, String msg){
-        TcpModel tcpModel = new TcpModel();
+    //tid1,fromId,data:{roleType:NURSE,filePath:pathUrl}
+    //带toId指定了目标设备的不用传roleType
+    public static TcpModel imMsg(Integer fromId, String filePath, String roleType){
+        Map map = new HashMap();
+        map.put("roleType", roleType);
+        map.put("filePath", filePath);
+
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.IM);
         tcpModel.setAction(TcpAction.IMAction.MSG);
         tcpModel.setFromId(fromId);
-        tcpModel.setData(msg);
+        tcpModel.setData(map);
         return tcpModel;
     }
 
-    public static TcpModel imRead(Integer fromId, Integer toId, Integer msg){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel imRead(Integer fromId, Integer toId, Integer msgId){
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.IM);
         tcpModel.setAction(TcpAction.IMAction.MSG_READ);
         tcpModel.setFromId(fromId);
         tcpModel.setToId(toId);
-        tcpModel.setData(msg);
+        tcpModel.setData(msgId);
+        return tcpModel;
+    }
+
+    public static TcpModel imReceived(TcpModel model){
+        //回复收到需要使用同一个tid
+        TcpModel tcpModel = new TcpModel();
+        if (!Strings.isNullOrEmpty(model.getTid())) {
+            tcpModel.setTid(model.getTid());
+        }
+        tcpModel.setType(TcpType.IM);
+        tcpModel.setAction(TcpAction.IMAction.RECEIVED);
+        tcpModel.setFromId(model.getFromId());
+        tcpModel.setToId(model.getToId());
+        tcpModel.setData(model.getData());
         return tcpModel;
     }
 }

+ 22 - 14
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/OtherUtil.java

@@ -7,16 +7,24 @@ import com.wdkl.ncs.android.middleware.tcp.enums.TcpType;
 
 public class OtherUtil {
     //分机SOS呼叫,不需要传toId
-    public static TcpModel sosCall(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel SOSCall(Integer fromId){
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.SOS);
         tcpModel.setAction(TcpAction.SOSAction.CALL);
         tcpModel.setFromId(fromId);
         return tcpModel;
     }
 
-    public static TcpModel sosCancel(Integer fromId, Integer toId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel RoomSOSCall(Integer fromId){
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.SOS);
+        tcpModel.setAction(TcpAction.SOSAction.ROOM_CALL);
+        tcpModel.setFromId(fromId);
+        return tcpModel;
+    }
+
+    public static TcpModel SOSCancel(Integer fromId, Integer toId){
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.SOS);
         tcpModel.setAction(TcpAction.SOSAction.CANCEL);
         tcpModel.setFromId(fromId);
@@ -25,7 +33,7 @@ public class OtherUtil {
     }
 
     public static TcpModel nursing(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.SIDE);
         tcpModel.setAction(TcpAction.SideAction.NURSING);
         tcpModel.setFromId(fromId);
@@ -33,7 +41,7 @@ public class OtherUtil {
     }
 
     public static TcpModel nursingEnd(Integer fromId, Integer interactionId){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.SIDE);
         tcpModel.setAction(TcpAction.SideAction.NURSING_END);
         tcpModel.setFromId(fromId);
@@ -42,7 +50,7 @@ public class OtherUtil {
     }
 
     public static TcpModel reInforce(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.REINFORCE);
         tcpModel.setAction(TcpAction.ReinforceAction.CALL);
         tcpModel.setFromId(fromId);
@@ -51,12 +59,17 @@ public class OtherUtil {
 
     //发送sos相关tcp
     public static void sendSosCall(Integer fromId) {
-        TcpModel tcpModel = OtherUtil.sosCall(fromId);
+        TcpModel tcpModel = OtherUtil.SOSCall(fromId);
         TcpClient.getInstance().sendMsg(tcpModel.toJson());
     }
 
     public static void cancelSosCall(Integer fromId, Integer toId) {
-        TcpModel tcpModel = OtherUtil.sosCancel(fromId, toId);
+        TcpModel tcpModel = OtherUtil.SOSCancel(fromId, toId);
+        TcpClient.getInstance().sendMsg(tcpModel.toJson());
+    }
+
+    public static void sendReinforce(Integer fromId) {
+        TcpModel tcpModel = reInforce(fromId);
         TcpClient.getInstance().sendMsg(tcpModel.toJson());
     }
 
@@ -69,9 +82,4 @@ public class OtherUtil {
         TcpModel tcpModel = OtherUtil.nursingEnd(fromId, interactionId);
         TcpClient.getInstance().sendMsg(tcpModel.toJson());
     }
-
-    public static void sendReinforce(Integer fromId) {
-        TcpModel tcpModel = reInforce(fromId);
-        TcpClient.getInstance().sendMsg(tcpModel.toJson());
-    }
 }

+ 76 - 20
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/channel/VoiceUtil.java

@@ -1,5 +1,6 @@
 package com.wdkl.ncs.android.middleware.tcp.channel;
 
+import com.wdkl.ncs.android.middleware.model.vo.InteractionVO;
 import com.wdkl.ncs.android.middleware.tcp.TcpClient;
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
@@ -9,25 +10,64 @@ import java.util.HashMap;
 import java.util.Map;
 
 public class VoiceUtil {
-    //分机呼叫,不需要传toId
-    public static TcpModel voiceCall(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+    //tid1,fromId,data:{roleType:NURSE}
+    //带toId指定了目标设备的不用传roleType,否则需要
+    public static TcpModel voiceCall(Integer fromId, String roleType){
+        Map map = new HashMap();
+        map.put("roleType", roleType);
+
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.CALL);
         tcpModel.setFromId(fromId);
+        tcpModel.setData(map);
         return tcpModel;
     }
 
-    public static TcpModel videoCall(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceCallBed(Integer fromId, Integer toId){
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.VOICE);
+        tcpModel.setAction(TcpAction.VoiceAction.CALL);
+        tcpModel.setFromId(fromId);
+        tcpModel.setToId(toId);
+        return tcpModel;
+    }
+
+    public static TcpModel videoCall(Integer fromId, String roleType){
+        Map map = new HashMap();
+        map.put("roleType", roleType);
+
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.VCALL);
         tcpModel.setFromId(fromId);
+        tcpModel.setData(map);
         return tcpModel;
     }
 
-    public static TcpModel voiceAccept(Integer fromId, Integer toId, Integer interactionId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel videoCallBed(Integer fromId, Integer toId){
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.VOICE);
+        tcpModel.setAction(TcpAction.VoiceAction.VCALL);
+        tcpModel.setFromId(fromId);
+        tcpModel.setToId(toId);
+        return tcpModel;
+    }
+
+    public static TcpModel voiceHCall(Integer fromId, String roleType){
+        Map map = new HashMap();
+        map.put("roleType", roleType);
+
+        TcpModel tcpModel = new TcpModel(null);
+        tcpModel.setType(TcpType.VOICE);
+        tcpModel.setAction(TcpAction.VoiceAction.HCALL);
+        tcpModel.setFromId(fromId);
+        tcpModel.setData(map);
+        return tcpModel;
+    }
+
+    public static TcpModel voiceAccept(String tid, Integer fromId, Integer toId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.ACCEPT);
         tcpModel.setFromId(fromId);
@@ -38,8 +78,8 @@ public class VoiceUtil {
         return tcpModel;
     }
 
-    public static TcpModel voiceReject(Integer fromId, Integer toId, Integer interactionId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceReject(String tid, Integer fromId, Integer toId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.REJECT);
         tcpModel.setFromId(fromId);
@@ -50,8 +90,8 @@ public class VoiceUtil {
         return tcpModel;
     }
 
-    public static TcpModel voiceCalling(Integer fromId, Integer toId, Integer interactionId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceCalling(String tid, Integer fromId, Integer toId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.CALLING);
         tcpModel.setFromId(fromId);
@@ -62,16 +102,31 @@ public class VoiceUtil {
         return tcpModel;
     }
 
-    public static TcpModel voiceCancel(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceCancel(String tid, Integer fromId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.CANCEL);
         tcpModel.setFromId(fromId);
+        if (interactionId != -1) {
+            tcpModel.setData(interactionId);
+        }
         return tcpModel;
     }
 
-    public static TcpModel voiceHandoff(Integer fromId, Integer toId, Integer interactionId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceCancelBed(String tid, Integer fromId, Integer toId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
+        tcpModel.setType(TcpType.VOICE);
+        tcpModel.setAction(TcpAction.VoiceAction.CANCEL);
+        tcpModel.setFromId(fromId);
+        tcpModel.setToId(toId);
+        if (interactionId != -1) {
+            tcpModel.setData(interactionId);
+        }
+        return tcpModel;
+    }
+
+    public static TcpModel voiceHandoff(String tid, Integer fromId, Integer toId, Integer interactionId){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.HANDOFF);
         tcpModel.setFromId(fromId);
@@ -84,17 +139,18 @@ public class VoiceUtil {
         return tcpModel;
     }
 
-    public static TcpModel voiceSuccess(Integer fromId, Integer toId){
-        TcpModel tcpModel = new TcpModel();
+    public static TcpModel voiceSuccess(String tid, Integer fromId, Integer toId, InteractionVO interaction){
+        TcpModel tcpModel = new TcpModel(tid);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.SUCCESS);
         tcpModel.setFromId(fromId);
         tcpModel.setToId(toId);
+        tcpModel.setData(interaction);
         return tcpModel;
     }
 
     public static TcpModel voiceCancelByDoor(Integer fromId){
-        TcpModel tcpModel = new TcpModel();
+        TcpModel tcpModel = new TcpModel(null);
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.CANCEL_BY_DOOR);
         tcpModel.setFromId(fromId);
@@ -105,7 +161,7 @@ public class VoiceUtil {
      ************************* 发送呼叫相关TCP *********************************
     ***************************************************************************/
     //呼叫分机
-    public static void startAudioCallBed(Integer fromId, Integer toId) {
+    /*public static void startAudioCallBed(Integer fromId, Integer toId) {
         TcpModel tcpModel = new TcpModel();
         tcpModel.setType(TcpType.VOICE);
         tcpModel.setAction(TcpAction.VoiceAction.CALL);
@@ -168,7 +224,7 @@ public class VoiceUtil {
     public static void rejectAudioCall(Integer fromId, Integer toId, Integer interactionId) {
         TcpModel tcpModel = VoiceUtil.voiceReject(fromId, toId, interactionId);
         TcpClient.getInstance().sendMsg(tcpModel.toJson());
-    }
+    }*/
 
     //门口机取消分机呼叫
     public static void cancelCallByDoor(Integer fromId) {

+ 37 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpCallback.java

@@ -0,0 +1,37 @@
+package com.wdkl.ncs.android.middleware.tcp.dto;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * 描述
+ *
+ * @author allen
+ * 2022-11-01 12:10
+ */
+public class TcpCallback {
+    public static final String CALLBACK = "CALLBACK";
+    public static final String CALLBACK_SUCCESS = "send success";
+    public static final String CALLBACK_FAIL = "send fail";
+
+    private String tid;
+
+    public TcpCallback(String tid){
+        this.tid = tid;
+    }
+
+    public void onSuccess(JSONObject jsonObject){
+
+    }
+
+    public void onFailed(JSONObject jsonObject){
+
+    }
+
+    public void onAck(){
+
+    }
+
+    public String getTid() {
+        return tid;
+    }
+}

+ 25 - 67
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpModel.java

@@ -9,6 +9,8 @@ import com.wdkl.ncs.android.middleware.model.vo.InteractionVO;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction;
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpType;
 
+import org.bson.types.ObjectId;
+
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
@@ -20,6 +22,7 @@ import java.util.Map;
  * 2021-03-30 11:49
  */
 public class TcpModel implements Serializable {
+    private String tid;
     /**
      * TCP传输对象的类型
      */
@@ -43,6 +46,26 @@ public class TcpModel implements Serializable {
      */
     private Object data;
 
+    public TcpModel(){
+        //this.tid = new ObjectId().toString();
+    }
+
+    public TcpModel(String tid){
+        if (Strings.isNullOrEmpty(tid)) {
+            this.tid = new ObjectId().toString();
+        } else {
+            this.tid = tid;
+        }
+    }
+
+    public String getTid() {
+        return tid;
+    }
+
+    public void setTid(String tid) {
+        this.tid = tid;
+    }
+
     public TcpType getType() {
         return type;
     }
@@ -94,6 +117,7 @@ public class TcpModel implements Serializable {
         TcpModel tcpModel = new TcpModel();
 
         JSONObject jsonObject = JSON.parseObject(tcpModelJsonString);
+        String tid = jsonObject.getString("tid");
         String type = jsonObject.getString("type");
         String action = jsonObject.getString("action");
         Integer fromId = jsonObject.getInteger("fromId");
@@ -141,6 +165,7 @@ public class TcpModel implements Serializable {
                 break;
         }
 
+        tcpModel.setTid(tid);
         tcpModel.setType(tcpType);
         tcpModel.setAction(tcpAction);
         tcpModel.setToId(toId);
@@ -150,71 +175,4 @@ public class TcpModel implements Serializable {
         return tcpModel;
     }
 
-    public static String callbackSuccess(){
-        TcpModel tcpModel = new TcpModel();
-        tcpModel.setType(TcpType.CALLBACK);
-        tcpModel.setAction(TcpAction.CallbackAction.SUCCESS);
-        return tcpModel.toJson();
-    }
-
-    public static String callbackFailed(){
-        TcpModel tcpModel = new TcpModel();
-        tcpModel.setType(TcpType.CALLBACK);
-        tcpModel.setAction(TcpAction.CallbackAction.FAILED);
-        return tcpModel.toJson();
-    }
-
-    public static String refresh() {
-        TcpModel tcpModel = new TcpModel();
-        tcpModel.setType(TcpType.DATA);
-        tcpModel.setAction(TcpAction.DataAction.REFRESH);
-        return tcpModel.toJson();
-    }
-
-
-    public static String interaction() {
-        TcpModel tcpModel = new TcpModel();
-        tcpModel.setType(TcpType.DATA);
-        tcpModel.setAction(TcpAction.DataAction.INTERACTION);
-        return tcpModel.toJson();
-    }
-
-    /**
-     * 示例
-     * @param args
-     */
-    public static void main(String[] args) {
-        //创建对象示例
-        TcpModel tcpModel = new TcpModel();
-        tcpModel.type = TcpType.VOICE;
-        tcpModel.action = TcpAction.VoiceAction.CALL;
-
-        Map map = new HashMap();
-
-        DeviceDO deviceDO = new DeviceDO();
-        deviceDO.setCode("123");
-        deviceDO.setEthMac("abcd");
-        map.put("device",deviceDO);
-
-        FrameDO frameDO = new FrameDO();
-        frameDO.setName("ok");
-        map.put("frame",frameDO);
-
-        tcpModel.setData(map);
-
-        System.out.println("enum show === " + tcpModel.action.getDescription() + " -- " + tcpModel.action.getName());
-
-        //要传输的json字符串
-        String jsonStr = tcpModel.toJson();
-        System.out.println("json show === " + jsonStr);
-
-        //获利传输的JSON字符串,转换为对象
-        TcpModel dTcpModel = TcpModel.getModelByJson(jsonStr);
-        //数据反转
-        String dataString = dTcpModel.getData().toString();
-        JSONObject dataJSON = JSON.parseObject(dataString);
-        DeviceDO dDeviceDO = JSON.parseObject(dataJSON.getString("device"), DeviceDO.class);
-
-        System.out.println("json de show === " + dTcpModel.action + " -- " + dDeviceDO.getEthMac());
-    }
 }

+ 49 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/dto/TcpSendModel.java

@@ -0,0 +1,49 @@
+package com.wdkl.ncs.android.middleware.tcp.dto;
+
+import java.io.Serializable;
+
+/**
+ * 描述
+ *
+ * @author allen
+ * 2022-11-28 11:23
+ */
+public class TcpSendModel implements Serializable {
+    private String tid;
+    private String msg;
+    //第一次发出的时间戳,比对一定时间后清除缓存
+    private Long ts;
+
+    @Override
+    public String toString() {
+        return "TcpSendModel{" +
+                "tid='" + tid + '\'' +
+                ", msg='" + msg + '\'' +
+                ", ts=" + ts +
+                '}';
+    }
+
+    public String getTid() {
+        return tid;
+    }
+
+    public void setTid(String tid) {
+        this.tid = tid;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Long getTs() {
+        return ts;
+    }
+
+    public void setTs(Long ts) {
+        this.ts = ts;
+    }
+}

+ 106 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/enums/RoleTypeEnum.java

@@ -0,0 +1,106 @@
+package com.wdkl.ncs.android.middleware.tcp.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.wdkl.ncs.android.middleware.model.dos.RoleDO;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author
+ * @title: Vothin
+ * @projectName nc
+ * @date 2021/5/1910:29
+ */
+public enum RoleTypeEnum {
+    ADMINISTRATORS(1, "管理员"),
+    DOCTOR(2, "医生"),
+    NURSE(3, "护士"),
+    WORKER(4, "护工"),
+    NURSE_SUPERVISOR(5, "护士主管"),
+    DIETITIAN(6, "营养师"),
+    HOUSEKEEPER(7, "管家"),
+    NURSE_HEAD(8, "护士组长"),
+    LIFE_ASSISTANT(9, "生活助理");
+    private final int value;
+    private final String typeName;
+
+
+    RoleTypeEnum(int value, String typeName) {
+        this.value = value;
+        this.typeName = typeName;
+    }
+
+    public int value() {
+        return this.value;
+    }
+
+    public String typeName() {
+        return this.typeName;
+    }
+
+    /**
+     * 通过typeName 转换成枚举
+     *
+     * @param typeName
+     * @return
+     */
+    public static RoleTypeEnum parse(String typeName) {
+        RoleTypeEnum[] values = RoleTypeEnum.values();
+        for (RoleTypeEnum value : values) {
+            if (value.typeName().equals(typeName)) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 通过value值转换成枚举
+     *
+     * @param value
+     * @return
+     */
+    public static RoleTypeEnum parse(int value) {
+        RoleTypeEnum[] values = RoleTypeEnum.values();
+        for (RoleTypeEnum roleTypeEnum : values) {
+            if (roleTypeEnum.value() == value) {
+                return roleTypeEnum;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * 把角色DO转换为 RoleTypeEnum
+     * @param roleDO
+     * @return
+     */
+
+    public static RoleTypeEnum parse(RoleDO roleDO) {
+        RoleTypeEnum[] values = RoleTypeEnum.values();
+        for (RoleTypeEnum roleTypeEnum : values) {
+            if (roleTypeEnum.name().equals(roleDO.getRoleType())) {
+                return roleTypeEnum;
+            }
+        }
+        return null;
+    }
+
+
+    public static List getNames(){
+        RoleTypeEnum[] values = RoleTypeEnum.values();
+
+        return Arrays.stream(values).map(p-> {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("key",p.name());
+            jsonObject.put("typeName",p.typeName());
+            return jsonObject;
+        }).collect(Collectors.toList());
+    }
+
+
+
+}

+ 57 - 6
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/enums/TcpAction.java

@@ -14,6 +14,7 @@ public interface TcpAction {
     String getDescription();
 
     enum CallbackAction implements TcpAction {
+        ACK("反馈"),
         SUCCESS("同步"),
         FAILED("失败"),
         NO_MATCH("没有匹配");
@@ -88,7 +89,7 @@ public interface TcpAction {
         HANDOFF("挂断"),
         CANCEL("取消"),
         PCALLING("已经通话中"),
-        VOICE_OFF("通话被接听"),
+        VOICE_OFF("通话被其他设备处理"),
         RS485CALL("485界面发起呼叫"),
         RS485CANCEL("485界面呼叫取消"),
         RS485CANCEL_BY_DOOR("485门口机取消房间内的呼叫"),
@@ -104,6 +105,7 @@ public interface TcpAction {
         GAINED("呼叫被应答"),
         HCALL("手柄呼叫"),
         HRESPONSE("响应手柄"),
+        HRESPONSED("响应过手柄了"),
         NO_MATCH("没有匹配");
 
 
@@ -174,8 +176,9 @@ public interface TcpAction {
 
 
     enum SOSAction implements TcpAction {
-        CALL("紧急呼叫"),
-        CANCEL("取消"),
+        CALL("紧急呼叫"),   //1
+        CANCEL("取消"),   //1
+        CANCELED("已取消"),    //1
         TRANSFER("转接"),
         ALARM_TEST("测试报警"),
         ALARM_INTRUSION("侵入报警"),
@@ -196,6 +199,12 @@ public interface TcpAction {
         ALARM_VITAL("体征报警"),
         AlARM_BUTTON("紧急按钮"),
         ALARM_FALL_RADAR("跌到报警"),
+        ALARM_INFUSION_RADAR("输液报警"),
+        ROOM_CALL("房间紧急呼叫"),    //1
+        OTHER_CALL("其他紧急呼叫"),   //1
+        RECEIVED("客户端收到确认"),
+        // 当设备在科室级时用这个PART_USER_CALL,比如:用户手环
+        PART_USER_CALL("用户紧急呼叫"),   //
         NO_MATCH("没有匹配");
 
         private final String description;
@@ -319,7 +328,9 @@ public interface TcpAction {
     }
 
     enum DeviceAction implements TcpAction {
-        RESTART("重启"),
+        RESTART("重启APP"),
+        REBOOT("重启机器"),
+        OPEN_DEBUG("打开网络调试"),
         CONNECT("连接"),
         APP_UPDATE("APP更新"),
         DEVICE_REFRESH("设备刷新"),
@@ -327,6 +338,8 @@ public interface TcpAction {
         DEVICE_CHANGE("设备更换"),
         USER_CHANGE("用户绑定"),
         SERVER_CHANGE("设备ip地址更换"),
+        S485_POWER_RESET("485控制版复位电路"),
+        S485_POWER_RESET_SUCCESS("485控制版复位电路成功"),
         NO_MATCH("没有匹配");
 
         private final String description;
@@ -355,13 +368,14 @@ public interface TcpAction {
 
     enum EventAction implements TcpAction {
         KEY_CLICK("按键事件"),
-        RESPONSE("已响应"),
+        RESPONSE("响应"),
+        RESPONSED("已响应"),
         RECEIVED("接收端收到确认"),
         CANCEL("取消"),
         CANCEL_CONFIRM("接收端确认收到取消"),
+        NO_TARGET("没有目标设备"),
         COMPLETED("完成"),
         NO_MATCH("没有匹配");
-
         private final String description;
         EventAction(String description){
             this.description = description;
@@ -578,4 +592,41 @@ public interface TcpAction {
             return userOptionEnum == null ? NO_MATCH :userOptionEnum;
         }
     }
+
+    /**
+     * 433相关action
+      */
+    enum S433Action implements TcpAction {
+        CALL("呼叫"),
+        SOS_CALL("紧急呼叫"),
+        CANCEL("取消"),
+        SYNC_TIME("同步时间"),
+        DATA("同步数据"),
+        EXIST("调试"),
+        ACK("返回"),
+        NO_MATCH("没有匹配");
+
+        private final String description;
+        S433Action(String description){
+            this.description = description;
+        }
+        public String getDescription() {
+            return description;
+        }
+
+        public String getName(){
+            return this.name();
+        }
+
+        private final static Map<String , S433Action> ENUM_MAP = new HashMap<String, S433Action>();
+        static {
+            for(S433Action v : values()) {
+                ENUM_MAP.put(v.toString() , v);
+            }
+        }
+        public static S433Action fromString(String v) {
+            S433Action userOptionEnum = ENUM_MAP.get(v);
+            return userOptionEnum == null ? NO_MATCH :userOptionEnum;
+        }
+    }
 }

+ 483 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/tcp/util/DateUtil.java

@@ -0,0 +1,483 @@
+package com.wdkl.ncs.android.middleware.tcp.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * 日期相关的操作
+ *
+ * @author Dawei
+ */
+
+@SuppressWarnings({"AlibabaCollectionInitShouldAssignCapacity", "AlibabaUndefineMagicConstant"})
+public class DateUtil {
+    /**
+     * 一天的秒数
+     */
+    public static final long ONE_DAY = 86400;
+
+    /**
+     * 获取当前格式化后的时间
+     * @return
+     */
+    public static String formatNow() {
+        return DateUtil.toString(new Date(), "yyyy-MM-dd HH:mm:ss");
+    }
+    /**
+     * 当天的开始时间
+     *
+     * @return
+     */
+    public static long startOfTodDay() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 将 Sun Apr 15 04:12:39 CST 2018 格式的时间转换为时间戳
+     *
+     * @param dateFormat Sun Apr 15 04:12:39 CST 2018 格式的时间
+     * @return 时间戳
+     */
+    public static long getFormatDate(String dateFormat) {
+        try {
+            SimpleDateFormat sdf1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
+
+            return sdf1.parse(dateFormat).getTime() / 1000;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    public static long startOfDay(String s) {
+        Date date = null;
+        Calendar calendar= Calendar.getInstance();
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            date = simpleDateFormat.parse(s);
+            calendar.setTime(date);
+        } catch (Exception e) {
+        }
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        long start = calendar.getTime().getTime()/1000;
+        return start;
+    }
+
+    public static long endOfDay(String s) {
+        Date date = null;
+        Calendar calendar= Calendar.getInstance();
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            date = simpleDateFormat.parse(s);
+            calendar.setTime(date);
+        } catch (Exception e) {
+        }
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        long start = calendar.getTime().getTime()/1000;
+        return start;
+    }
+
+
+
+    /**
+     * 当天的结束时间
+     *
+     * @return
+     */
+    public static long endOfTodDay() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 昨天的开始时间
+     *
+     * @return
+     */
+    public static long startOfyesterday() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.add(Calendar.DATE, -1);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 昨天的结束时间
+     *
+     * @return
+     */
+    public static long endOfyesterday() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        calendar.add(Calendar.DATE, -1);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 某天的开始时间
+     *
+     * @param dayUntilNow 距今多少天以前
+     * @return 时间戳
+     */
+    public static long startOfSomeDay(int dayUntilNow) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        calendar.add(Calendar.DATE, -dayUntilNow);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 某天的开始时间
+     *
+     * @param dayUntilNow 距今多少天以后
+     * @return 时间戳
+     */
+    public static long endOfSomeDay(int dayUntilNow) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        calendar.add(Calendar.DATE, +dayUntilNow);
+        Date date = calendar.getTime();
+        return date.getTime() / 1000;
+    }
+
+    /**
+     * 某天的年月日
+     *
+     * @param dayUntilNow 距今多少天以前
+     * @return 年月日map key为 year month day
+     */
+    public static Map<String, Object> getYearMonthAndDay(int dayUntilNow) {
+
+        Map<String, Object> map = new HashMap<String, Object>(3);
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        calendar.add(Calendar.DATE, -dayUntilNow);
+        map.put("year", calendar.get(Calendar.YEAR));
+        map.put("month", calendar.get(Calendar.MONTH) + 1);
+        map.put("day", calendar.get(Calendar.DAY_OF_MONTH));
+        return map;
+    }
+
+    /**
+     * 将一个字符串转换成日期格式
+     *
+     * @param date
+     * @param pattern
+     * @return
+     */
+    public static Date toDate(String date, String pattern) {
+        if ("".equals("" + date)) {
+            return null;
+        }
+        if (pattern == null) {
+            pattern = "yyyy-MM-dd";
+        }
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        Date newDate = new Date();
+        try {
+            newDate = sdf.parse(date);
+
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return newDate;
+    }
+
+    /**
+     * 获取上个月的开始结束时间
+     *
+     * @return
+     */
+    public static Long[] getLastMonth() {
+        // 取得系统当前时间
+        Calendar cal = Calendar.getInstance();
+        int year = cal.get(Calendar.YEAR);
+        int month = cal.get(Calendar.MONTH) + 1;
+
+        // 取得系统当前时间所在月第一天时间对象
+        cal.set(Calendar.DAY_OF_MONTH, 1);
+
+        // 日期减一,取得上月最后一天时间对象
+        cal.add(Calendar.DAY_OF_MONTH, -1);
+
+        // 输出上月最后一天日期
+        int day = cal.get(Calendar.DAY_OF_MONTH);
+
+        String months = "";
+        String days = "";
+
+        if (month > 1) {
+            month--;
+        } else {
+            year--;
+            month = 12;
+        }
+        if (!(String.valueOf(month).length() > 1)) {
+            months = "0" + month;
+        } else {
+            months = String.valueOf(month);
+        }
+        if (!(String.valueOf(day).length() > 1)) {
+            days = "0" + day;
+        } else {
+            days = String.valueOf(day);
+        }
+        String firstDay = "" + year + "-" + months + "-01";
+        String lastDay = "" + year + "-" + months + "-" + days + " 23:59:59";
+
+        Long[] lastMonth = new Long[2];
+        lastMonth[0] = DateUtil.getDateline(firstDay);
+        lastMonth[1] = DateUtil.getDateline(lastDay, "yyyy-MM-dd HH:mm:ss");
+
+        return lastMonth;
+    }
+
+    public static Long[] getMonthStartEnd(String year, String month){
+        Integer monthInt = Integer.parseInt(month);
+        if (monthInt<0 || monthInt>12){
+            return null;
+        }
+
+        Date date = null;
+        Calendar cal= Calendar.getInstance();
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
+        try {
+            date = simpleDateFormat.parse(year+'-'+month);
+            cal.setTime(date);
+        } catch (Exception e) {
+        }
+
+        // 输出下月第一天日期
+        int notMonth = monthInt + 1;
+        // 取得系统当前时间所在月第一天时间对象
+        cal.set(Calendar.DAY_OF_MONTH, 1);
+
+        // 日期减一,取得上月最后一天时间对象
+        cal.add(Calendar.DAY_OF_MONTH, -1);
+        cal.set(Calendar.MILLISECOND, 0);
+
+        //long start = cal.getTime().getTime()/1000;
+
+        String months = "";
+        String nextMonths = "";
+
+        if (!(String.valueOf(monthInt).length() > 1)) {
+            months = "0" + monthInt;
+        } else {
+            months = String.valueOf(monthInt);
+        }
+        if (!(String.valueOf(notMonth).length() > 1)) {
+            nextMonths = "0" + notMonth;
+        } else {
+            nextMonths = String.valueOf(notMonth);
+        }
+        String firstDay = "" + year + "-" + months + "-01 00:00:00";
+        String lastDay = "" + year + "-" + nextMonths + "-01 00:00:00";
+        Long[] currentMonth = new Long[2];
+        currentMonth[0] = DateUtil.getDateline(firstDay,"yyyy-MM-dd HH:mm:ss");
+        currentMonth[1] = DateUtil.getDateline(lastDay,"yyyy-MM-dd HH:mm:ss");
+
+        return currentMonth;
+    }
+
+    /**
+     * 获取当月的开始结束时间
+     *
+     * @return
+     */
+    public static Long[] getCurrentMonth() {
+        // 取得系统当前时间
+        Calendar cal = Calendar.getInstance();
+        int year = cal.get(Calendar.YEAR);
+        int month = cal.get(Calendar.MONTH) + 1;
+        // 输出下月第一天日期
+        int notMonth = cal.get(Calendar.MONTH) + 2;
+        // 取得系统当前时间所在月第一天时间对象
+        cal.set(Calendar.DAY_OF_MONTH, 1);
+
+        // 日期减一,取得上月最后一天时间对象
+        cal.add(Calendar.DAY_OF_MONTH, -1);
+
+        String months = "";
+        String nextMonths = "";
+
+        if (!(String.valueOf(month).length() > 1)) {
+            months = "0" + month;
+        } else {
+            months = String.valueOf(month);
+        }
+        if (!(String.valueOf(notMonth).length() > 1)) {
+            nextMonths = "0" + notMonth;
+        } else {
+            nextMonths = String.valueOf(notMonth);
+        }
+        String firstDay = "" + year + "-" + months + "-01";
+        String lastDay = "" + year + "-" + nextMonths + "-01";
+        Long[] currentMonth = new Long[2];
+        currentMonth[0] = DateUtil.getDateline(firstDay);
+        currentMonth[1] = DateUtil.getDateline(lastDay);
+
+        return currentMonth;
+    }
+
+    /**
+     * 获取某年开始结束时间
+     *
+     * @return
+     */
+    public static Long[] getYearTime(Integer year) {
+
+
+        Calendar firstCal = Calendar.getInstance();
+        firstCal.set(Calendar.YEAR, year - 1);
+        firstCal.set(Calendar.MONTH, Calendar.DECEMBER);
+        firstCal.set(Calendar.DATE, 31);
+
+        Calendar lastCal = Calendar.getInstance();
+        lastCal.set(Calendar.YEAR, year);
+        lastCal.set(Calendar.MONTH, Calendar.DECEMBER);
+        lastCal.set(Calendar.DATE, 31);
+
+        Long[] yearTime = new Long[2];
+        yearTime[0] = firstCal.getTime().getTime() / 1000;
+        yearTime[1] = lastCal.getTime().getTime() / 1000;
+
+        return yearTime;
+    }
+
+    /**
+     * 把日期转换成字符串型
+     *
+     * @param date
+     * @param pattern
+     * @return
+     */
+    public static String toString(Date date, String pattern) {
+        if (date == null) {
+            return "";
+        }
+        if (pattern == null) {
+            pattern = "yyyy-MM-dd";
+        }
+        String dateString = "";
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        try {
+            dateString = sdf.format(date);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return dateString;
+    }
+
+    public static String toString(Long time, String pattern) {
+        if (time > 0) {
+            if (time.toString().length() == 10) {
+                time = time * 1000;
+            }
+            Date date = new Date(time);
+            String str = DateUtil.toString(date, pattern);
+            return str;
+        }
+        return "";
+    }
+
+    /**
+     * 为了方便mock 设置此属性
+     * 如果设置了此属性,则回直接返回设置的值
+     */
+    public static Long mockDate;
+
+    public static long getDateline() {
+        if (mockDate != null) {
+            return mockDate;
+        }
+        return System.currentTimeMillis() / 1000;
+    }
+
+    /**
+     * 判断当前时间是否在某个时间范围
+     *
+     * @param start 开始时间,以秒为单位的时间戳
+     * @param end   结束时间,以秒为单位的时间戳
+     * @return 是否在范围内
+     */
+    public static boolean inRangeOf(long start, long end) {
+        long now = getDateline();
+        return start <= now && end >= now;
+    }
+
+    public static long getDateline(String date) {
+        return toDate(date, "yyyy-MM-dd").getTime() / 1000;
+    }
+
+    public static long getDateHaveHour(String date) {
+        return toDate(date, "yyyy-MM-dd HH").getTime() / 1000;
+    }
+
+    public static long getDateline(String date, String pattern) {
+        return toDate(date, pattern).getTime() / 1000;
+    }
+
+    /**
+     * 查当前日期是一周中的星期几
+     * @return 1=Sunday,,,7=Saturday
+     */
+    public static long getDayOfWeek(Date date){
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        return cal.get(Calendar.DAY_OF_WEEK);// 1=Sunday,,,7=Saturday
+    }
+
+    public static long getDayOfWeekForMonBegin(Date date){
+        long week=getDayOfWeek(date);
+         if(week== Calendar.SUNDAY)return 7;
+         else return week-1;
+    }
+
+    public static String getNowStrForRs485(){
+        Date date = new Date();
+        String nowString = DateUtil.toString(date, "yyyy-MM-dd HH:mm:ss");
+        nowString += " " + getDayOfWeekForMonBegin(date);
+        return nowString;
+    }
+
+}