完善了功能

This commit is contained in:
zxj
2025-07-25 10:36:30 +08:00
parent 5b3773d277
commit c89efd2d6f
10 changed files with 134 additions and 86 deletions
@@ -13,6 +13,7 @@ import android.widget.TextView
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.sw.inbound.utils.DateTimeUtils import com.sw.inbound.utils.DateTimeUtils
@@ -23,9 +24,11 @@ import com.sw.plate.utils.comn.SerialPortManager
import com.sw.platecabinet.R import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.setClickListeners import com.sw.platecabinet.ext.setClickListeners
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.utils.PermissionHelper import com.sw.platecabinet.utils.PermissionHelper
import com.sw.platecabinet.view.CustomDialog import com.sw.platecabinet.view.CustomDialog
import com.sw.platecabinet.viewmodel.SettingViewModel import com.sw.platecabinet.viewmodel.SettingViewModel
import com.sw.platecabinet.viewmodel.UserViewModel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -44,15 +47,23 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
private var mDialogWaiting: CustomDialog? = null private var mDialogWaiting: CustomDialog? = null
private val permissionHelpers = mutableMapOf<Int, PermissionHelper>() private val permissionHelpers = mutableMapOf<Int, PermissionHelper>()
protected var keyEventHelper: ScanGunKeyEventHelper? = null protected var keyEventHelper: ScanGunKeyEventHelper? = null
private val viewModel by viewModels<SettingViewModel>()
// 管理员对应的viewmodel
private val settingViewModel by viewModels<SettingViewModel>()
// 用户对应的viewModel
protected val viewModel by viewModels<UserViewModel>()
private var startTime: Long = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
startTime = System.currentTimeMillis()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
context = this context = this
// disableSystemUICompletely() disableSystemUICompletely()
// 确保内容延伸到导航栏区域 // 确保内容延伸到导航栏区域
// WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
//保持亮屏 //保持亮屏
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
@@ -64,6 +75,8 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
registerDataChange() registerDataChange()
initialize() initialize()
registerKeyEvent() registerKeyEvent()
val durationTime = System.currentTimeMillis() - startTime
Timber.d("启动时间:$durationTime")
} }
/** /**
@@ -84,7 +97,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
* 处理扫描枪数据 * 处理扫描枪数据
*/ */
protected open fun handleScanKeyInfo(scanInfo: String) { protected open fun handleScanKeyInfo(scanInfo: String) {
viewModel.findByPlateNumber(plateNumber = scanInfo) settingViewModel.findByPlateNumber(plateNumber = scanInfo)
} }
override fun dispatchKeyEvent(event: KeyEvent): Boolean { override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@@ -234,8 +247,10 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
* 注册数据监听 * 注册数据监听
*/ */
protected open fun registerDataChange() { protected open fun registerDataChange() {
Timber.d("registerDataChange")
lifecycleScope.launch { lifecycleScope.launch {
viewModel.showLoading.collect { viewModel.showLoading.collect {
Timber.d("registerDataChange 用户 showLoading = $it")
if (it) { if (it) {
showWaitingDialog("") showWaitingDialog("")
} else { } else {
@@ -246,32 +261,35 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
lifecycleScope.launch { lifecycleScope.launch {
viewModel.currentUserInfo.drop(1).collect { viewModel.currentUserInfo.drop(1).collect {
if (it == null) return@collect if (it == null) return@collect
if (it.equipmentBoxCode?.isNotEmpty() == true) { handleLoginSuccess(it, false)
SerialApi.openPlate( }
it.equipmentBoxCode.toInt(), }
object : SerialPortManager.SendCallback { lifecycleScope.launch {
override fun onSuccess() { settingViewModel.showLoading.collect {
MainActivity.start(context, pageType = PageType.PLATE_OPEN) Timber.d("registerDataChange 管理员 showLoading = $it")
} if (it) {
showWaitingDialog("")
override fun onFail(e: Exception?) {
ToastUtils.showToast("柜门打开失败")
}
})
} else { } else {
viewModel.getEquipmentList() hideWaitingDialog()
} }
} }
} }
lifecycleScope.launch { lifecycleScope.launch {
viewModel.equipmentList.drop(1).collect { settingViewModel.searchUserInfo.drop(1).collect {
Timber.d("registerDataChange 管理员 currentUserInfo = $it")
if (it == null) return@collect
handleLoginSuccess(it, true)
}
}
lifecycleScope.launch {
settingViewModel.equipmentList.drop(1).collect {
if (it.isEmpty()) return@collect if (it.isEmpty()) return@collect
val unbindList = it.filter { !it.isBound() } val unbindList = it.filter { !it.isBound() }
if (unbindList.isEmpty()) { if (unbindList.isEmpty()) {
MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL) MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL)
} else { } else {
val firstInfo = unbindList[0] val firstInfo = unbindList[0]
val currentUserInfo = viewModel.currentUserInfo.value val currentUserInfo = settingViewModel.searchUserInfo.value
firstInfo.plateNumber = currentUserInfo?.plateNumber ?: "" firstInfo.plateNumber = currentUserInfo?.plateNumber ?: ""
MainActivity.start( MainActivity.start(
context = context, context = context,
@@ -283,6 +301,33 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
} }
} }
/**
* 处理登录成功操作
* @param isAdmin true 管理员 执行绑盘此操作 false 用户,提示错误
*/
fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
viewModel.resetUserInfo()
if (equipmentUserInfo.equipmentBoxCode?.isNotEmpty() == true) {
SerialApi.openPlate(
equipmentUserInfo.equipmentBoxCode.toInt(),
object : SerialPortManager.SendCallback {
override fun onSuccess() {
MainActivity.start(context, pageType = PageType.PLATE_OPEN)
}
override fun onFail(e: Exception?) {
ToastUtils.showToast("柜门打开失败")
}
})
} else {
if (isAdmin) {
settingViewModel.getEquipmentList()
} else {
ToastUtils.showToast("无餐盘信息")
}
}
}
override fun onDestroy() { override fun onDestroy() {
timeJob?.cancel() timeJob?.cancel()
keyEventHelper?.onDestroy() keyEventHelper?.onDestroy()
@@ -12,7 +12,6 @@ import android.view.ViewTreeObserver
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo import com.arcsoft.face.ErrorInfo
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.ConfigUtil import com.sw.plate.utils.arcface.ConfigUtil
@@ -31,9 +30,7 @@ import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.utils.PermissionHelper import com.sw.platecabinet.utils.PermissionHelper
import com.sw.platecabinet.viewmodel.UserViewModel import com.sw.platecabinet.utils.ThreadUtils
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
/** /**
@@ -41,7 +38,6 @@ import timber.log.Timber
*/ */
class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(), class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
ViewTreeObserver.OnGlobalLayoutListener { ViewTreeObserver.OnGlobalLayoutListener {
private val viewModel by viewModels<UserViewModel>()
private val recognizeViewModel by viewModels<RecognizeViewModel>() private val recognizeViewModel by viewModels<RecognizeViewModel>()
private val CAMERA_PERMISSION_REQUEST_CODE = 100 private val CAMERA_PERMISSION_REQUEST_CODE = 100
@@ -60,7 +56,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
} }
override fun initialize() { override fun initialize() {
viewModel.activeEngine() ThreadUtils.launch {
viewModel.activeEngine()
}
initArcViewModel() initArcViewModel()
initArcView() initArcView()
openRectInfoDraw = true openRectInfoDraw = true
@@ -72,20 +71,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
} }
} }
override fun registerDataChange() {
super.registerDataChange()
lifecycleScope.launch {
viewModel.currentUserInfo.drop(1).collect {
Timber.d("currentUserInfo it = $it")
if (it != null) {
ToastUtils.showToast("登录成功")
MainActivity.start(context, pageType = PageType.PLATE_CABINET_FULL)
finish()
}
}
}
}
private fun checkCameraPermission() { private fun checkCameraPermission() {
Timber.i("checkCameraPermission") Timber.i("checkCameraPermission")
val permissionHelper = val permissionHelper =
@@ -355,12 +340,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
checkCameraPermission() checkCameraPermission()
} }
// @Override
// protected void onResume() {
// super.onResume();
// resumeCamera();
// }
private fun resumeCamera() { private fun resumeCamera() {
isRecognition = true isRecognition = true
if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) { if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) {
@@ -368,6 +347,12 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
} }
} }
override fun onResume() {
super.onResume()
resumeCamera()
viewModel.resetUserInfo()
}
protected override fun onPause() { protected override fun onPause() {
pauseCamera() pauseCamera()
super.onPause() super.onPause()
@@ -1,19 +1,12 @@
package com.sw.platecabinet.activity package com.sw.platecabinet.activity
import android.content.Intent import android.content.Intent
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.face.Test
import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.viewmodel.UserViewModel import com.sw.platecabinet.utils.KeyboardUtils
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import timber.log.Timber
class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() { class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
private val viewModel by viewModels<UserViewModel>()
override fun inflateViewBinding(): ActivityLoginByPwdBinding { override fun inflateViewBinding(): ActivityLoginByPwdBinding {
return ActivityLoginByPwdBinding.inflate(layoutInflater) return ActivityLoginByPwdBinding.inflate(layoutInflater)
@@ -24,41 +17,27 @@ class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
} }
override fun initialize() { override fun initialize() {
binding.etPhone.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) KeyboardUtils.showKeyboard(v)
}
binding.btnLogin.setOnClickListener { binding.btnLogin.setOnClickListener {
val phone = binding.etPhone.text.toString() val phone = binding.etPhone.text.toString()
val pwd = binding.etPwd.text.toString() val pwd = binding.etPwd.text.toString()
if (phone.isEmpty() || pwd.isEmpty()) { if (phone.isEmpty() || pwd.isEmpty()) {
ToastUtils.showToast("手机或校验码不能为空") ToastUtils.showToast("手机或校验码不能为空")
val test = Test()
for (i in 1..1000) {
test.test1()
}
return@setOnClickListener return@setOnClickListener
} }
viewModel.loginWithPwd(phone = phone, password = pwd) viewModel.loginWithPwd(phone = phone, password = pwd)
KeyboardUtils.hideKeyboard(this)
} }
binding.tvFaceRec.setOnClickListener { binding.tvFaceRec.setOnClickListener {
val intent = Intent(this, LoginByFaceActivity::class.java) val intent = Intent(this, LoginByFaceActivity::class.java)
startActivity(intent) startActivity(intent)
// handleScanKeyInfo(binding.etPwd.text.toString())
} }
} }
override fun registerDataChange() { override fun onResume() {
super.registerDataChange() super.onResume()
lifecycleScope.launch { viewModel.resetUserInfo()
viewModel.currentUserInfo
.drop(1)
.collect {
Timber.d("currentUserInfo it = $it")
if (it != null) {
// ToastUtils.showToast("登录成功")
MainActivity.start(context, pageType = PageType.PLATE_OPEN)
finish()
}
}
}
} }
} }
@@ -22,6 +22,7 @@ import com.sw.platecabinet.ext.maskName
import com.sw.platecabinet.ext.maskPhone import com.sw.platecabinet.ext.maskPhone
import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.SearchResult import com.sw.platecabinet.model.response.SearchResult
import com.sw.platecabinet.utils.KeyboardUtils
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@@ -154,6 +155,7 @@ class BindPlateFragment : BaseFragment<FragmentBindPlateBinding>(
memberId = checkedItem!!.id!!, memberId = checkedItem!!.id!!,
plateNumber = plateNumber plateNumber = plateNumber
) )
KeyboardUtils.hideKeyboard(requireActivity())
} }
binding.tvBack.setOnClickListener { activity?.finish() } binding.tvBack.setOnClickListener { activity?.finish() }
} }
@@ -111,7 +111,7 @@ class SettingListFragment :
if (item.isBound()) { if (item.isBound()) {
val date = DateTimeUtils.parseDateTime(item.updateTime) val date = DateTimeUtils.parseDateTime(item.updateTime)
val timeInMillis = date?.time ?: 0L val timeInMillis = date?.time ?: 0L
val isOldTime = DateTimeUtils.isMoreThan36HoursFromNow(timeInMillis) val isOldTime = DateTimeUtils.isMoreThanHoursFromNow(timeInMillis)
this.llRoot.setBackgroundResource(R.drawable.grid_item_bind) this.llRoot.setBackgroundResource(R.drawable.grid_item_bind)
this.tvNum.setTextColor(resources.getColor(R.color.bind_4E535D)) this.tvNum.setTextColor(resources.getColor(R.color.bind_4E535D))
@@ -73,15 +73,15 @@ object DateTimeUtils {
} }
/** /**
* 判断给定时间是否距离当前时间超过36小时 * 判断给定时间是否距离当前时间超过72小时
* @param timeInMillis 时间戳(毫秒) * @param timeInMillis 时间戳(毫秒)
* @return true 表示超过36小时,false 表示未超过 * @return true 表示超过72小时,false 表示未超过
*/ */
fun isMoreThan36HoursFromNow(timeInMillis: Long): Boolean { fun isMoreThanHoursFromNow(timeInMillis: Long): Boolean {
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
val timeDifference = currentTime - timeInMillis val timeDifference = currentTime - timeInMillis
val hoursDifference = timeDifference / (1000 * 60 * 60) // 毫秒转小时 val hoursDifference = timeDifference / (1000 * 60 * 60) // 毫秒转小时
return hoursDifference >= 36 return hoursDifference >= 72
} }
/** /**
@@ -0,0 +1,29 @@
package com.sw.platecabinet.utils
import android.app.Activity
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
/**
* 键盘工具类
*/
object KeyboardUtils {
/**
* 显示键盘
*/
fun showKeyboard(view: View) {
val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
/**
* 隐藏键盘
*/
fun hideKeyboard(activity: Activity) {
val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val view = activity.currentFocus ?: View(activity)
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
}
@@ -21,8 +21,8 @@ class SettingViewModel : BaseViewModel() {
private val _searchMemberList = MutableStateFlow<List<SearchResult.Member>>(emptyList()) private val _searchMemberList = MutableStateFlow<List<SearchResult.Member>>(emptyList())
val searchMemberList: StateFlow<List<SearchResult.Member>> = _searchMemberList val searchMemberList: StateFlow<List<SearchResult.Member>> = _searchMemberList
private val _currentUserInfo = MutableStateFlow<EquipmentUserInfo?>(null) private val _searchUserInfo = MutableStateFlow<EquipmentUserInfo?>(null)
val currentUserInfo: StateFlow<EquipmentUserInfo?> = _currentUserInfo val searchUserInfo: StateFlow<EquipmentUserInfo?> = _searchUserInfo
var currentPage = 1 var currentPage = 1
var isLoading = false var isLoading = false
@@ -148,9 +148,9 @@ class SettingViewModel : BaseViewModel() {
} }
} }
_currentUserInfo.value = response.data _searchUserInfo.value = response.data
} else { } else {
_currentUserInfo.value = EquipmentUserInfo( _searchUserInfo.value = EquipmentUserInfo(
plateNumber = plateNumber, plateNumber = plateNumber,
equipmentCode = equipmentCode, equipmentCode = equipmentCode,
updateTime = DateTimeUtils.getDateTimeString() updateTime = DateTimeUtils.getDateTimeString()
@@ -140,4 +140,13 @@ class UserViewModel : BaseViewModel() {
} }
} }
} }
/**
* 重置用户信息
*/
fun resetUserInfo() {
Timber.d("resetUserInfo")
_currentUserInfo.value = null
}
} }
@@ -155,11 +155,10 @@ public class ScanGunKeyEventHelper {
* @return * @return
*/ */
public boolean isScanGunEvent(KeyEvent event) { public boolean isScanGunEvent(KeyEvent event) {
if (event == null || event.getDevice() == null) return false;
L.e("event===" + event.getDevice().getName() + L.e("event===" + event.getDevice().getName() +
"===Char===" + event.getCharacters() + "===Char===" + event.getCharacters() +
"===Action===" + event.getAction()); "===Action===" + event.getAction());
return event.getDevice().getName().equals(mDeviceName); return event.getDevice().getName().equals(mDeviceName);
} }
} }