ScanLoginActivity.kt 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package com.example.chemical.ui.login
  2. import android.graphics.Bitmap
  3. import android.os.Bundle
  4. import android.os.Handler
  5. import android.os.Looper
  6. import android.view.LayoutInflater
  7. import android.view.MotionEvent
  8. import android.view.View
  9. import android.widget.ImageView
  10. import android.widget.TextView
  11. import com.bumptech.glide.Glide
  12. import com.bumptech.glide.load.engine.DiskCacheStrategy
  13. import com.bumptech.glide.request.RequestOptions
  14. import com.example.chemical.ChemicalApp
  15. import com.example.chemical.R
  16. import com.example.chemical.databinding.ActivityScanLoginBinding
  17. import com.example.chemical.ui.common.BaseCountDownActivity
  18. import com.example.chemical.utils.MediaPlayerHelper
  19. import com.example.chemical.utils.TimesUils
  20. import com.example.chemical.utils.UiManager
  21. import com.example.chemical.weidith.AuthenticationDialog
  22. import com.example.chemical.weidith.CustomDialog
  23. import com.google.zxing.BarcodeFormat
  24. import com.google.zxing.MultiFormatWriter
  25. import com.google.zxing.WriterException
  26. import com.google.zxing.common.BitMatrix
  27. import com.kongzue.dialogx.dialogs.PopTip
  28. import com.lztek.toolkit.Lztek
  29. import com.rc.core.log.RcLog
  30. import com.rc.httpcore.HttpClient
  31. import com.rc.httpcore.HttpConfig
  32. import com.rc.httpcore.client.ApiRepository
  33. import com.rc.httpcore.exception.NetException
  34. import retrofit2.HttpException
  35. import java.net.ConnectException
  36. import java.net.SocketTimeoutException
  37. //扫码登录
  38. class ScanLoginActivity : BaseCountDownActivity<ActivityScanLoginBinding>() {
  39. private var mLztek: Lztek? = null
  40. private var mDeviceNum: String? = null //设备唯一标识
  41. override fun createViewBinding() = ActivityScanLoginBinding.inflate(LayoutInflater.from(this))
  42. override fun initData() {
  43. super.initData()
  44. MediaPlayerHelper.playRawMp3(this, R.raw.login_wei_xin_sao_ma)
  45. viewBinding.deptName.text = "${ChemicalApp.confs!!.deptName}-${ChemicalApp.confs!!.roomNum}"
  46. viewBinding.tvReturn.text = "返回${ChemicalApp.confs!!.backTime}s"
  47. Glide.with(this)
  48. .load("${HttpConfig.API_BASE_IMG_URL}${ChemicalApp.confs!!.circularLogo}")
  49. .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.AUTOMATIC))
  50. .into(viewBinding.image)
  51. val stringExtra = intent.getStringExtra("mtypes")
  52. val map = mutableMapOf<String, String>()
  53. if (stringExtra != null) {
  54. map["mtypes"] = stringExtra
  55. }
  56. when (stringExtra) {
  57. "1" -> {
  58. viewBinding.linType.visibility = View.GONE
  59. }
  60. "6" -> {
  61. viewBinding.tvFace.visibility = View.GONE
  62. }
  63. }
  64. try {
  65. var str = intent.getStringExtra("faceList")
  66. if (str != null) {
  67. map["faceList"] = str
  68. }
  69. } catch (e: Exception) {
  70. }
  71. //人脸识别
  72. viewBinding.tvFace.setOnClickListener {
  73. UiManager.switcher(this, map, FacialLoginActivity::class.java)
  74. finish()
  75. }
  76. //刷卡
  77. viewBinding.tvCrad.setOnClickListener {
  78. UiManager.switcher(this, map, SwipeActivity::class.java)
  79. finish()
  80. }
  81. }
  82. override fun initViews(savedInstanceState: Bundle?) {
  83. super.initViews(savedInstanceState)
  84. val stringExtra = intent.getStringExtra("mtypes")
  85. if (stringExtra == "1") {
  86. viewBinding.linType.visibility = View.GONE
  87. } else if (stringExtra == "5") {
  88. viewBinding.tvCrad.visibility = View.GONE
  89. }
  90. val map = mutableMapOf<String, String>()
  91. if (stringExtra != null) {
  92. map["mtypes"] = stringExtra
  93. }
  94. viewBinding.tvFace.setOnClickListener {
  95. var str = intent.getStringExtra("faceList")
  96. if (str != null) {
  97. map["faceList"] = str
  98. }
  99. UiManager.switcher(this, map, FacialLoginActivity::class.java)
  100. finish()
  101. }
  102. viewBinding.tvCrad.setOnClickListener {
  103. UiManager.switcher(this, map, SwipeActivity::class.java)
  104. finish()
  105. }
  106. val currentDateTime = TimesUils.getCurrentDateTime()
  107. mLztek = Lztek.create(this)
  108. val toUpperCase = mLztek!!.ethMac.toUpperCase()
  109. mDeviceNum = toUpperCase.replace(":", "")
  110. RcLog.info("=========当前设备得mac地址$mDeviceNum")
  111. val text =
  112. HttpConfig.API_BASE_QC_URL + "?code=${currentDateTime}&subId=${ChemicalApp.subjectId!!}&type=11&macId=${mDeviceNum}" // 要生成二维码的文本内容
  113. val width = 130 // 二维码宽度
  114. val height = 130 // 二维码高度
  115. loadQRCodeIntoImageView(text, width, height, viewBinding.img)
  116. myHandler.start()
  117. viewBinding.tvReturn.setOnClickListener { finish() }
  118. }
  119. private val myHandler = MyHandler {
  120. logInAuthScan()
  121. }
  122. //用户登录
  123. private fun logInAuthScan() {
  124. HttpClient.token = null
  125. showLoading("查询中...")
  126. val currentDateTime = TimesUils.getCurrentDateTime()
  127. RcLog.info("=获取时间作为code$currentDateTime")
  128. val disposable =
  129. ApiRepository.getScanCode(mDeviceNum!!, currentDateTime, ChemicalApp.subjectId!!)
  130. .subscribe({ data ->
  131. dismissLoading()
  132. myHandler.stop()
  133. ChemicalApp.userData = data
  134. // ChemicalApp!!.userData!!.cardNum = data.cardNum
  135. authenticationInfo(data.userId, ChemicalApp.subjectId!!)
  136. }, { throwable ->
  137. dismissLoading()
  138. throwableView(throwable)
  139. })
  140. addDisposable(disposable)
  141. }
  142. //验证当前人员身份
  143. private fun authenticationInfo(userId: String, subId: String) {
  144. showLoading("验证中...")
  145. val disposable = ApiRepository.userCardValidation(userId, subId)
  146. .subscribe({ data ->
  147. dismissLoading()
  148. val allFalse = with(data) {
  149. cabinetAdmin == false &&
  150. belongUser == false &&
  151. toipcUser == false &&
  152. safeUser == false &&
  153. collegeAdmin == false &&
  154. schoolLevelAdmin == false &&
  155. adminUser == false
  156. apply == false &&
  157. white == false
  158. }
  159. if (allFalse) {
  160. HttpClient.token = null
  161. ChemicalApp.userData = null
  162. customDialogView(2, "当前身份不符合")
  163. } else {
  164. //校级管理员 schoolLevelAdmin
  165. //院级管理员 collegeAdmin
  166. //实验室负责人 adminUser
  167. //安全负责人 safeUser
  168. //柜锁管理员 cabinetAdmin
  169. //是否化学品归属人 belongUser
  170. //是否化学品归属课题组下成员 toipcUser
  171. if (data.schoolLevelAdmin == true || data.collegeAdmin == true) {
  172. authenticationDialog(data.faceImg, data.userName)
  173. } else if (data.adminUser == true || data.safeUser == true || data.cabinetAdmin == true) {
  174. //实验室负责人 or 安全负责人 or 柜锁管理员
  175. authenticationDialog(data.faceImg, data.userName)
  176. } else if (data.belongUser == true || data.toipcUser == true) { //当前身份 归属人or课题组
  177. authenticationDialog(data.faceImg, data.userName)
  178. } else if (data.white == true || data.apply == true) {// 白名单和实验室准入
  179. authenticationDialog(data.faceImg, data.userName)
  180. } else {
  181. HttpClient.token = null
  182. ChemicalApp.userData = null
  183. customDialogView(2, "当前身份不符合")
  184. }
  185. }
  186. }, { throwable ->
  187. PopTip.show(throwable.message)
  188. dismissLoading()
  189. HttpClient.token = null
  190. ChemicalApp.userData = null
  191. })
  192. addDisposable(disposable)
  193. }
  194. // 生成二维码的函数
  195. private fun generateQRCode(text: String, width: Int, height: Int): Bitmap? {
  196. try {
  197. val bitMatrix: BitMatrix =
  198. MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height)
  199. val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
  200. for (x in 0 until width) {
  201. for (y in 0 until height) {
  202. bitmap.setPixel(
  203. x,
  204. y,
  205. if (bitMatrix[x, y]) 0xFF000000.toInt() else 0xFFFFFFFF.toInt()
  206. )
  207. }
  208. }
  209. return bitmap
  210. } catch (e: WriterException) {
  211. e.printStackTrace()
  212. }
  213. return null
  214. }
  215. // 使用 Glide 加载二维码到 ImageView
  216. private fun loadQRCodeIntoImageView(
  217. text: String,
  218. width: Int,
  219. height: Int,
  220. imageView: ImageView
  221. ) {
  222. val bitmap = generateQRCode(text, width, height)
  223. bitmap?.let {
  224. Glide.with(this)
  225. .load(it)
  226. .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
  227. .into(imageView)
  228. }
  229. }
  230. override fun onDestroy() {
  231. super.onDestroy()
  232. myHandler.stop()
  233. // 移除回调,以防止内存泄漏
  234. try {
  235. handlerBack.removeCallbacks(countdownRunnable)
  236. } catch (e: Exception) {
  237. }
  238. }
  239. class MyHandler(private val callback: () -> Unit) {
  240. private val handler = Handler()
  241. // private val interval: Long = 10 * 60 * 1000 // 10分钟
  242. private val interval: Long = 3000 // 3秒
  243. private val runnable = object : Runnable {
  244. override fun run() {
  245. callback.invoke()
  246. handler.postDelayed(this, interval)
  247. }
  248. }
  249. fun start() {
  250. handler.postDelayed(runnable, interval)
  251. }
  252. fun stop() {
  253. handler.removeCallbacks(runnable)
  254. handler.removeCallbacksAndMessages(null)
  255. }
  256. }
  257. override fun onBackPressed() {
  258. super.onBackPressed()
  259. finish()
  260. }
  261. override fun cdTime(cd: Int) {
  262. viewBinding.tvReturn.text = "返回${cd}s"
  263. }
  264. private val handlerBack = Handler(Looper.getMainLooper())
  265. private var timeLeftInSeconds = 2
  266. private var mTvView: TextView? = null
  267. private var mDialogsAut: AuthenticationDialog? = null
  268. //身份认证成功
  269. private fun authenticationDialog(faceImg: String?, userName: String) {
  270. MediaPlayerHelper.playRawMp3(this, R.raw.login_ren_zheng_tong_hua)
  271. mDialogsAut = AuthenticationDialog(
  272. this,
  273. faceImg,
  274. ChemicalApp.confs!!.subName,
  275. ChemicalApp.confs!!.deptName,
  276. "${ChemicalApp.confs!!.buildName}${ChemicalApp.confs!!.floorName}",
  277. userName, object : AuthenticationDialog.IClickLit {
  278. override fun onUpView(tvView: TextView) {
  279. mTvView = tvView
  280. }
  281. })
  282. mDialogsAut!!.show()
  283. // 开始倒计时
  284. handlerBack.post(countdownRunnable)
  285. // 获取对话框的 Window 对象
  286. mDialogsAut!!.window?.decorView?.setOnTouchListener { _, event ->
  287. // 判断是否点击了对话框外部空白区域
  288. if (event.action == MotionEvent.ACTION_DOWN) {
  289. val x = event.x
  290. val y = event.y
  291. val dialogView = mDialogsAut!!.window?.decorView
  292. if (dialogView != null && (x < 0 || x > dialogView.width || y < 0 || y > dialogView.height)) {
  293. // 在此处执行点击对话框外部空白区域时的操作
  294. // 例如关闭对话框
  295. // 移除回调,以防止内存泄漏
  296. mDialogsAut!!.dismiss()
  297. finish()
  298. return@setOnTouchListener true
  299. }
  300. }
  301. return@setOnTouchListener false
  302. }
  303. }
  304. private val countdownRunnable = object : Runnable {
  305. override fun run() {
  306. if (timeLeftInSeconds > 0) {
  307. mTvView!!.text = "${timeLeftInSeconds}秒后自动返回首页"
  308. timeLeftInSeconds--
  309. handlerBack.postDelayed(this, 1000)
  310. } else {
  311. mDialogsAut!!.dismiss()
  312. finish()
  313. }
  314. }
  315. }
  316. /**
  317. * 0 没有图标 1 绿色(成功) 2红色(失败)
  318. * 失败或者成功的弹框
  319. */
  320. private fun customDialogView(types: Int, msg: String) {
  321. val customDialog = CustomDialog(this, types, msg)
  322. if (!this.isFinishing && !this.isDestroyed) {
  323. customDialog.show()
  324. }
  325. }
  326. /**
  327. * 异常处理
  328. */
  329. private fun throwableView(throwable: Throwable) {
  330. RcLog.info("${throwable.message}")
  331. // when (throwable) {
  332. // is NetException -> {
  333. // if (throwable.message.isNullOrEmpty()) {
  334. // "接口请求失败(${throwable.code})"
  335. // } else {
  336. // throwable.message!!
  337. // }
  338. // }
  339. // is SocketTimeoutException -> "请求超时,请稍后重试"
  340. // is ConnectException -> "无法连接服务器,请检查网络"
  341. // is HttpException -> "服务器繁忙,请稍后重试"
  342. // else -> null
  343. // }?.let { customDialogView(2, "$it") }
  344. customDialogView(2, "${throwable.message}")
  345. }
  346. }