BusinessManager.kt 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283
  1. package com.grkj.iscs_mars
  2. //todo 所有蓝牙包替换com.clj. -> com.clj.
  3. import android.bluetooth.BluetoothGattCharacteristic
  4. import android.content.Context
  5. import android.content.Intent
  6. import androidx.appcompat.app.AppCompatActivity
  7. import androidx.lifecycle.MutableLiveData
  8. import com.google.gson.Gson
  9. import com.grkj.iscs_mars.ble.BleBean
  10. import com.grkj.iscs_mars.ble.BleCmdManager
  11. import com.grkj.iscs_mars.ble.BleConnectionManager
  12. import com.grkj.iscs_mars.ble.BleConst
  13. import com.grkj.iscs_mars.ble.BleConst.STATUS_READY
  14. import com.grkj.iscs_mars.ble.BleConst.STATUS_WORK
  15. import com.grkj.iscs_mars.ble.BleReturnDispatcher
  16. import com.grkj.iscs_mars.ble.BleSendDispatcher
  17. import com.grkj.iscs_mars.ble.BleUtil
  18. import com.grkj.iscs_mars.ble.CustomBleWriteCallback
  19. import com.grkj.iscs_mars.enums.NoKeyReason
  20. import com.grkj.iscs_mars.extentions.removeLeadingZeros
  21. import com.grkj.iscs_mars.extentions.serialNo
  22. import com.grkj.iscs_mars.extentions.startsWith
  23. import com.grkj.iscs_mars.extentions.toHexStrings
  24. import com.grkj.iscs_mars.modbus.DockBean
  25. import com.grkj.iscs_mars.modbus.ModBusController
  26. import com.grkj.iscs_mars.modbus.ModBusController.dockList
  27. import com.grkj.iscs_mars.modbus.ModBusController.getOneKey
  28. import com.grkj.iscs_mars.model.Constants.USER_TYPE_LOCKER
  29. import com.grkj.iscs_mars.model.DeviceConst
  30. import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_CARD
  31. import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
  32. import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_KEY
  33. import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_LOCK
  34. import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
  35. import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_KEY
  36. import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_LOCK
  37. import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_PORTABLE
  38. import com.grkj.iscs_mars.model.DictAndSystemConstants
  39. import com.grkj.iscs_mars.model.ISCSDomainData
  40. import com.grkj.iscs_mars.model.bo.DeviceTakeUpdateBO
  41. import com.grkj.iscs_mars.model.bo.UpdateKeyReturnBO
  42. import com.grkj.iscs_mars.model.bo.WorkTicketGetBO
  43. import com.grkj.iscs_mars.model.bo.WorkTicketSendBO
  44. import com.grkj.iscs_mars.model.bo.WorkTicketSendBO.LockListBO
  45. import com.grkj.iscs_mars.model.eventmsg.CurrentModeMsg
  46. import com.grkj.iscs_mars.model.eventmsg.DeviceExceptionMsg
  47. import com.grkj.iscs_mars.model.eventmsg.DeviceTakeUpdateMsg
  48. import com.grkj.iscs_mars.model.eventmsg.LoadingMsg
  49. import com.grkj.iscs_mars.model.eventmsg.MsgEvent
  50. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants
  51. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_CURRENT_MODE
  52. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_DEVICE_EXCEPTION
  53. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_DEVICE_TAKE_UPDATE
  54. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_LOADING
  55. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_SWITCH_COLLECTION_UPDATE
  56. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_SWITCH_MODE
  57. import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
  58. import com.grkj.iscs_mars.model.eventmsg.SwitchModeMsg
  59. import com.grkj.iscs_mars.model.eventmsg.UpdateTicketProgressMsg
  60. import com.grkj.iscs_mars.model.vo.dict.CommonDictRespVO
  61. import com.grkj.iscs_mars.model.vo.hardware.CabinetSlotsRespVo
  62. import com.grkj.iscs_mars.model.vo.hardware.SwitchListReqVO
  63. import com.grkj.iscs_mars.model.vo.key.KeyPageRespVO
  64. import com.grkj.iscs_mars.model.vo.lock.LockPageRespVO
  65. import com.grkj.iscs_mars.model.vo.lock.LockTakeUpdateReqVO
  66. import com.grkj.iscs_mars.model.vo.ticket.LockPointUpdateReqVO
  67. import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
  68. import com.grkj.iscs_mars.service.CheckKeyInfoTask
  69. import com.grkj.iscs_mars.util.ActivityUtils
  70. import com.grkj.iscs_mars.util.CommonUtils
  71. import com.grkj.iscs_mars.util.Executor
  72. import com.grkj.iscs_mars.util.NetApi
  73. import com.grkj.iscs_mars.util.SPUtils
  74. import com.grkj.iscs_mars.util.ToastUtils
  75. import com.grkj.iscs_mars.util.log.LogUtil
  76. import com.grkj.iscs_mars.view.activity.LoginActivity
  77. import com.grkj.iscs_mars.view.base.BaseActivity
  78. import com.grkj.iscs_mars.view.dialog.TipDialog
  79. import com.huyuhui.fastble.data.BleDevice
  80. import com.huyuhui.fastble.exception.BleException
  81. import com.sik.cronjob.managers.CronJobScanner
  82. import com.sik.sikandroid.activity.ActivityTracker
  83. import com.sik.sikcore.SIKCore
  84. import com.sik.sikcore.date.TimeUtils
  85. import com.sik.sikcore.thread.ThreadUtils
  86. import kotlinx.coroutines.Dispatchers
  87. import kotlinx.coroutines.async
  88. import kotlinx.coroutines.suspendCancellableCoroutine
  89. import kotlinx.coroutines.withContext
  90. import kotlin.coroutines.resume
  91. /**
  92. * 业务层管理
  93. */
  94. object BusinessManager {
  95. // 消息总线
  96. val mEventBus = MutableLiveData<MsgEvent>()
  97. @JvmStatic
  98. @Volatile
  99. // 已连接的蓝牙钥匙集合
  100. var deviceList: MutableList<BleBean> = mutableListOf()
  101. // Modbus数据页面监听
  102. class DeviceListener(
  103. val key: Any, val callBack: (DockBean) -> Unit
  104. )
  105. private val listeners = ArrayList<DeviceListener>()
  106. private var initListener: (() -> Unit)? = null
  107. // 归还设备是否需要登录
  108. var NEED_AUTH = true
  109. // 归还设备是否需要登录及角色验证
  110. var CAN_RETURN = true
  111. get() {
  112. val loginUser = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext!!)
  113. return (NEED_AUTH && loginUser != null) || !NEED_AUTH
  114. }
  115. // 设备待取列表(需要报给后台的列表,等实际取完再上报)
  116. @JvmStatic
  117. val mDeviceTakeList = mutableListOf<DeviceTakeUpdateBO>()
  118. // 是否是测试人员登录的
  119. var isTestMode = false
  120. // 有问题的钥匙的列表 - rfid
  121. var mExceptionKeyList = mutableListOf<String>()
  122. /**
  123. * 检查钥匙任务
  124. */
  125. var checkKeyInfoTask: CheckKeyInfoTask = CheckKeyInfoTask()
  126. /**
  127. * 初始化消息总线
  128. */
  129. fun initMsgEventBus() {
  130. mEventBus.observeForever {
  131. LogUtil.i("msgEvent : $it")
  132. when (it.code) {
  133. // loading消息
  134. MSG_EVENT_LOADING -> {
  135. Executor.runOnMain {
  136. val loadingMsg = it.data as LoadingMsg
  137. (ActivityUtils.currentActivity() as BaseActivity<*>).handleLoading(
  138. loadingMsg.isShow, loadingMsg.loadingText
  139. )
  140. }
  141. }
  142. // 设备取出
  143. MSG_EVENT_DEVICE_TAKE_UPDATE -> {
  144. handleDeviceTake(it.data as DeviceTakeUpdateMsg)
  145. }
  146. MsgEventConstants.MSG_EVENT_INIT_KEY_COMPLETE -> {
  147. val job = CronJobScanner.scanJobs(checkKeyInfoTask)
  148. MyApplication.cronJobManager.registerJobs(job)
  149. }
  150. // 钥匙当前模式
  151. MSG_EVENT_CURRENT_MODE -> {
  152. handleCurrentMode(it.data as CurrentModeMsg)
  153. }
  154. // 钥匙切换模式结果
  155. MSG_EVENT_SWITCH_MODE -> {
  156. when ((it.data as SwitchModeMsg).job) {
  157. // 工作模式
  158. 1 -> {
  159. if (it.data.res == 1) {
  160. // 只能在这里断开,不能全部断开
  161. BleSendDispatcher.scheduleDisconnect(it.data.bleBean.bleDevice.mac)
  162. // 打开钥匙卡扣
  163. val keyBean =
  164. ModBusController.getKeyByMac(it.data.bleBean.bleDevice.mac)
  165. if (keyBean == null) {
  166. sendEventMsg(
  167. MsgEvent(
  168. MSG_EVENT_LOADING,
  169. LoadingMsg(false, "未找到钥匙信息", false)
  170. )
  171. )
  172. ToastUtils.tip(R.string.key_not_exists)
  173. } else {
  174. sendLoadingEventMsg(CommonUtils.getStr(R.string.take_out_key_tip))
  175. val dock =
  176. ModBusController.getDockByKeyMac(it.data.bleBean.bleDevice.mac)
  177. keyBean.isReady = false
  178. ModBusController.controlKeyBuckle(
  179. true, keyBean.isLeft, dock?.addr
  180. )
  181. ModBusController.updateKeyReadyStatus(
  182. it.data.bleBean.bleDevice.mac, false, 1
  183. )
  184. ToastUtils.tip(R.string.take_out_key)
  185. ThreadUtils.runOnIO {
  186. checkMyTodoForHandleKey(it.data.bleBean.bleDevice.mac)
  187. }
  188. }
  189. } else {
  190. LogUtil.e("切换工作模式失败 : ${it.data.bleBean.bleDevice.mac}")
  191. Executor.delayOnMain(500) {
  192. switchWorkMode(it.data.bleBean.bleDevice, false)
  193. }
  194. }
  195. }
  196. // 待机模式
  197. 2 -> {
  198. if (it.data.res == 1) {
  199. ModBusController.updateKeyReadyStatus(
  200. it.data.bleBean.bleDevice.mac, true, 2
  201. )
  202. // 延时再次获取当前状态,触发handleCurrentMode里工作票下发状态检查
  203. Executor.delayOnMain(500) {
  204. getCurrentStatus(1, it.data.bleBean.bleDevice)
  205. }
  206. } else {
  207. LogUtil.e("切换待机模式失败 : ${it.data.bleBean.bleDevice.mac}")
  208. Executor.delayOnMain(500) {
  209. switchReadyMode(it.data.bleBean.bleDevice)
  210. }
  211. }
  212. }
  213. }
  214. }
  215. MSG_EVENT_SWITCH_COLLECTION_UPDATE -> {
  216. ThreadUtils.runOnIO {
  217. val switchListReqVOS = ModBusController.getSwitchData().map {
  218. SwitchListReqVO(
  219. it.idx.toString(),
  220. if (it.enabled) "1" else "0",
  221. TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
  222. )
  223. }
  224. NetApi.updateSwitchList(switchListReqVOS) {
  225. LogUtil.i("开关更新完成")
  226. }
  227. }
  228. }
  229. }
  230. }
  231. }
  232. /**
  233. * 检查我的待办
  234. */
  235. suspend fun checkMyTodoForHandleKey(mac: String? = null, delayMillis: Long = 60_0000): Boolean {
  236. if (!CAN_RETURN) {
  237. return false
  238. }
  239. val result = suspendCancellableCoroutine<Boolean> { cont ->
  240. NetApi.getMySelfState {
  241. if (it) {
  242. LogUtil.i("蓝牙连接-存在上锁解锁待办")
  243. if (BleSendDispatcher.canConnect()) {
  244. LogUtil.i("蓝牙连接-发送队列可以连接")
  245. mac?.let {
  246. connectExistsKey(listOf(it))
  247. }
  248. }
  249. } else {
  250. LogUtil.i("蓝牙连接-没有待办数据,延迟断开所有发送连接")
  251. BleSendDispatcher.disconnectAll(delayMillis)
  252. }
  253. if (cont.isActive) {
  254. cont.resume(it)
  255. }
  256. }
  257. }
  258. return result
  259. }
  260. /**
  261. * 连接一把存在的可连接的钥匙
  262. */
  263. fun connectExistsKey(exceptKeyMac: List<String> = listOf()) {
  264. ThreadUtils.runOnIO {
  265. // —— 串行请求1 & 2 ——
  266. val slotsPage = getSlotsPage()
  267. // —— 并行加载字典(或按需串行也行) ——
  268. val slotStatus =
  269. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_STATUS) }
  270. val keyStatus =
  271. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_KEY_STATUS) }
  272. val slotType =
  273. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_TYPE) }
  274. // 等待字典加载完成
  275. val slotStatusList = slotStatus.await()
  276. val keyStatusList = keyStatus.await()
  277. val slotTypeList = slotType.await()
  278. withContext(Dispatchers.Default) {
  279. val keyPage = withContext(Dispatchers.IO) { getKeyPage() }
  280. getOneKey(
  281. slotsPage?.records?.filter {
  282. it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
  283. }?.toMutableList() ?: mutableListOf(),
  284. (keyPage?.records?.filter { it.exStatus == keyStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
  285. ?.map { it.keyNfc ?: "" }?.toMutableList() ?: mutableListOf()),
  286. exceptKeyMac
  287. )
  288. }
  289. }
  290. }
  291. /****************************************** ModBus ******************************************/
  292. /**
  293. * 链接底座
  294. */
  295. fun connectDock(isNeedInit: Boolean = false) {
  296. ModBusController.interruptReadTrashBinStatus(false)
  297. ModBusController.start(MyApplication.instance!!.applicationContext)
  298. ModBusController.unregisterListener(MyApplication.instance!!.applicationContext)
  299. if (isNeedInit) {
  300. ModBusController.initDevicesStatus()
  301. }
  302. }
  303. /**
  304. * 断开底座链接
  305. */
  306. fun disconnectDock() {
  307. ModBusController.stop()
  308. }
  309. /**
  310. * 注册状态监听
  311. */
  312. fun registerStatusListener(key: Any, listener: (DockBean) -> Unit) {
  313. listeners.add(DeviceListener(key, listener))
  314. }
  315. /**
  316. * 注册初始化监听
  317. */
  318. fun registerInitListener(listener: () -> Unit) {
  319. this.initListener = listener
  320. }
  321. /**
  322. * 取消注册初始化监听
  323. */
  324. fun unRegisterInitListener() {
  325. this.initListener = null
  326. }
  327. /**
  328. * 取消注册状态监听
  329. */
  330. fun unregisterListener(key: Any) {
  331. val it = listeners.iterator()
  332. while (it.hasNext()) {
  333. if (it.next().key == key) {
  334. it.remove()
  335. }
  336. }
  337. }
  338. /**
  339. * 总的监听,做预处理,其余的所有监听均使用本监听处理后的数据,只允许调用一次
  340. */
  341. fun registerMainListener() {
  342. ModBusController.registerStatusListener(this) { res ->
  343. deviceStatusHandle(res)
  344. }
  345. }
  346. /**
  347. * 硬件状态
  348. * 1、检测到有钥匙
  349. * 2、上锁
  350. * 3、开启充电
  351. * 4、蓝牙连接
  352. * 5、蓝牙数据通讯
  353. */
  354. private fun deviceStatusHandle(res: Any) {
  355. LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
  356. if (res.isEmpty() || res.any { it.isEmpty() }) {
  357. var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
  358. val addressList = mutableListOf<String>()
  359. ModBusController.modBusManager?.mSlaveAddressList?.forEach { itDock ->
  360. if (res.none { it.isNotEmpty() && it[0] == itDock }) {
  361. addressList.add("0x${String.format("%02X", itDock)}")
  362. }
  363. }
  364. tipStr += addressList
  365. ToastUtils.tip(tipStr)
  366. }
  367. res.forEachIndexed { index, bytes ->
  368. val dockBean = ModBusController.updateStatus(bytes) ?: return@forEachIndexed
  369. ModBusController.isInitReady = true
  370. when (dockBean.type) {
  371. DOCK_TYPE_KEY -> {
  372. if (!CAN_RETURN) {
  373. return@forEachIndexed
  374. }
  375. dockBean.getKeyList().forEach { keyBean ->
  376. deviceKeyHandler(dockBean, keyBean)
  377. }
  378. }
  379. DOCK_TYPE_LOCK -> {
  380. if (!CAN_RETURN) {
  381. return@forEachIndexed
  382. }
  383. dockBean.getLockList().forEach { lockBean ->
  384. deviceLockHandler(dockBean, lockBean)
  385. }
  386. }
  387. DOCK_TYPE_ELEC_LOCK_BOARD -> {
  388. // TODO 占位
  389. }
  390. DOCK_TYPE_PORTABLE -> {
  391. // TODO 便携式待完善
  392. dockBean.deviceList.forEach { deviceBean ->
  393. if (deviceBean.isExist) {
  394. when (deviceBean.type) {
  395. DEVICE_TYPE_KEY -> {
  396. if (!CAN_RETURN) {
  397. return@forEachIndexed
  398. }
  399. deviceKeyHandler(dockBean, deviceBean as DockBean.KeyBean)
  400. }
  401. DEVICE_TYPE_LOCK -> {
  402. if (!CAN_RETURN) {
  403. return@forEachIndexed
  404. }
  405. deviceLockHandler(dockBean, deviceBean as DockBean.LockBean)
  406. }
  407. DEVICE_TYPE_CARD -> {
  408. ModBusController.readPortalCaseCardRfid(dockBean.addr) { res ->
  409. if (res.size < 11) {
  410. LogUtil.e("Portal Case card rfid error")
  411. return@readPortalCaseCardRfid
  412. }
  413. val rfid = res.copyOfRange(3, 11).toHexStrings(false)
  414. .removeLeadingZeros()
  415. LogUtil.i("卡片RFID : $rfid")
  416. }
  417. }
  418. DEVICE_TYPE_FINGERPRINT -> {
  419. }
  420. }
  421. }
  422. }
  423. }
  424. DeviceConst.DOCK_TYPE_COLLECT -> {
  425. ModBusController.switchStatus(bytes) {}
  426. }
  427. }
  428. Executor.delayOnMain(200) {
  429. if (!ISCSDomainData.isDeviceRegistration) {
  430. listeners.forEach { it.callBack(dockBean) }
  431. }
  432. }
  433. }
  434. Executor.delayOnMain(200) {
  435. if (ISCSDomainData.isDeviceRegistration) {
  436. initListener?.invoke()
  437. }
  438. }
  439. }
  440. /**
  441. * 挂锁处理
  442. */
  443. private fun deviceLockHandler(
  444. dockBean: DockBean, lockBean: DockBean.LockBean
  445. ) {
  446. if (lockBean.isExist) {
  447. ModBusController.readLockRfid(dockBean.addr, lockBean.idx) { res ->
  448. if (res.size < 11) {
  449. LogUtil.e("Lock rfid error")
  450. return@readLockRfid
  451. }
  452. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  453. ModBusController.updateLockRfid(
  454. dockBean.addr, lockBean.idx, rfid
  455. )
  456. ThreadUtils.runOnIO {
  457. val lockStatusReq =
  458. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_PAD_LOCK_STATUS) }
  459. val slotStatus =
  460. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_STATUS) }
  461. val slotType =
  462. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_TYPE) }
  463. val slotsPageReq = async { getSlotsPage() }
  464. var lockStatus = lockStatusReq.await()
  465. val slotsPage = slotsPageReq.await()
  466. val slotStatusList = slotStatus.await()
  467. val slotTypeList = slotType.await()
  468. NetApi.getIsLockPage { lockData ->
  469. //锁rfid未异常正常请求锁数据,关锁
  470. if (rfid in (lockData?.records?.filter { it.exStatus == lockStatus.find { it.dictLabel == "异常" }?.dictValue }
  471. ?.map { it.lockNfc }?.toMutableList() ?: mutableListOf())) {
  472. ToastUtils.tip(
  473. MyApplication.instance?.applicationContext!!.getString(
  474. R.string.lock_exception_tag
  475. )
  476. )
  477. } else if (slotsPage?.records?.filter {
  478. it.slotType == slotTypeList.find { d -> d.dictLabel == "锁" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
  479. }
  480. ?.find { it.row?.toInt() == dockBean.row && (lockBean.idx + 1) == it.col?.toInt() } != null) {
  481. ToastUtils.tip(
  482. MyApplication.instance?.applicationContext!!.getString(
  483. R.string.slot_exception_tag
  484. )
  485. )
  486. } else {
  487. NetApi.getLockInfo(rfid) {
  488. if (it != null) {
  489. NetApi.getLockStateByNfc(rfid) {
  490. if (it != 1) {
  491. ModBusController.controlLockBuckle(
  492. false, dockBean.addr, lockBean.idx
  493. ) { itRst ->
  494. if (itRst.isNotEmpty()) {
  495. // 上报锁具信息
  496. NetApi.updateLockReturn(
  497. rfid, MyApplication.instance!!.serialNo()
  498. ) {}
  499. }
  500. }
  501. } else {
  502. ToastUtils.tip(CommonUtils.getStr(R.string.ticket_not_finish_can_not_return_lock))
  503. }
  504. }
  505. }
  506. }
  507. }
  508. }
  509. }
  510. }
  511. } else {
  512. LogUtil.i("挂锁取出-:${lockBean.rfid}")
  513. sendEventMsg(
  514. MsgEvent(
  515. MSG_EVENT_DEVICE_TAKE_UPDATE,
  516. DeviceTakeUpdateMsg(DEVICE_TYPE_LOCK, lockBean.rfid)
  517. )
  518. )
  519. }
  520. }
  521. private fun deviceKeyHandler(dockBean: DockBean, keyBean: DockBean.KeyBean) {
  522. if (keyBean.isExist) {
  523. // 放回钥匙,读取rfid
  524. ModBusController.readKeyRfid(
  525. dockBean.addr, if (keyBean.isLeft) 0 else 1
  526. ) { isLeft, res ->
  527. if (!ISCSDomainData.isDeviceRegistration) {
  528. ModBusController.controlKeyCharge(
  529. true, keyBean.isLeft, dockBean.addr
  530. )
  531. }
  532. if (res.size < 11) {
  533. LogUtil.e("Key rfid error")
  534. return@readKeyRfid
  535. }
  536. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  537. ThreadUtils.runOnIO {
  538. val slotStatus =
  539. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_STATUS) }
  540. val slotType =
  541. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_TYPE) }
  542. val slotsPageReq = async { getSlotsPage() }
  543. val keyStatusReq =
  544. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_KEY_STATUS) }
  545. val keyPageReq = async { getKeyPage() }
  546. var keyStatus = keyStatusReq.await()
  547. var keyData = keyPageReq.await()
  548. val slotsPage = slotsPageReq.await()
  549. val slotStatusList = slotStatus.await()
  550. val slotTypeList = slotType.await()
  551. //锁钥匙未异常正常请求锁数据,关锁
  552. if (rfid in (keyData?.records?.filter { it.exStatus == keyStatus.find { it.dictLabel == "异常" }?.dictValue }
  553. ?.map { it.keyNfc }?.toMutableList() ?: mutableListOf())) {
  554. ToastUtils.tip(
  555. MyApplication.instance?.applicationContext!!.getString(
  556. R.string.key_exception_tag
  557. )
  558. )
  559. } else if (slotsPage?.records?.filter {
  560. it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
  561. }
  562. ?.find { it.row?.toInt() == dockBean.row && it.col?.toInt() == (dockBean.col + (if (keyBean.isLeft) 0 else 1) * 2) } != null) {
  563. ToastUtils.tip(
  564. MyApplication.instance?.applicationContext!!.getString(
  565. R.string.slot_exception_tag
  566. )
  567. )
  568. } else {
  569. ModBusController.updateKeyRfid(
  570. dockBean.addr, keyBean.isLeft, rfid
  571. )
  572. // 放回钥匙,上锁
  573. ModBusController.controlKeyBuckle(
  574. false, keyBean.isLeft, dockBean.addr
  575. ) {
  576. NetApi.getKeyInfo(rfid) {
  577. ModBusController.updateKeyNewHardware(
  578. dockBean.addr, true, it == null
  579. )
  580. if (it != null && !it.macAddress.isNullOrEmpty()) {
  581. ModBusController.updateKeyMac(
  582. dockBean.addr, keyBean.isLeft, it.macAddress
  583. )
  584. ModBusController.updateKeyReadyStatus(
  585. it.macAddress, false, 5
  586. )
  587. } else {
  588. LogUtil.e("Get key info fail : $rfid")
  589. if (!ISCSDomainData.isDeviceRegistration) {
  590. ToastUtils.tip(R.string.get_key_info_fail)
  591. }
  592. ModBusController.controlKeyBuckle(
  593. true, keyBean.isLeft, dockBean.addr
  594. )
  595. }
  596. }
  597. }
  598. }
  599. }
  600. }
  601. } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
  602. // 移出待连监听集合,防止connectKey循环失败
  603. keyBean.mac?.let {
  604. unregisterConnectListener(it)
  605. }
  606. sendEventMsg(
  607. MsgEvent(
  608. MSG_EVENT_DEVICE_TAKE_UPDATE, DeviceTakeUpdateMsg(DEVICE_TYPE_KEY, keyBean.rfid)
  609. )
  610. )
  611. }
  612. }
  613. /**
  614. * 更新所有锁仓状态
  615. */
  616. fun updateAllBuckleStatus(done: () -> Unit) {
  617. ModBusController.updateAllBuckleStatus(done)
  618. }
  619. /**
  620. * 更新开关状态
  621. */
  622. fun updateSwitchStatus(done: () -> Unit) {
  623. ModBusController.updateSwitchStatus(done)
  624. }
  625. /**
  626. * 钥匙归还提示确认弹窗,当前策略:作业票未完成是否强制上传数据
  627. */
  628. private fun showKeyReturnUploadDataForceDialog(onConfirm: () -> Unit, onCancel: () -> Unit) {
  629. val ctx = ActivityUtils.currentActivity() as BaseActivity<*>
  630. val dlg = TipDialog(ctx)
  631. dlg.setTip(ctx.getString(R.string.key_return_force_tip))
  632. dlg.setType(TipDialog.TYPE_ALL)
  633. // 加个选择判断,如果是直接取消弹框而不是点击“确定”,当成确定
  634. var state = 0
  635. dlg.setConfirmListener {
  636. state = 1
  637. onConfirm.invoke()
  638. }
  639. dlg.setOnCancelListener {
  640. state = 2
  641. onCancel.invoke()
  642. }
  643. dlg.setOnDismissListener {
  644. if (state == 0) {
  645. onCancel.invoke()
  646. }
  647. }
  648. dlg.show()
  649. }
  650. /**
  651. * 钥匙归还提示确认弹框,当前策略:作业票未完成禁止归还钥匙
  652. */
  653. private fun showKeyReturnDialog(onConfirm: () -> Unit) {
  654. val ctx = ActivityUtils.currentActivity() as BaseActivity<*>
  655. val dlg = TipDialog(ctx)
  656. dlg.setTip(ctx.getString(R.string.key_return_tip))
  657. dlg.setType(TipDialog.TYPE_CONFIRM)
  658. // 加个选择判断,如果是直接取消弹框而不是点击“确定”,当成确定
  659. var state = 0
  660. dlg.setConfirmListener {
  661. state = 1
  662. onConfirm.invoke()
  663. }
  664. dlg.setOnDismissListener {
  665. if (state == 0) {
  666. onConfirm.invoke()
  667. }
  668. }
  669. dlg.show()
  670. }
  671. fun readLockBuckleStatus() {
  672. // TODO slaveIdx暂时写死,调试用
  673. ModBusController.readBuckleStatus(true, 0) { type, res ->
  674. LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}")
  675. when (type) {
  676. 0 -> {
  677. val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
  678. val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
  679. LogUtil.i("锁具底座卡扣状态 : $isLeftLock - $isRightLock")
  680. }
  681. 1 -> {
  682. val tempList = mutableListOf<Boolean>()
  683. for (i in 0..7) {
  684. tempList.add((res[4].toInt() shr i) and 0x1 == 1)
  685. }
  686. LogUtil.i("锁具底座卡扣1-8状态 : $tempList")
  687. }
  688. 2 -> {
  689. val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
  690. val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
  691. LogUtil.i("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status")
  692. }
  693. }
  694. }
  695. }
  696. fun readKeyBuckleStatus() {
  697. // TODO slaveIdx暂时写死,调试用
  698. ModBusController.readBuckleStatus(false, 1) { type, res ->
  699. LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}")
  700. // TODO 待验证
  701. when (type) {
  702. 0 -> {
  703. val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
  704. val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
  705. LogUtil.i("钥匙底座卡扣状态 : $isLeftLock - $isRightLock")
  706. }
  707. 1 -> {
  708. val tempList = mutableListOf<Boolean>()
  709. for (i in 0..7) {
  710. tempList.add((res[4].toInt() shr i) and 0x1 == 1)
  711. }
  712. LogUtil.i("锁具底座卡扣1-8状态 : $tempList")
  713. }
  714. 2 -> {
  715. val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
  716. val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
  717. LogUtil.i("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status")
  718. }
  719. }
  720. }
  721. }
  722. // 1. 把 NetApi.get…Page 包成 suspend 函数
  723. private suspend fun getSlotsPage(): CabinetSlotsRespVo? = suspendCancellableCoroutine { cont ->
  724. NetApi.getIsLockCabinetSlotsPage { slots ->
  725. cont.resume(slots)
  726. }
  727. }
  728. private suspend fun getLocksPage(): LockPageRespVO? = suspendCancellableCoroutine { cont ->
  729. NetApi.getIsLockPage { locks ->
  730. cont.resume(locks)
  731. }
  732. }
  733. private suspend fun getKeyPage(): KeyPageRespVO? = suspendCancellableCoroutine { cont ->
  734. NetApi.getIsKeyPage { keys ->
  735. cont.resume(keys)
  736. cont.cancel()
  737. }
  738. }
  739. // 2. 把原本同步的字典查询留在 IO 线程
  740. private suspend fun <T> fetchDict(key: String): List<T> = withContext(Dispatchers.IO) {
  741. @Suppress("UNCHECKED_CAST") NetApi.getDictData(key) as List<T>
  742. }
  743. // 3. 重写 checkEquipCount
  744. fun checkEquipCount(
  745. needLockCount: Int,
  746. isNeedKey: Boolean,
  747. callBack: (Pair<Byte, DockBean.KeyBean?>?, MutableMap<Byte, MutableList<DockBean.LockBean>>) -> Unit
  748. ) {
  749. // 你可以改成接收 CoroutineScope 或者直接在全局 Scope 启动
  750. ThreadUtils.runOnMain {
  751. sendLoadingEventMsg(MyApplication.instance?.applicationContext!!.getString(R.string.check_key_and_lock))
  752. try {
  753. // —— 串行请求1 & 2 ——
  754. val slotsPage = getSlotsPage()
  755. val locksPage = getLocksPage()
  756. // —— 并行加载字典(或按需串行也行) ——
  757. val lockStatus =
  758. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_PAD_LOCK_STATUS) }
  759. val slotStatus =
  760. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_STATUS) }
  761. val slotType =
  762. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_SLOT_TYPE) }
  763. val keyStatus =
  764. async { fetchDict<CommonDictRespVO>(DictAndSystemConstants.KEY_KEY_STATUS) }
  765. // 等待字典加载完成
  766. val lockStatusList = lockStatus.await()
  767. val slotStatusList = slotStatus.await()
  768. val slotTypeList = slotType.await()
  769. val keyStatusList = keyStatus.await()
  770. // —— 在 Default 线程做计算密集操作 ——
  771. val lockMap = withContext(Dispatchers.Default) {
  772. ModBusController.getLocks(
  773. needLockCount,
  774. slotsPage?.records?.filter {
  775. it.slotType == slotTypeList.find { d -> d.dictLabel == "锁" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
  776. }?.toMutableList() ?: mutableListOf(),
  777. locksPage?.records?.filter { it.exStatus == lockStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
  778. ?.map { it.lockNfc ?: "" }?.toMutableList() ?: mutableListOf()
  779. )
  780. }
  781. // —— 如果需钥匙,再请求并计算 ——
  782. var keyPair: Pair<Byte, DockBean.KeyBean?>? = null
  783. if (isNeedKey) {
  784. val keyPage = withContext(Dispatchers.IO) { getKeyPage() }
  785. keyPair = withContext(Dispatchers.Default) {
  786. getOneKey(
  787. slotsPage?.records?.filter {
  788. it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
  789. }?.toMutableList() ?: mutableListOf(),
  790. keyPage?.records?.filter { it.exStatus == keyStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
  791. ?.map { it.keyNfc ?: "" }?.toMutableList() ?: mutableListOf()
  792. )
  793. }
  794. }
  795. // —— 全部计算完毕,在主线程一次性回调 ——
  796. callBack(keyPair, lockMap)
  797. } catch (e: Exception) {
  798. // 根据需求处理异常,或把异常信息也通过 callback 返回
  799. sendLoadingEventMsg(null, false)
  800. e.printStackTrace()
  801. ToastUtils.tip("检查设备异常:${e.message}")
  802. }
  803. }
  804. }
  805. /****************************************** 蓝牙 ******************************************/
  806. /******************************************蓝牙通用准备******************************************/
  807. /**
  808. * 注册连接监听
  809. */
  810. fun registerConnectListener(
  811. mac: String, connectNow: Boolean = false, isSend: Boolean = true, callBack: ((
  812. Boolean, BleBean?
  813. ) -> Unit)? = null
  814. ) {
  815. BleConnectionManager.registerConnectListener(mac, connectNow, isSend, callBack)
  816. }
  817. /**
  818. * 连接监听反注册
  819. */
  820. fun unregisterConnectListener(mac: String, bleBean: BleBean? = null) {
  821. BleConnectionManager.unregisterConnectListener(mac, bleBean)
  822. }
  823. /******************************************蓝牙通用准备结束******************************************/
  824. fun getBleDeviceByMac(mac: String?): BleBean? {
  825. return deviceList.find { it.bleDevice.mac == mac }
  826. }
  827. fun getBleBeanByRfid(nfc: String?): BleBean? {
  828. nfc ?: return null
  829. ModBusController.getKeyByRfid(nfc)?.mac?.let { itMac ->
  830. return getBleDeviceByMac(itMac)
  831. }
  832. return null
  833. }
  834. /**
  835. * 下发工作票
  836. */
  837. private fun sendTicketBusiness(
  838. isLock: Boolean,
  839. mac: String,
  840. ticketDetail: TicketDetailRespVO,
  841. lockList: MutableList<String?>?,
  842. activity: AppCompatActivity,
  843. isNeedLoading: Boolean = false,
  844. ) {
  845. if (BleSendDispatcher.isConnected(mac)) {
  846. val bleBean = getBleDeviceByMac(mac)
  847. if (bleBean == null) {
  848. LogUtil.e("sendTicketBusiness fail : $mac, bleBean is null")
  849. return
  850. }
  851. // 单bleBean json赋值
  852. bleBean.retryCount = 0
  853. bleBean.ticketSend = generateTicketSendJson(isLock, ticketDetail, lockList)
  854. bleBean.ticketSend?.let { itJson ->
  855. sendTicketWithRetry(itJson, bleBean.bleDevice, isNeedLoading)
  856. }
  857. } else {
  858. ThreadUtils.runOnIODelayed(1000) {
  859. sendTicketBusiness(isLock, mac, ticketDetail, lockList, activity, isNeedLoading)
  860. }
  861. }
  862. }
  863. /**
  864. * 带重试的下发工作票,重试次数3,间隔500ms
  865. */
  866. private fun sendTicketWithRetry(
  867. json: String,
  868. bleDevice: BleDevice,
  869. isNeedLoading: Boolean = false,
  870. maxRetries: Int = 3,
  871. delayMillis: Long = 500
  872. ) {
  873. var retryCount = 0
  874. fun attemptSend() {
  875. sendTicket(json, bleDevice, isNeedLoading) { sendRst ->
  876. if (!sendRst && retryCount < maxRetries) {
  877. retryCount++
  878. // 等待一段时间后再次尝试
  879. Executor.delayOnMain(delayMillis) {
  880. LogUtil.i("Retry attempt, mac : ${bleDevice.mac}, retryCount : $retryCount")
  881. attemptSend()
  882. }
  883. }
  884. }
  885. }
  886. attemptSend()
  887. }
  888. /**
  889. * 读取工作票完成情况
  890. */
  891. private fun getTicketStatusBusiness(
  892. mac: String, isNeedLoading: Boolean = false
  893. ) {
  894. LogUtil.i("检查钥匙连接情况")
  895. if (BleReturnDispatcher.isConnected(mac)) {
  896. getBleDeviceByMac(mac)?.bleDevice?.let {
  897. LogUtil.i("开始读取作业票")
  898. BleReturnDispatcher.busy(mac)
  899. getTicketStatusWithRetry(
  900. it,
  901. isNeedLoading
  902. )
  903. }
  904. } else {
  905. //如果连接在待发列表则断开连接,重新使用归还队列连接之后检查
  906. if (BleSendDispatcher.isConnected(mac)) {
  907. BleSendDispatcher.scheduleDisconnect(mac)
  908. BleReturnDispatcher.submit(mac) {
  909. getTicketStatusBusiness(mac, isNeedLoading)
  910. }
  911. }
  912. if (isNeedLoading) sendEventMsg(
  913. MsgEvent(
  914. MSG_EVENT_LOADING, LoadingMsg(false, null, false)
  915. )
  916. )
  917. }
  918. }
  919. private fun getTicketStatusWithRetry(
  920. bleDevice: BleDevice,
  921. isNeedLoading: Boolean = false,
  922. maxRetries: Int = 3,
  923. delayMillis: Long = 500
  924. ) {
  925. var retryCount = 0
  926. fun attemptSend() {
  927. getTicketStatus(bleDevice, isNeedLoading) { sendRst ->
  928. if (!sendRst && retryCount < maxRetries) {
  929. retryCount++
  930. // 等待一段时间后再次尝试
  931. Executor.delayOnMain(delayMillis) {
  932. LogUtil.i("Retry attempt, mac : ${bleDevice.mac}, retryCount : $retryCount")
  933. attemptSend()
  934. }
  935. }
  936. }
  937. }
  938. attemptSend()
  939. }
  940. private fun sendTicket(
  941. jsonStr: String,
  942. bleDevice: BleDevice,
  943. isNeedLoading: Boolean = false,
  944. processCallback: ((Boolean) -> Unit)? = null
  945. ) {
  946. if (isNeedLoading) sendEventMsg(
  947. MsgEvent(
  948. MSG_EVENT_LOADING,
  949. LoadingMsg(true, CommonUtils.getStr(R.string.start_to_send_ticket), null)
  950. )
  951. )
  952. BleCmdManager.sendWorkTicket(
  953. jsonStr, bleDevice = bleDevice, callback = object : CustomBleWriteCallback() {
  954. override fun onWriteSuccess(
  955. bleDevice: BleDevice,
  956. characteristic: BluetoothGattCharacteristic,
  957. current: Int,
  958. total: Int,
  959. justWrite: ByteArray,
  960. data: ByteArray
  961. ) {
  962. LogUtil.i("sendTicket success")
  963. if (isNeedLoading) sendEventMsg(
  964. MsgEvent(
  965. MSG_EVENT_LOADING,
  966. LoadingMsg(true, CommonUtils.getStr(R.string.sending_ticket), null)
  967. )
  968. )
  969. }
  970. override fun onWriteFailure(
  971. bleDevice: BleDevice,
  972. characteristic: BluetoothGattCharacteristic?,
  973. exception: BleException,
  974. current: Int,
  975. total: Int,
  976. justWrite: ByteArray?,
  977. data: ByteArray?,
  978. isTotalFail: Boolean
  979. ) {
  980. LogUtil.e("sendTicket fail : ${bleDevice.mac}")
  981. if (isNeedLoading) sendEventMsg(
  982. MsgEvent(
  983. MSG_EVENT_LOADING,
  984. LoadingMsg(false, CommonUtils.getStr(R.string.send_ticket_fail), null)
  985. )
  986. )
  987. processCallback?.invoke(false)
  988. }
  989. })
  990. }
  991. /**
  992. * 生成下发工作票Json
  993. *
  994. * @param vo 工作票详情
  995. */
  996. private fun generateTicketSendJson(
  997. isLock: Boolean, vo: TicketDetailRespVO, lockList: MutableList<String?>?
  998. ): String {
  999. LogUtil.i("generateTicketSendJson : $lockList")
  1000. val bo = WorkTicketSendBO(
  1001. cardNo = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.userCardList?.get(
  1002. 0
  1003. ),
  1004. )
  1005. CommonUtils.getDiffHours(vo.ticketEndTime)?.let {
  1006. bo.effectiveTime = it
  1007. }
  1008. // 有配置则用配置,没用则填充默认密码
  1009. bo.password =
  1010. SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.keyCode ?: "123456"
  1011. val dataBO = WorkTicketSendBO.DataBO(
  1012. taskCode = vo.ticketId.toString(), codeId = 1
  1013. )
  1014. val taskList = ArrayList<WorkTicketSendBO.DataBO.DataListBO>()
  1015. vo.ticketPointsVOList?.filter { it.pointStatus == if (isLock) "0" else "1" }
  1016. ?.let { itList ->
  1017. itList.forEach { pointVO ->
  1018. if (vo.noUnlockTicketPointsVOSet?.any { it.pointId == pointVO.pointId } == true && !isLock) {
  1019. return@forEach
  1020. }
  1021. val task = WorkTicketSendBO.DataBO.DataListBO(
  1022. dataId = pointVO.pointId?.toInt(),
  1023. equipRfidNo = pointVO.pointNfc,
  1024. equipName = pointVO.pointName,
  1025. target = if (isLock) 0 else 1
  1026. )
  1027. if (!isLock) {
  1028. task.infoRfidNo = pointVO.lockNfc
  1029. }
  1030. pointVO.prePointId?.let {
  1031. task.prevId = it.toInt()
  1032. }
  1033. // TODO partCode待补充
  1034. taskList.add(task)
  1035. }
  1036. }
  1037. dataBO.dataList = taskList
  1038. bo.data = mutableListOf(dataBO)
  1039. if (isLock) {
  1040. // TODO 挂锁数组
  1041. if (!lockList.isNullOrEmpty()) {
  1042. bo.lockList = mutableListOf()
  1043. lockList.forEachIndexed { index, s ->
  1044. if (s.isNullOrEmpty()) {
  1045. LogUtil.w("Lock nfc is null or empty")
  1046. return@forEachIndexed
  1047. }
  1048. bo.lockList?.add(LockListBO(index + 1, s))
  1049. }
  1050. }
  1051. }
  1052. // TODO partList 待补充
  1053. val jsonStr = Gson().toJson(bo)
  1054. LogUtil.i("json : $jsonStr")
  1055. return jsonStr
  1056. }
  1057. /**
  1058. * 生成下空发工作票Json
  1059. *
  1060. * @param vo 工作票详情
  1061. */
  1062. fun generateEmptyTicketSendJson(): String {
  1063. // 构造一个所有字段都为空/默认值的 WorkTicketSendBO
  1064. val bo = WorkTicketSendBO(
  1065. cardNo = "", // 空卡号
  1066. effectiveTime = 0, // 默认有效时长
  1067. password = "" // 空密码
  1068. ).apply {
  1069. // data 列表留空
  1070. data = mutableListOf()
  1071. // lockList 留空(如果字段非空,再设置为 emptyList())
  1072. lockList = mutableListOf()
  1073. }
  1074. // 转成 JSON 并返回
  1075. val jsonStr = Gson().toJson(bo)
  1076. LogUtil.i("generateEmptyTicketJson: $jsonStr")
  1077. return jsonStr
  1078. }
  1079. fun handleRsp(
  1080. bleBean: BleBean,
  1081. byteArray: ByteArray,
  1082. isNeedLoading: Boolean = false,
  1083. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  1084. ) {
  1085. // TODO Token校验
  1086. // val len = byteArray[2].toInt()
  1087. // val token = byteArray.copyOfRange(len + 7, len + 11)
  1088. // if (token.contentEquals(bleBean.token)) {
  1089. // LogUtil.i("Token is right")
  1090. // } else {
  1091. // LogUtil.e("Token is wrong")
  1092. // }
  1093. when {
  1094. // 获取令牌
  1095. byteArray.startsWith(BleConst.RSP_GET_TOKEN) -> BleCmdManager.handleToken(
  1096. bleBean.bleDevice, byteArray
  1097. ) { isSuccess ->
  1098. if (isSuccess) {
  1099. //尝试使用命令作为心跳 ,获取token完成之后就要建立心跳了
  1100. BleCmdManager.getPower(
  1101. bleBean.bleDevice.mac, null
  1102. )
  1103. }
  1104. }
  1105. // 工作模式切换
  1106. byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> {
  1107. handleSwitchModeResult(byteArray, isNeedLoading) { res, job ->
  1108. sendEventMsg(
  1109. MsgEvent(
  1110. MSG_EVENT_SWITCH_MODE, SwitchModeMsg(job.toInt(), res.toInt(), bleBean)
  1111. )
  1112. )
  1113. }
  1114. }
  1115. // 工作票下发
  1116. byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(
  1117. bleBean, byteArray, isNeedLoading
  1118. )
  1119. // 获取设备当前状态
  1120. byteArray.startsWith(BleConst.RSP_CURRENT_STATUS) -> BleCmdManager.handleCurrentStatus(
  1121. byteArray
  1122. ) {
  1123. sendEventMsg(MsgEvent(MSG_EVENT_CURRENT_MODE, CurrentModeMsg(bleBean, it)))
  1124. }
  1125. // 获取设备工作票完成情况
  1126. byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() -> handleTicketStatus(
  1127. bleBean.bleDevice, byteArray, isNeedLoading
  1128. )
  1129. byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
  1130. val power = byteArray[4].toInt()
  1131. ModBusController.updateKeyPower(power, bleBean.bleDevice.mac)
  1132. LogUtil.i("电量(${bleBean.bleDevice.mac}):${power}")
  1133. prepareDoneCallBack?.invoke(true, bleBean)
  1134. if (power < 50) {//如果电量小于50就打开仓位充电
  1135. ModBusController.controlKeyCharge(true, bleBean.bleDevice.mac) {
  1136. LogUtil.i("钥匙: ${bleBean.bleDevice.mac} 开始充电")
  1137. }
  1138. }
  1139. }
  1140. }
  1141. }
  1142. /**
  1143. * 工作模式切换结果
  1144. * job : 0x01:工作模式 0x02:待机模式
  1145. * res : 0x01:成功 0x02:失败
  1146. */
  1147. private fun handleSwitchModeResult(
  1148. byteArray: ByteArray,
  1149. isNeedLoading: Boolean = false,
  1150. callBack: ((Byte, Byte) -> Unit)? = null
  1151. ) {
  1152. BleCmdManager.handleSwitchModeResult(byteArray) { job, res ->
  1153. if (res == 0x01.toByte() && job == 0x01.toByte()) {
  1154. LogUtil.i("切换工作模式成功")
  1155. if (isNeedLoading) sendEventMsg(
  1156. MsgEvent(
  1157. MSG_EVENT_LOADING, LoadingMsg(false, "切换工作模式成功", null)
  1158. )
  1159. )
  1160. } else if (res == 0x01.toByte() && job == 0x02.toByte()) {
  1161. LogUtil.i("切换待机模式成功")
  1162. if (isNeedLoading) sendEventMsg(
  1163. MsgEvent(
  1164. MSG_EVENT_LOADING, LoadingMsg(false, "切换待机模式成功", null)
  1165. )
  1166. )
  1167. } else {
  1168. LogUtil.e("切换模式失败 : ${job.toInt()} - ${res.toInt()}")
  1169. if (isNeedLoading) sendEventMsg(
  1170. MsgEvent(
  1171. MSG_EVENT_LOADING, LoadingMsg(false, null, null)
  1172. )
  1173. )
  1174. }
  1175. callBack?.invoke(res, job)
  1176. }
  1177. }
  1178. /**
  1179. * 工作票下发结果
  1180. * res:0x00:成功 0x01:失败 0x02:传输超时 0x0D:当前IDX超出范围 0x0E:当前数据CRC校验失败 0x14:JSON结构错误 0x63:未知错误
  1181. */
  1182. private fun handleWorkTicketResult(
  1183. bleBean: BleBean, byteArray: ByteArray, isNeedLoading: Boolean = false
  1184. ) {
  1185. BleCmdManager.handleWorkTicketResult(bleBean, byteArray) { isSuccess, rst ->
  1186. if (isNeedLoading) sendEventMsg(
  1187. MsgEvent(
  1188. MSG_EVENT_LOADING, LoadingMsg(false, null, null)
  1189. )
  1190. )
  1191. if (isSuccess) {
  1192. // 下发完毕,切换工作模式
  1193. LogUtil.i("工作票下发完毕")
  1194. if (isNeedLoading) sendEventMsg(
  1195. MsgEvent(
  1196. MSG_EVENT_LOADING, LoadingMsg(true, "切换钥匙为工作模式", null)
  1197. )
  1198. )
  1199. Executor.delayOnIO(800) {
  1200. //切换到工作模式
  1201. switchWorkMode(bleBean.bleDevice, isNeedLoading)
  1202. }
  1203. } else {
  1204. sendLoadingEventMsg(null, false)
  1205. if (bleBean.retryCount < 3) {
  1206. Executor.delayOnMain(500) {
  1207. bleBean.retryCount++
  1208. sendLoadingEventMsg(MyApplication.instance!!.getString(R.string.start_to_send_ticket))
  1209. sendTicketWithRetry(bleBean.ticketSend!!, bleBean.bleDevice, isNeedLoading)
  1210. }
  1211. } else {
  1212. ToastUtils.tip(R.string.send_ticket_fail)
  1213. LogUtil.e("Send ticket fail")
  1214. ModBusController.getKeyByMac(bleBean.bleDevice.mac)?.let { itKey ->
  1215. mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_KEY && it.nfc == itKey.rfid }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. /**
  1222. * 获取当前钥匙的状态
  1223. */
  1224. fun getCurrentStatus(
  1225. from: Int,
  1226. bleDevice: BleDevice,
  1227. retryCount: Int = 0,
  1228. timeoutCallBack: ((Boolean) -> Unit)? = null
  1229. ) {
  1230. LogUtil.i("getCurrentStatus - ${bleDevice.mac} - from : $from")
  1231. var isTimeout = true
  1232. // 加1秒防止早于onWriteFailure开始处理导致多次处理
  1233. Executor.delayOnMain((BleUtil.OPERATE_TIMEOUT + 1).toLong()) {
  1234. if (isTimeout) {
  1235. LogUtil.e("getCurrentStatus timeout : mac = ${bleDevice.mac}, retryCount = $retryCount")
  1236. if (retryCount > 0) {
  1237. if (from != 4) {
  1238. val canConnect = BleSendDispatcher.canConnect()
  1239. LogUtil.i("发送队列是否可以连接:${canConnect}")
  1240. if (BleSendDispatcher.isConnected(bleDevice.mac)) {
  1241. BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
  1242. }
  1243. BleSendDispatcher.submit(bleDevice.mac) {
  1244. getCurrentStatus(
  1245. from, bleDevice, retryCount - 1, timeoutCallBack
  1246. )
  1247. }
  1248. } else {
  1249. BleReturnDispatcher.clearNoBusyConnectedDevice()
  1250. BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
  1251. BleReturnDispatcher.submit(bleDevice.mac) {
  1252. getCurrentStatus(
  1253. from, bleDevice, retryCount - 1, timeoutCallBack
  1254. )
  1255. }
  1256. }
  1257. } else {
  1258. BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
  1259. BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
  1260. ModBusController.getKeyByMac(bleDevice.mac)?.rfid?.let {
  1261. addExceptionKey(it)
  1262. timeoutCallBack?.invoke(true)
  1263. }
  1264. }
  1265. }
  1266. }
  1267. BleCmdManager.getCurrentStatus(bleDevice, object : CustomBleWriteCallback() {
  1268. override fun onWriteSuccess(
  1269. bleDevice: BleDevice,
  1270. characteristic: BluetoothGattCharacteristic,
  1271. current: Int,
  1272. total: Int,
  1273. justWrite: ByteArray,
  1274. data: ByteArray
  1275. ) {
  1276. LogUtil.i("getCurrentStatus success : ${bleDevice.mac}")
  1277. isTimeout = false
  1278. timeoutCallBack?.invoke(false)
  1279. }
  1280. override fun onWriteFailure(
  1281. bleDevice: BleDevice,
  1282. characteristic: BluetoothGattCharacteristic?,
  1283. exception: BleException,
  1284. current: Int,
  1285. total: Int,
  1286. justWrite: ByteArray?,
  1287. data: ByteArray?,
  1288. isTotalFail: Boolean
  1289. ) {
  1290. LogUtil.i("getCurrentStatus fail : ${bleDevice.mac}")
  1291. isTimeout = false
  1292. Executor.delayOnMain(1000) {
  1293. getCurrentStatus(
  1294. from, bleDevice,
  1295. retryCount - 1, timeoutCallBack = timeoutCallBack
  1296. )
  1297. }
  1298. }
  1299. })
  1300. }
  1301. /**
  1302. * 获取电池电量
  1303. */
  1304. fun getBatteryPower(bleDevice: BleDevice) {
  1305. LogUtil.i("获取电池电量:${bleDevice.mac}")
  1306. BleCmdManager.getPower(bleDevice.mac, object : CustomBleWriteCallback() {
  1307. override fun onWriteSuccess(
  1308. bleDevice: BleDevice,
  1309. characteristic: BluetoothGattCharacteristic,
  1310. current: Int,
  1311. total: Int,
  1312. justWrite: ByteArray,
  1313. data: ByteArray
  1314. ) {
  1315. LogUtil.i("发送获取电池电量命令成功:${bleDevice.mac}")
  1316. }
  1317. override fun onWriteFailure(
  1318. bleDevice: BleDevice,
  1319. characteristic: BluetoothGattCharacteristic?,
  1320. exception: BleException,
  1321. current: Int,
  1322. total: Int,
  1323. justWrite: ByteArray?,
  1324. data: ByteArray?,
  1325. isTotalFail: Boolean
  1326. ) {
  1327. ThreadUtils.runOnIODelayed(500) {
  1328. LogUtil.i("发送获取电池电量命令失败:${bleDevice.mac}")
  1329. getBatteryPower(bleDevice)
  1330. }
  1331. }
  1332. })
  1333. }
  1334. /**
  1335. * 切换工作模式
  1336. */
  1337. private fun switchWorkMode(bleDevice: BleDevice, isNeedLoading: Boolean = false) {
  1338. LogUtil.i("switchWorkMode - ${bleDevice.mac}")
  1339. BleCmdManager.switchMode(STATUS_WORK, bleDevice, object : CustomBleWriteCallback() {
  1340. override fun onWriteSuccess(
  1341. bleDevice: BleDevice,
  1342. characteristic: BluetoothGattCharacteristic,
  1343. current: Int,
  1344. total: Int,
  1345. justWrite: ByteArray,
  1346. data: ByteArray
  1347. ) {
  1348. LogUtil.i("switch mode work success : ${bleDevice.mac}")
  1349. }
  1350. override fun onWriteFailure(
  1351. bleDevice: BleDevice,
  1352. characteristic: BluetoothGattCharacteristic?,
  1353. exception: BleException,
  1354. current: Int,
  1355. total: Int,
  1356. justWrite: ByteArray?,
  1357. data: ByteArray?,
  1358. isTotalFail: Boolean
  1359. ) {
  1360. LogUtil.e("switch mode work fail : ${exception?.code} - ${exception?.description}")
  1361. Executor.delayOnMain(500) {
  1362. switchWorkMode(bleDevice, isNeedLoading)
  1363. }
  1364. }
  1365. })
  1366. }
  1367. /**
  1368. * 处理工作票完成情况
  1369. */
  1370. private fun handleTicketStatus(
  1371. bleDevice: BleDevice, byteArray: ByteArray, isNeedLoading: Boolean = false
  1372. ) {
  1373. BleCmdManager.handleTicketStatus(bleDevice, byteArray) { ticketJson ->
  1374. if (ticketJson.isNullOrEmpty()) {
  1375. return@handleTicketStatus
  1376. }
  1377. if (isNeedLoading) sendEventMsg(
  1378. MsgEvent(
  1379. MSG_EVENT_LOADING, LoadingMsg(false, "工作票完成状态读取完成", null)
  1380. )
  1381. )
  1382. LogUtil.i("Get ticket status complete : ${bleDevice.mac}")
  1383. BleReturnDispatcher.removeBusy(bleDevice.mac)
  1384. // TD:Ticket Done
  1385. if (isNeedLoading) sendEventMsg(
  1386. MsgEvent(
  1387. MSG_EVENT_LOADING, LoadingMsg(false, "TD$ticketJson}", true)
  1388. )
  1389. )
  1390. val workTicketGetBO = try {
  1391. Gson().fromJson(ticketJson, WorkTicketGetBO::class.java)
  1392. } catch (e: Exception) {
  1393. null
  1394. }
  1395. if (workTicketGetBO == null) {
  1396. ToastUtils.tip(R.string.ticket_data_error)
  1397. return@handleTicketStatus
  1398. }
  1399. // 判断workTicketGetBO里是否有未完成的
  1400. ThreadUtils.runOnIO {
  1401. val finishedStatus = workTicketGetBO.hasFinished()
  1402. LogUtil.i("作业票结束情况:${finishedStatus}")
  1403. if (finishedStatus.first) {
  1404. Executor.delayOnMain(500) {
  1405. handleKeyReturn(bleDevice, workTicketGetBO, finishedStatus.second)
  1406. //检查钥匙是否代取,如果是的话给钥匙
  1407. val keyBean = ModBusController.getKeyByMac(bleDevice.mac)
  1408. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.nfc == keyBean?.rfid }
  1409. ?.let { itKey ->
  1410. LogUtil.i("检查到存在待取钥匙:${itKey}")
  1411. sendLoadingEventMsg(
  1412. MyApplication.instance?.applicationContext!!.getString(
  1413. R.string.ble_connecting
  1414. )
  1415. )
  1416. handleGiveKey(itKey)
  1417. }
  1418. }
  1419. } else {
  1420. // 当前策略:作业票未完成禁止归还钥匙
  1421. withContext(Dispatchers.Main) {
  1422. showKeyReturnUploadDataForceDialog({
  1423. handleKeyReturn(bleDevice, workTicketGetBO, finishedStatus.second)
  1424. //检查钥匙是否代取,如果是的话给钥匙
  1425. val keyBean = ModBusController.getKeyByMac(bleDevice.mac)
  1426. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.nfc == keyBean?.rfid }
  1427. ?.let { itKey ->
  1428. sendLoadingEventMsg(
  1429. MyApplication.instance?.applicationContext!!.getString(
  1430. R.string.ble_connecting
  1431. )
  1432. )
  1433. handleGiveKey(itKey)
  1434. }
  1435. }) {
  1436. sendLoadingEventMsg(null, false)
  1437. ToastUtils.tip(R.string.continue_the_ticket)
  1438. BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
  1439. // 打开卡扣,防止初始化的时候选择不处理钥匙导致无法使用
  1440. val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
  1441. val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
  1442. keyBean?.let {
  1443. ModBusController.controlKeyBuckle(true, keyBean.isLeft, dock.addr)
  1444. }
  1445. }
  1446. }
  1447. }
  1448. }
  1449. }
  1450. }
  1451. /**
  1452. * ticketFinished主要是后端的作业票是否已经结束,结束了,就直接修改状态就好了
  1453. */
  1454. private fun handleKeyReturn(
  1455. bleDevice: BleDevice, workTicketGetBO: WorkTicketGetBO?, ticketFinished: Boolean
  1456. ) {
  1457. val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
  1458. val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
  1459. keyBean?.let {
  1460. ModBusController.controlKeyBuckle(false, keyBean.isLeft, dock.addr)
  1461. }
  1462. if (ticketFinished) {
  1463. mDeviceTakeList.removeIf { it.nfc == keyBean?.rfid }
  1464. switchReadyMode(bleDevice)
  1465. } else {
  1466. // 上报隔离点状态
  1467. val keyNfc = ModBusController.getKeyByMac(bleDevice.mac)?.rfid ?: "key rfid lost"
  1468. workTicketGetBO?.data?.forEach { data ->
  1469. val updateList = mutableListOf<LockPointUpdateReqVO>()
  1470. data.dataList?.filter { it.closed == 1 && it.status == it.target }
  1471. ?.forEach { dataListDTO ->
  1472. val updateVO = LockPointUpdateReqVO(
  1473. data.taskCode?.toLong(),
  1474. dataListDTO.infoRfidNo,
  1475. dataListDTO.equipRfidNo,
  1476. keyNfc,
  1477. dataListDTO.target,
  1478. dataListDTO.status
  1479. )
  1480. updateList.add(updateVO)
  1481. }
  1482. sendLoadingEventMsg(null, false)
  1483. if (CAN_RETURN) {
  1484. //如果需要上报的点位数据为空则直接上报钥匙归还
  1485. if (updateList.isEmpty()) {
  1486. mDeviceTakeList.removeIf { it.nfc == keyBean?.rfid }
  1487. // 上报钥匙归还
  1488. keyReturn(data.taskCode?.toLong()!!, keyNfc)
  1489. switchReadyMode(bleDevice)
  1490. return@forEach
  1491. }
  1492. // 上报点位钥匙绑定
  1493. NetApi.updateLockPointBatch(updateList) { isSuccess, msg, code ->
  1494. LogUtil.i("还锁操作:${isSuccess},${msg},${code}")
  1495. if (isSuccess) {
  1496. // 上报钥匙归还
  1497. keyReturn(data.taskCode?.toLong()!!, keyNfc)
  1498. data.taskCode?.toLong()?.let {
  1499. sendEventMsg(
  1500. MsgEvent(
  1501. MSG_EVENT_UPDATE_TICKET_PROGRESS,
  1502. UpdateTicketProgressMsg(it)
  1503. )
  1504. )
  1505. }
  1506. // 确认归还,切换为待机模式
  1507. switchReadyMode(bleDevice)
  1508. } else {
  1509. ThreadUtils.runOnMain {
  1510. // 当前策略:作业票未完成禁止归还钥匙
  1511. showKeyReturnDialog {
  1512. sendLoadingEventMsg(null, false)
  1513. ToastUtils.tip(R.string.continue_the_ticket)
  1514. BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
  1515. // 打开卡扣,防止初始化的时候选择不处理钥匙导致无法使用
  1516. if (workTicketGetBO.data?.all { it.dataList?.all { it.closed == 1 } == true } == true) {
  1517. workTicketGetBO.data?.firstOrNull()?.taskCode?.toLong()
  1518. ?.let {
  1519. checkStepAndTicketDetailThenSendTicket(
  1520. it, bleDevice.mac
  1521. )
  1522. }
  1523. } else {
  1524. val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
  1525. val keyBean =
  1526. dock?.getKeyList()?.find { it.mac == bleDevice.mac }
  1527. keyBean?.let {
  1528. ModBusController.controlKeyBuckle(
  1529. true, keyBean.isLeft, dock.addr
  1530. )
  1531. }
  1532. }
  1533. }
  1534. }
  1535. SPUtils.clearUpdateKeyReturn(MyApplication.instance!!)
  1536. SPUtils.clearUpdateLockPoint(MyApplication.instance!!)
  1537. }
  1538. }
  1539. } else {
  1540. SPUtils.saveUpdateLockPoint(MyApplication.instance!!, updateList)
  1541. SPUtils.saveUpdateKeyReturn(
  1542. MyApplication.instance!!,
  1543. UpdateKeyReturnBO(data.taskCode?.toLong()!!, keyNfc!!)
  1544. )
  1545. // 保存待发数据,切换为待机模式
  1546. switchReadyMode(bleDevice)
  1547. }
  1548. }
  1549. }
  1550. }
  1551. /**
  1552. * 钥匙归还
  1553. */
  1554. private fun keyReturn(ticketId: Long, keyNfc: String) {
  1555. NetApi.updateKeyReturn(
  1556. ticketId,
  1557. keyNfc,
  1558. MyApplication.instance!!.serialNo()
  1559. ) { isSuccess, msg, code ->
  1560. if (!isSuccess) {
  1561. if (msg == MyApplication.instance?.applicationContext!!.getString(
  1562. R.string.ticket_lost
  1563. )
  1564. ) {
  1565. sendEventMsg(
  1566. MsgEvent(
  1567. MsgEventConstants.MSG_EVENT_TICKET_FINISHED, null
  1568. )
  1569. )
  1570. }
  1571. SPUtils.clearUpdateKeyReturn(MyApplication.instance!!)
  1572. ToastUtils.tip(R.string.key_return_success)
  1573. } else {
  1574. ToastUtils.tip(R.string.key_return_success)
  1575. }
  1576. }
  1577. }
  1578. /**
  1579. * 处理虚拟钥匙取出,如果作业的全部点位已经上锁更新钥匙的状态使用
  1580. */
  1581. fun handleVirtualKeyGive(taskCode: Long, keyNfc: String, done: () -> Unit) {
  1582. // 上报钥匙归还
  1583. NetApi.updateKeyTake(taskCode, keyNfc, MyApplication.instance!!.serialNo()) { isSuccess ->
  1584. if (isSuccess) {
  1585. done()
  1586. }
  1587. }
  1588. }
  1589. /**
  1590. * 处理虚拟钥匙归还,如果作业的全部点位已经上锁更新钥匙的状态使用
  1591. */
  1592. fun handleVirtualKeyReturn(taskCode: Long, keyNfc: String, done: () -> Unit) {
  1593. // 上报钥匙归还
  1594. NetApi.updateKeyReturn(
  1595. taskCode, keyNfc, MyApplication.instance!!.serialNo()
  1596. ) { isSuccess, msg, code ->
  1597. if (!isSuccess) {
  1598. if (msg == MyApplication.instance?.applicationContext!!.getString(
  1599. R.string.ticket_lost
  1600. )
  1601. ) {
  1602. sendEventMsg(
  1603. MsgEvent(
  1604. MsgEventConstants.MSG_EVENT_TICKET_FINISHED, null
  1605. )
  1606. )
  1607. }
  1608. SPUtils.clearUpdateKeyReturn(MyApplication.instance!!)
  1609. } else {
  1610. done()
  1611. sendEventMsg(
  1612. MsgEvent(
  1613. MSG_EVENT_UPDATE_TICKET_PROGRESS, UpdateTicketProgressMsg(taskCode)
  1614. )
  1615. )
  1616. }
  1617. }
  1618. }
  1619. fun switchReadyMode(bleDevice: BleDevice) {
  1620. BleCmdManager.switchMode(STATUS_READY, bleDevice, object : CustomBleWriteCallback() {
  1621. override fun onWriteSuccess(
  1622. bleDevice: BleDevice,
  1623. characteristic: BluetoothGattCharacteristic,
  1624. current: Int,
  1625. total: Int,
  1626. justWrite: ByteArray,
  1627. data: ByteArray
  1628. ) {
  1629. LogUtil.i("switch mode ready success : ${bleDevice.mac}")
  1630. }
  1631. override fun onWriteFailure(
  1632. bleDevice: BleDevice,
  1633. characteristic: BluetoothGattCharacteristic?,
  1634. exception: BleException,
  1635. current: Int,
  1636. total: Int,
  1637. justWrite: ByteArray?,
  1638. data: ByteArray?,
  1639. isTotalFail: Boolean
  1640. ) {
  1641. LogUtil.e("switch mode ready fail : ${bleDevice.mac}")
  1642. Executor.delayOnMain(300) {
  1643. switchReadyMode(bleDevice)
  1644. }
  1645. }
  1646. })
  1647. }
  1648. /**
  1649. * 获取工作票完成情况
  1650. */
  1651. private fun getTicketStatus(
  1652. bleDevice: BleDevice,
  1653. isNeedLoading: Boolean = false,
  1654. processCallback: ((Boolean) -> Unit)? = null
  1655. ) {
  1656. if (isNeedLoading) sendEventMsg(
  1657. MsgEvent(
  1658. MSG_EVENT_LOADING, LoadingMsg(true, "开始获取工作票", null)
  1659. )
  1660. )
  1661. BleCmdManager.getTicketStatus(bleDevice, object : CustomBleWriteCallback() {
  1662. override fun onWriteSuccess(
  1663. bleDevice: BleDevice,
  1664. characteristic: BluetoothGattCharacteristic,
  1665. current: Int,
  1666. total: Int,
  1667. justWrite: ByteArray,
  1668. data: ByteArray
  1669. ) {
  1670. if (isNeedLoading) sendEventMsg(
  1671. MsgEvent(
  1672. MSG_EVENT_LOADING, LoadingMsg(false, "工作票获取成功", null)
  1673. )
  1674. )
  1675. LogUtil.i("getTicketStatus success")
  1676. }
  1677. override fun onWriteFailure(
  1678. bleDevice: BleDevice,
  1679. characteristic: BluetoothGattCharacteristic?,
  1680. exception: BleException,
  1681. current: Int,
  1682. total: Int,
  1683. justWrite: ByteArray?,
  1684. data: ByteArray?,
  1685. isTotalFail: Boolean
  1686. ) {
  1687. if (isNeedLoading) sendEventMsg(
  1688. MsgEvent(
  1689. MSG_EVENT_LOADING, LoadingMsg(false, "工作票获取失败", false)
  1690. )
  1691. )
  1692. processCallback?.invoke(false)
  1693. LogUtil.e("getTicketStatus fail")
  1694. }
  1695. })
  1696. }
  1697. /**
  1698. * 添加待更新取出状态的设备
  1699. */
  1700. fun addDeviceTake(deviceType: Int, ticketId: Long, nfc: String?) {
  1701. LogUtil.i("addDeviceTake : $deviceType - $ticketId - $nfc")
  1702. mDeviceTakeList.removeIf { it.deviceType == deviceType && it.nfc == nfc }
  1703. mDeviceTakeList.add(DeviceTakeUpdateBO(deviceType, ticketId, nfc!!))
  1704. }
  1705. fun removeDeviceTake(deviceType: Int, nfc: String?) {
  1706. LogUtil.i("removeDeviceTake : $deviceType - $nfc")
  1707. mDeviceTakeList.removeIf { it.deviceType == deviceType && it.nfc == nfc }
  1708. }
  1709. private fun handleDeviceTake(deviceTakeUpdateBO: DeviceTakeUpdateMsg, rfid: String? = null) {
  1710. LogUtil.i("$deviceTakeUpdateBO")
  1711. when (deviceTakeUpdateBO.deviceType) {
  1712. // 钥匙
  1713. 0 -> {
  1714. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.nfc == deviceTakeUpdateBO.nfc }
  1715. ?.let { info ->
  1716. if (mDeviceTakeList.any { it.deviceType == DeviceConst.DEVICE_TYPE_LOCK && it.ticketId == info.ticketId }) {
  1717. LogUtil.i("存在未取出的挂锁,不继续操作")
  1718. return
  1719. }
  1720. sendLoadingEventMsg(null, false)
  1721. NetApi.updateKeyTake(
  1722. info.ticketId, info.nfc, MyApplication.instance?.serialNo()!!
  1723. ) { isSuccess ->
  1724. if (isSuccess) {
  1725. mDeviceTakeList.removeIf {
  1726. it.deviceType == DEVICE_TYPE_KEY && it.nfc == info.nfc && it.ticketId ==
  1727. info.ticketId
  1728. }
  1729. sendEventMsg(
  1730. MsgEvent(
  1731. MSG_EVENT_UPDATE_TICKET_PROGRESS,
  1732. UpdateTicketProgressMsg(info.ticketId)
  1733. )
  1734. )
  1735. //钥匙取出之后重新再连一把钥匙待机
  1736. ModBusController.getKeyByRfid(
  1737. info.nfc
  1738. )?.mac?.let {
  1739. unregisterConnectListener(it)
  1740. }
  1741. //待机数不够就再连一把,但不能是原来那把
  1742. ModBusController.getKeyByRfid(
  1743. info.nfc
  1744. )?.mac?.let {
  1745. ThreadUtils.runOnIO {
  1746. checkMyTodoForHandleKey(it)
  1747. }
  1748. }
  1749. }
  1750. }
  1751. } ?: sendLoadingEventMsg(null, false)
  1752. }
  1753. // 挂锁
  1754. 1 -> {
  1755. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_LOCK && it.nfc == deviceTakeUpdateBO.nfc }
  1756. ?.let { info ->
  1757. NetApi.updateLockTake(
  1758. mutableListOf(
  1759. LockTakeUpdateReqVO(
  1760. info.ticketId, info.nfc, MyApplication.instance?.serialNo()!!
  1761. )
  1762. )
  1763. ) { isSuccess ->
  1764. Executor.runOnMain {
  1765. if (isSuccess == false) {
  1766. LogUtil.e("Lock take report fail")
  1767. ToastUtils.tip(R.string.lock_take_report_fail)
  1768. SPUtils.saveTicketTakeLockException(info.ticketId)
  1769. mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_LOCK && it.nfc == info.nfc }
  1770. mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_KEY && it.ticketId == info.ticketId }
  1771. sendLoadingEventMsg(null, false)
  1772. return@runOnMain
  1773. }
  1774. // 检查是不是要发钥匙了
  1775. mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_LOCK && it.nfc == info.nfc }
  1776. // 检查当前工作票是否取完挂锁
  1777. if (mDeviceTakeList.any { it.deviceType == DEVICE_TYPE_LOCK && it.ticketId == info.ticketId }) {
  1778. LogUtil.i("Waiting all locks to take out")
  1779. sendLoadingEventMsg(
  1780. MyApplication.instance?.applicationContext?.getString(
  1781. R.string.take_out_lock_tip,
  1782. mDeviceTakeList.count { it.deviceType == DEVICE_TYPE_LOCK && it.ticketId == info.ticketId })
  1783. )
  1784. ToastUtils.tip(R.string.take_out_rest_locks)
  1785. return@runOnMain
  1786. } else {
  1787. LogUtil.i("All locks are taken")
  1788. sendLoadingEventMsg(null, false)
  1789. }
  1790. if (SPUtils.getTicketTakeLockException(info.ticketId)) {
  1791. ToastUtils.tip(R.string.current_ticket_report_lock_take_exception_tip)
  1792. return@runOnMain
  1793. }
  1794. // 检查有无当前工作票的钥匙
  1795. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.ticketId == info.ticketId }
  1796. ?.let { itKey ->
  1797. sendLoadingEventMsg(
  1798. MyApplication.instance?.applicationContext!!.getString(
  1799. R.string.ble_connecting
  1800. )
  1801. )
  1802. handleGiveKey(itKey)
  1803. }
  1804. }
  1805. }
  1806. }
  1807. }
  1808. }
  1809. }
  1810. /**
  1811. * 分配钥匙
  1812. */
  1813. private fun handleGiveKey(deviceTakeUpdateBO: DeviceTakeUpdateBO) {
  1814. getBleDeviceByMac(ModBusController.getKeyByRfid(deviceTakeUpdateBO.nfc)?.mac)?.let {
  1815. getCurrentStatus(
  1816. 2,
  1817. getBleDeviceByMac(ModBusController.getKeyByRfid(deviceTakeUpdateBO.nfc)?.mac)!!.bleDevice
  1818. ) {
  1819. if (!it) {
  1820. return@getCurrentStatus
  1821. }
  1822. LogUtil.w("handleGiveKey timeout")
  1823. removeDeviceTake(DEVICE_TYPE_KEY, deviceTakeUpdateBO.nfc)
  1824. checkEquipCount(0, true) { keyPair, lockMap ->
  1825. if (keyPair == null) {
  1826. ThreadUtils.runOnMain {
  1827. val tipDialog = TipDialog(SIKCore.getApplication())
  1828. tipDialog.setTip(
  1829. SIKCore.getApplication().getString(R.string.key_take_error_tip)
  1830. )
  1831. tipDialog.setConfirmListener {
  1832. tipDialog.dismiss()
  1833. sendEventMsg(
  1834. MsgEvent(
  1835. MSG_EVENT_DEVICE_EXCEPTION,
  1836. DeviceExceptionMsg(DEVICE_TYPE_KEY, deviceTakeUpdateBO.nfc)
  1837. )
  1838. )
  1839. }
  1840. tipDialog.show()
  1841. }
  1842. } else {
  1843. addDeviceTake(
  1844. DEVICE_TYPE_KEY, deviceTakeUpdateBO.ticketId, keyPair.second?.rfid!!
  1845. )
  1846. handleGiveKey(
  1847. DeviceTakeUpdateBO(
  1848. DEVICE_TYPE_KEY, deviceTakeUpdateBO.ticketId, keyPair.second?.rfid!!
  1849. )
  1850. )
  1851. }
  1852. }
  1853. }
  1854. } ?: run {
  1855. ThreadUtils.runOnMain {
  1856. ActivityTracker.getCurrentActivity()?.let {
  1857. val tipDialog = TipDialog(it)
  1858. tipDialog.setTip(
  1859. SIKCore.getApplication().getString(R.string.key_take_error_tip)
  1860. )
  1861. tipDialog.setConfirmListener {
  1862. tipDialog.dismiss()
  1863. sendEventMsg(
  1864. MsgEvent(
  1865. MSG_EVENT_DEVICE_EXCEPTION,
  1866. DeviceExceptionMsg(DEVICE_TYPE_KEY, deviceTakeUpdateBO.nfc)
  1867. )
  1868. )
  1869. }
  1870. tipDialog.show()
  1871. }
  1872. }
  1873. }
  1874. }
  1875. /**
  1876. * 根据当前模式进行处理
  1877. */
  1878. private fun handleCurrentMode(currentModeMsg: CurrentModeMsg) {
  1879. when (currentModeMsg.mode) {
  1880. // 工作模式
  1881. 0x01.toByte() -> {
  1882. // 读工作票
  1883. getTicketStatusBusiness(currentModeMsg.bleBean.bleDevice.mac)
  1884. }
  1885. // 待机模式
  1886. 0x02.toByte() -> {
  1887. // 根据情况看是否需要下发工作票
  1888. ModBusController.getKeyByMac(currentModeMsg.bleBean.bleDevice.mac)?.let { key ->
  1889. // 判断是否有待取的钥匙
  1890. val updateBo =
  1891. mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && key.rfid == it.nfc }
  1892. if (mDeviceTakeList.any { it.deviceType == DEVICE_TYPE_LOCK && it.ticketId == updateBo?.ticketId }) {
  1893. //todo 如果有钥匙待取但是对应的作业票的锁还有的,就不发
  1894. return
  1895. }
  1896. updateBo?.let { itBO ->
  1897. if (BleReturnDispatcher.isConnected(currentModeMsg.bleBean.bleDevice.mac)) {
  1898. LogUtil.i("当前钥匙在归还队列,断开连接")
  1899. BleReturnDispatcher.scheduleDisconnect(currentModeMsg.bleBean.bleDevice.mac)
  1900. }
  1901. if (BleSendDispatcher.isConnected(currentModeMsg.bleBean.bleDevice.mac)) {
  1902. LogUtil.i("当前钥匙已在发送队列连接")
  1903. checkAndSendTicket(currentModeMsg, itBO)
  1904. } else {
  1905. LogUtil.i("当前钥匙未加入发送队列,连接后发送")
  1906. BleSendDispatcher.submit(currentModeMsg.bleBean.bleDevice.mac) {
  1907. checkAndSendTicket(currentModeMsg, itBO)
  1908. }
  1909. }
  1910. } ?: let {
  1911. ModBusController.updateKeyReadyStatus(
  1912. currentModeMsg.bleBean.bleDevice.mac, true, 4
  1913. )
  1914. sendLoadingEventMsg(null, false)
  1915. BleReturnDispatcher.scheduleDisconnect(currentModeMsg.bleBean.bleDevice.mac)
  1916. //连上之后没有工作票要下发就断开 看是否还有设备等待连接,没有就不断开,有就让路,一般是初始化的时候
  1917. ThreadUtils.runOnIO {
  1918. checkMyTodoForHandleKey(currentModeMsg.bleBean.bleDevice.mac)
  1919. }
  1920. }
  1921. } ?: let {
  1922. ModBusController.updateKeyReadyStatus(
  1923. currentModeMsg.bleBean.bleDevice.mac, true, 4
  1924. )
  1925. sendLoadingEventMsg(null, false)
  1926. BleReturnDispatcher.scheduleDisconnect(currentModeMsg.bleBean.bleDevice.mac)
  1927. //连上之后没有工作票要下发就断开 看是否还有设备等待连接,没有就不断开,有就让路,一般是初始化的时候
  1928. ThreadUtils.runOnIO {
  1929. checkMyTodoForHandleKey(currentModeMsg.bleBean.bleDevice.mac)
  1930. }
  1931. }
  1932. }
  1933. // 故障模式
  1934. 0x03.toByte() -> {
  1935. // TODO 上报?
  1936. ToastUtils.tip(
  1937. "${currentModeMsg.bleBean.bleDevice.mac} : " + "${CommonUtils.getStr(R.string.key_is_in_failure_mode)}"
  1938. )
  1939. }
  1940. }
  1941. }
  1942. /**
  1943. * 检查并下发作业票
  1944. */
  1945. private fun checkAndSendTicket(currentModeMsg: CurrentModeMsg, itBO: DeviceTakeUpdateBO) {
  1946. NetApi.getStepDetail(itBO.ticketId) {
  1947. var step = 0
  1948. it?.filter { it.stepStatus == "1" }
  1949. ?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
  1950. step = it
  1951. }
  1952. NetApi.getTicketDetail(itBO.ticketId) { ticketDetail, _ ->
  1953. if (ticketDetail == null) {
  1954. return@getTicketDetail
  1955. }
  1956. val role = ticketDetail?.ticketUserVOList?.find {
  1957. it.userId == SPUtils.getLoginUser(MyApplication.instance?.applicationContext!!)?.userId && it.userType == USER_TYPE_LOCKER
  1958. }
  1959. if (role == null) {
  1960. ToastUtils.tip(R.string.you_are_not_locker_tip)
  1961. return@getTicketDetail
  1962. }
  1963. if (step == 4) { // 上锁工作票
  1964. sendTicketBusiness(
  1965. true,
  1966. currentModeMsg.bleBean.bleDevice.mac,
  1967. ticketDetail,
  1968. ticketDetail.ticketLockVOList?.filter {
  1969. ticketDetail.ticketPointsVOList?.mapNotNull { it.lockId }
  1970. ?.contains(it.lockId) != true
  1971. }?.map { it.lockNfc }?.toMutableList(),
  1972. ActivityUtils.currentActivity() as BaseActivity<*>,
  1973. true
  1974. )
  1975. } else if (step == 7) { // 解锁工作票
  1976. sendTicketBusiness(
  1977. false,
  1978. currentModeMsg.bleBean.bleDevice.mac,
  1979. ticketDetail,
  1980. null,
  1981. ActivityUtils.currentActivity() as BaseActivity<*>,
  1982. true
  1983. )
  1984. }
  1985. }
  1986. }
  1987. }
  1988. /**
  1989. * 检查步骤和作业票详情并且下发作业票
  1990. */
  1991. private fun checkStepAndTicketDetailThenSendTicket(ticketId: Long, mac: String) {
  1992. NetApi.getStepDetail(ticketId) {
  1993. var step = 0
  1994. it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
  1995. step = it
  1996. }
  1997. NetApi.getTicketDetail(ticketId) { ticketDetail, _ ->
  1998. if (ticketDetail == null) {
  1999. return@getTicketDetail
  2000. }
  2001. val role = ticketDetail?.ticketUserVOList?.find {
  2002. it.userId == SPUtils.getLoginUser(MyApplication.instance?.applicationContext!!)?.userId && it.userType == USER_TYPE_LOCKER
  2003. }
  2004. if (role == null) {
  2005. ToastUtils.tip(R.string.you_are_not_locker_tip)
  2006. return@getTicketDetail
  2007. }
  2008. if (step == 4) { // 上锁工作票
  2009. sendTicketBusiness(
  2010. true,
  2011. mac,
  2012. ticketDetail,
  2013. ticketDetail.ticketLockVOList?.filter {
  2014. ticketDetail.ticketPointsVOList?.mapNotNull { it.lockId }
  2015. ?.contains(it.lockId) != true
  2016. }?.map { it.lockNfc }?.toMutableList(),
  2017. ActivityUtils.currentActivity() as BaseActivity<*>,
  2018. true
  2019. )
  2020. } else if (step == 7) { // 解锁工作票
  2021. sendTicketBusiness(
  2022. false,
  2023. mac,
  2024. ticketDetail,
  2025. null,
  2026. ActivityUtils.currentActivity() as BaseActivity<*>,
  2027. true
  2028. )
  2029. }
  2030. }
  2031. }
  2032. }
  2033. fun submitKeyData(context: Context) {
  2034. if (!CAN_RETURN) return
  2035. val updateList = SPUtils.getUpdateLockPoint(context)
  2036. if (updateList.isNotEmpty()) {
  2037. NetApi.updateLockPointBatch(updateList) { isSuccess, msg, code ->
  2038. LogUtil.i("submitKeyData还锁操作:${isSuccess},${msg},${code}")
  2039. if (isSuccess || code == 500) {
  2040. SPUtils.clearUpdateLockPoint(context)
  2041. SPUtils.clearUpdateKeyReturn(context)
  2042. }
  2043. }
  2044. }
  2045. val returnList =
  2046. SPUtils.getUpdateKeyReturn(context).filter { it.keyNfc.isNotEmpty() }.toMutableList()
  2047. if (returnList.isEmpty()) {
  2048. return
  2049. }
  2050. val itemsToRemove = returnList.toList()
  2051. var count = 0
  2052. itemsToRemove.forEach { itData ->
  2053. NetApi.updateKeyReturn(
  2054. itData.ticketId, itData.keyNfc, context.serialNo()
  2055. ) { isSuccess, msg, code ->
  2056. count++
  2057. if (!isSuccess) {
  2058. if (msg == MyApplication.instance?.applicationContext!!.getString(
  2059. R.string.ticket_lost
  2060. )
  2061. ) {
  2062. sendEventMsg(
  2063. MsgEvent(
  2064. MsgEventConstants.MSG_EVENT_TICKET_FINISHED, null
  2065. )
  2066. )
  2067. }
  2068. SPUtils.clearUpdateKeyReturn(MyApplication.instance!!)
  2069. }
  2070. }
  2071. }
  2072. }
  2073. fun sendLoadingEventMsg(str: String?, isShow: Boolean = true) {
  2074. sendEventMsg(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(isShow, str, false)))
  2075. }
  2076. fun logout(context: Context) {
  2077. reConnectKey()
  2078. NetApi.logout()
  2079. // 关所有有设备的卡扣
  2080. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
  2081. .forEach { dockBean ->
  2082. val hasLockIdxList =
  2083. dockBean.getLockList().filter { it.isExist }.map { it.idx } as MutableList<Int>
  2084. val noLockIdxList =
  2085. dockBean.getLockList().filter { !it.isExist }.map { it.idx } as MutableList<Int>
  2086. ModBusController.controlLockBuckle(false, dockBean.addr, hasLockIdxList)
  2087. ModBusController.controlLockBuckle(true, dockBean.addr, noLockIdxList)
  2088. }
  2089. dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
  2090. .forEach { dockBean ->
  2091. dockBean.getKeyList().forEach { key ->
  2092. if (key.isExist) {
  2093. NetApi.getKeyInfo(key.rfid.toString()) {
  2094. if (it != null && !it.macAddress.isNullOrEmpty()) {
  2095. ModBusController.updateKeyMac(
  2096. dockBean.addr, key.isLeft, it.macAddress
  2097. )
  2098. ModBusController.controlKeyBuckle(
  2099. false, key.isLeft, dockBean.addr
  2100. )
  2101. } else {
  2102. ModBusController.controlKeyBuckle(
  2103. true, key.isLeft, dockBean.addr
  2104. )
  2105. }
  2106. }
  2107. } else {
  2108. ModBusController.controlKeyBuckle(true, key.isLeft, dockBean.addr)
  2109. }
  2110. }
  2111. }
  2112. BleSendDispatcher.disconnectAll(60_0000L)
  2113. sendLoadingEventMsg(null, false)
  2114. context.startActivity(Intent(context, LoginActivity::class.java).apply {
  2115. flags = Intent.FLAG_ACTIVITY_NEW_TASK
  2116. })
  2117. }
  2118. /**
  2119. * 钥匙重新连接,清除内部作业票,清除所有代取设备重新分配
  2120. */
  2121. private fun reConnectKey() {
  2122. val keyList = mDeviceTakeList.filter { it.deviceType == DEVICE_TYPE_KEY }
  2123. // 不拿的设备不归你,下次登录重新按需分配
  2124. // 尽早clear,防止触发handleCurrentMode导致重新下发作业票
  2125. mDeviceTakeList.clear()
  2126. // 连接后直接切换待机模式,让钥匙作业票失效并且重新准备完毕
  2127. keyList.forEach {
  2128. val mac = ModBusController.getKeyByRfid(it.nfc)?.mac
  2129. if (mac == null) {
  2130. NetApi.getKeyInfo(it.nfc) { keyInfo ->
  2131. keyInfo?.macAddress?.let { itMac ->
  2132. registerConnectListener(itMac, isSend = true) { isDone, bleBean ->
  2133. if (isDone && bleBean != null) {
  2134. switchReadyMode(bleBean.bleDevice)
  2135. }
  2136. }
  2137. }
  2138. }
  2139. } else {
  2140. registerConnectListener(mac, isSend = true) { isDone, bleBean ->
  2141. if (isDone && bleBean != null) {
  2142. switchReadyMode(bleBean.bleDevice)
  2143. }
  2144. }
  2145. }
  2146. }
  2147. }
  2148. /**
  2149. * 强制使用setValue,防止postValue造成数据丢失
  2150. */
  2151. fun sendEventMsg(msgEvent: MsgEvent) {
  2152. Executor.runOnMain {
  2153. mEventBus.value = msgEvent
  2154. }
  2155. }
  2156. fun addExceptionKey(rfid: String) {
  2157. LogUtil.w("addExceptionKey: $rfid")
  2158. if (mExceptionKeyList.contains(rfid)) {
  2159. return
  2160. }
  2161. mExceptionKeyList.add(rfid)
  2162. }
  2163. fun removeExceptionKey(key: String) {
  2164. LogUtil.i("removeExceptionKey: $key")
  2165. mExceptionKeyList.remove(key)
  2166. }
  2167. }