diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f6181be..664312d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,21 +36,11 @@ - - - - - = mutableListOf() - - // 当前选中货架下标 - private var shelfIndex = 0 - - // 当前温度(摄氏) - private var showTemperatureC = "0" - - // 当前湿度 - private var showHumidity = "0" - - // 仅特定 deviceId 的部署点需要发送开锁指令 - private fun isNeedOpenLock() = App.deviceId == "4787e213-90ab-3e32-88e0-ac271a937751" - - private var deviceName = "" - - private lateinit var binding: ActivityHomeBinding - - private val viewModel: NetViewModel by viewModels() - - // 串口协议解析器,通过回调通知本 Activity - private fun initScaleManager() { - lifecycleScope.launch { - val ok = ScaleManager - .init(activateCode = ProtocolConstants.ACTIVE_MAP[App.deviceId] ?: "") - .onHeartbeat { _, data -> - data.weights.forEach { weight -> - val shelfNo = weight.index - if (shelfNo in 1..list.size) { - list.firstOrNull { it.deviceNo == shelfNo }?.let { model -> - model.weight = weight.grams.toDouble() - val pos = list.indexOf(model) - shelfAdapter.notifyItemChanged(pos) - log("getWeightInfo: deviceNo=${model.deviceNo},realWeight=${weight.grams}") - EventBus.getDefault().post(SendWeightEvent(model.deviceNo, weight.grams)) - } - } - } - } - .onTempReport { _ -> - updateLeftStatus(deviceName) - } - .onLog { message -> log(message) } - .start { data -> - lastDataReceivedTime = System.currentTimeMillis() - noDataWarningDialog?.takeIf { it.isShowing }?.dismiss() - log("receiveSerialPortData: $data") - } - log("onCreate: openState=$ok") - } - } - - @SuppressLint("NotifyDataSetChanged") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityHomeBinding.inflate(layoutInflater) - EventBus.getDefault().register(this) - setBackground() - setContentView(binding.root) - onBackPressedDispatcher.addCallback(this) { - - } - updateLeftStatus("") - initRecyclerView() - - // 初始化 ScaleManager:注册回调、打开串口、启动接收 - initScaleManager() - - // 网络状态监听,独立协程,与串口初始化并行执行 - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { - viewModel.getAccessTokenUiState.collect { state -> - when (state) { - is UiState.Loading -> {} - is UiState.Success<*> -> getTokenSuccess(state.data) - is UiState.Error -> toast(state.msg) - else -> {} - } - } - } - launch { - viewModel.getShelfListUiState.collect { state -> - when (state) { - is UiState.Loading -> showProgress() - is UiState.Success<*> -> updateUI(state.data) - is UiState.Error -> showError(state.msg) - else -> {} - } - } - } - launch { - viewModel.updateOverdueStateUiState.collect { state -> - if (state is UiState.Success<*>) { - val respData = state.data as? RespData<*> - if (respData == null) { - log("updateOverdueState: 数据类型错误,期望 RespData") - return@collect - } - val shelfResult = respData.data as? ShelfResult - if (shelfResult == null) { - log("updateOverdueState: 数据类型错误,期望 ShelfResult") - return@collect - } - val items = shelfResult.containerGoodsList - if (items.isNullOrEmpty()) { - log("updateOverdueState: 货架列表为空") - return@collect - } - applyOverdueState(items) - } - } - } - } - } - - binding.root.postDelayed({ - sendCmd(START_TEMP_CTRL_CMD) - sendCmd(C_TEMP_CMD) - }, 5000) - - saveGoodsTask() - overdueTask() - - viewModel.getShelfList(deviceId = App.deviceId) - } - - private val defDeviceList = listOf( - //原410货柜 - "7a991439-3a12-3ef7-809b-c0258b839473", - //原1楼餐厅货柜 - "4787e213-90ab-3e32-88e0-ac271a937751" - ) - - private fun getTokenSuccess(data: RespData<*>) { - log("getTokenSuccess: $data") - data.data?.let { - App.accessToken = it.toString() - viewModel.getShelfList(deviceId = App.deviceId) - } - } - - private fun showProgress() { - Loading.show(this) - } - - @SuppressLint("NotifyDataSetChanged") - private fun updateUI(data: RespData<*>) { - binding.include?.root?.gone() - window?.decorView?.postDelayed({ Loading.dismiss() }, 500) - val shelfResult = data.data as? ShelfResult - if (shelfResult == null) { - log("updateUI: 数据类型错误,期望 ShelfResult,实际类型:${data.data?.javaClass?.simpleName}") - loadEmptyView() - return - } - deviceName = shelfResult.deviceName - updateLeftStatus(deviceName) - - App.canteenId = shelfResult.placeId - var tempList = shelfResult.containerGoodsList - if (tempList.isNullOrEmpty()) { - loadEmptyView() - return - } - list.clear() - tempList = GridLayoutTool.initListSort(tempList) - list.addAll(tempList) - shelfAdapter.notifyDataSetChanged() - } - - private fun showError(message: String) { - Loading.dismiss() - toast(message) - loadEmptyView() - } - - private var tipDialog: CommonDialog? = null - - /** 最后一次成功收到串口数据的时间戳(毫秒) */ - private var lastDataReceivedTime = System.currentTimeMillis() - - /** 无数据超时提示弹窗 */ - private var noDataWarningDialog: CommonDialog? = null - - /** - * 无数据看门狗:每30秒检查一次,若超过5分钟未收到数据则弹出提示。 - * 收到数据后会自动重置计时并关闭弹窗。 - */ - private val noDataWatchdogTask = object : Runnable { - override fun run() { - // 生命周期检查,防止 Activity 销毁后继续执行 - if (isFinishing || isDestroyed) return - - val elapsed = System.currentTimeMillis() - lastDataReceivedTime - if (elapsed >= 5 * 60 * 1000L) { - if (noDataWarningDialog == null) { - noDataWarningDialog = CommonDialog(this@HomeActivity).apply { - dialogTitle = "设备提示" - dialogContent = - "长时间未收到数据,若无法开门或秤重量不更新情况,请考虑断电重启设备" - } - } - if (noDataWarningDialog?.isShowing == false) { - noDataWarningDialog?.show() - } - } - handler.postDelayed(this, 30 * 1000L) - } - } - - /** - * 用户超时无操作时关灯 - */ - override fun onUserInactive() { - switchLight(false) - } - - override fun onDestroy() { - // 清理 Handler 所有回调,防止内存泄漏 - handler.removeCallbacksAndMessages(null) - - // 关闭并释放 Dialog 引用,防止内存泄漏 - tipDialog?.dismiss() - tipDialog = null - noDataWarningDialog?.dismiss() - noDataWarningDialog = null - - runBlocking { ScaleManager.release() } - saveTaskJob?.cancel() - overdueTaskJob?.cancel() - EventBus.getDefault().unregister(this) - super.onDestroy() - } - - private val shelfAdapter by lazy { - ShelfAdapter(list).apply { - setOnItemClickListener { _, _, position -> - onShelfItemClicked(position) - } - } - } - - /** - * 处理货架格子点击事件:按需开锁,然后跳转 ShelfActivity - */ - private fun onShelfItemClicked(position: Int) { - shelfIndex = position - lifecycleScope.launch { - if (isNeedOpenLock()) { - val openCmd = if (list[position].deviceNo in 1..5) - ScaleManager.buildOpenLock1Cmd() - else - ScaleManager.buildOpenLock2Cmd() - ScaleManager.sendCmd(openCmd) - } - launch(Intent(this@HomeActivity, ShelfActivity::class.java).also { - it.putExtra(ShelfActivity.SHELF_MODEL, list[position]) - }) { result -> - result?.let { onShelfActivityResult(position, it) } - } - } - } - - /** - * 处理 ShelfActivity 返回结果:更新本地列表数据并同步到服务端 - */ - private fun onShelfActivityResult(position: Int, intent: Intent) { - @Suppress("DEPRECATION") - val model = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getSerializableExtra(ShelfActivity.SHELF_MODEL, ShelfModel::class.java) - } else { - intent.getSerializableExtra(ShelfActivity.SHELF_MODEL) as? ShelfModel - } ?: return - list[position].apply { - goodsId = model.goodsId - goodsName = model.goodsName - weight = model.weight - if (model.putCabinetDay.isNullOrBlank().not()) { - putCabinetDay = model.putCabinetDay - } - } - shelfAdapter.notifyItemChanged(position) - syncShelfGoodsToServer() - } - - private fun initRecyclerView() { - val layoutManager = GridLayoutTool.getLayoutManager(this@HomeActivity) ?: return - binding.rvShelf.let { - it.layoutManager = layoutManager - it.adapter = shelfAdapter - it.itemAnimator.let { - if (it is DefaultItemAnimator) { - it.supportsChangeAnimations = false - } - } - } - } - - private val handler = Handler(Looper.getMainLooper()) - - override fun onResume() { - super.onResume() - hideStatusBar() - // 启动无数据看门狗(每30秒检查一次) - handler.postDelayed(noDataWatchdogTask, 30 * 1000L) - } - - override fun onPause() { - super.onPause() - // 停止无数据看门狗 - handler.removeCallbacks(noDataWatchdogTask) - } - - @SuppressLint("NotifyDataSetChanged") - private fun loadEmptyView() { - list.clear() - shelfAdapter.notifyDataSetChanged() - binding.include?.let { - it.root.visible() - it.root.setOnClickListener { - viewModel.getShelfList(deviceId = App.deviceId) - } - it.ivEmptyIcon.setImageResource(R.drawable.ic_empty_white) - it.tvEmptyContent.setTextColor(Color.WHITE) - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - fun clearEmptyShelf(event: ClearShelfEvent) { - val item = list.firstOrNull { it.deviceNo == event.shelfNo } - item?.apply { - goodsId = "" - goodsName = null - weight = 0.0 - weightBak = if (event.weight <= 0.0) 0.0 else -1 * event.weight.toDouble() - createTime = null - overdueDay = null - } - shelfAdapter.notifyItemChanged(list.indexOf(item)) - } - - private val taskExecutor by lazy { IntervalExecutor() } - private var saveTaskJob: Job? = null - - /** - * 保存定时任务 - */ - private fun saveGoodsTask() { - saveTaskJob = - taskExecutor.startIntervalTaskWithInitialDelay(1 * 60 * 1000L, 5 * 60 * 1000L) { - syncShelfGoodsToServer() - } - } - - private var overdueTaskJob: Job? = null - - /** - * 过期时间定时任务 - */ - private fun overdueTask() { - overdueTaskJob = taskExecutor.startIntervalTaskWithInitialDelay(5 * 1000L, 5 * 60 * 1000L) { - updateOverdueState() - } - } - - private fun updateOverdueState() { - viewModel.updateOverdueState() - } - - /** - * 将接口返回的过期状态应用到本地列表,仅在状态变化时刷新对应 item - */ - private fun applyOverdueState(items: List) { - if (items.size != list.size) return - list.forEachIndexed { index, model -> - // 接口过期状态变化后更新状态 - if (items[index].overdue != model.overdue) { - model.overdue = items[index].overdue - shelfAdapter.notifyItemChanged(index) - log("更新编号为${model.deviceNo}物品:${model.goodsName}的过期状态:${model.overdue}") - } - } - } - - /** - * 构建 ShelfBody 并提交到服务端(被定时任务与 ShelfActivity 返回共用) - */ - private fun syncShelfGoodsToServer() { - log("performSync显示list:${list.toJsonString()}") - val submitList = GridLayoutTool.submitListSort(list) - submitList.forEach { - if (it.goodsId.isNullOrBlank()) { - it.weight = it.weightBak - } - } - val body = ShelfBody().also { - it.deviceId = App.deviceId ?: "" - it.canteenId = App.canteenId - it.temperature = showTemperatureC - it.humidity = showHumidity - it.goodsList = submitList - } - log("performSync提交body:${body.toJsonString()}") - viewModel.saveShelfGoodsList(body) - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/activity/HomeV2Activity.kt b/app/src/main/java/com/shuwei/intelligent/shelves/activity/HomeV2Activity.kt deleted file mode 100644 index 21be025..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/activity/HomeV2Activity.kt +++ /dev/null @@ -1,455 +0,0 @@ -package com.shuwei.intelligent.shelves.activity - -import android.annotation.SuppressLint -import android.content.Intent -import android.graphics.Color -import android.os.Build -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import androidx.activity.addCallback -import androidx.activity.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.GridLayoutManager -import com.shuwei.intelligent.shelves.App -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.adapter.ShelfV2Adapter -import com.shuwei.intelligent.shelves.base.BaseActivity -import com.shuwei.intelligent.shelves.databinding.ActivityHomeBinding -import com.shuwei.intelligent.shelves.dialog.CommonDialog -import com.shuwei.intelligent.shelves.model.CabinetInitResult -import com.shuwei.intelligent.shelves.model.ClearShelfEvent -import com.shuwei.intelligent.shelves.model.ShelfModelV2 -import com.shuwei.intelligent.shelves.model.SendWeightEvent -import com.shuwei.intelligent.shelves.model.ShelfModel -import com.shuwei.intelligent.shelves.model.SyncBody -import com.shuwei.intelligent.shelves.net.Loading -import com.shuwei.intelligent.shelves.net.NetViewModel -import com.shuwei.intelligent.shelves.net.NetViewModelV2 -import com.shuwei.intelligent.shelves.net.RespData -import com.shuwei.intelligent.shelves.net.UiState -import com.shuwei.intelligent.shelves.serial.ProtocolConstants -import com.shuwei.intelligent.shelves.serial.ProtocolConstants.C_TEMP_CMD -import com.shuwei.intelligent.shelves.serial.ProtocolConstants.START_TEMP_CTRL_CMD -import com.shuwei.intelligent.shelves.serial.ScaleManager -import com.shuwei.intelligent.shelves.utils.GridLayoutTool -import com.shuwei.intelligent.shelves.utils.IntervalExecutor -import com.shuwei.intelligent.shelves.utils.ext.gone -import com.shuwei.intelligent.shelves.utils.ext.toJsonString -import com.shuwei.intelligent.shelves.utils.ext.toast -import com.shuwei.intelligent.shelves.utils.ext.visible -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode - -class HomeV2Activity : BaseActivity() { - - companion object {} - - override val enableRightStatusMenu: Boolean = true - - // 货架列表数据 - private val list: MutableList = mutableListOf() - - // 当前选中货架下标 - private var shelfIndex = 0 - - // 当前温度(摄氏) - private var showTemperatureC = "0" - - // 当前湿度 - private var showHumidity = "0" - - // 仅特定 deviceId 的部署点需要发送开锁指令 - private fun isNeedOpenLock() = App.deviceId == "4787e213-90ab-3e32-88e0-ac271a937751" - - private var deviceName = "" - - private lateinit var binding: ActivityHomeBinding - - private val viewModel: NetViewModel by viewModels() - private val viewModelV2: NetViewModelV2 by viewModels() - - // 串口协议解析器,通过回调通知本 Activity - private fun initScaleManager() { - lifecycleScope.launch { - val ok = ScaleManager - .init(activateCode = ProtocolConstants.ACTIVE_MAP[App.deviceId] ?: "") - .onHeartbeat { _, data -> - data.weights.forEach { weight -> - val shelfNo = weight.index -// if (shelfNo in 1..list.size) { - // 用 slotNo 末尾数字与串口编号匹配 - val pos = list.indexOfFirst { - it.slotNo?.filter { c -> c.isDigit() }?.toIntOrNull() == shelfNo - } - val model = list.getOrNull(pos)?:return@forEach - model.weight = (1.0 * weight.grams / 1000.0).toBigDecimal() -// if (model.itemType == 1) { -// model.actualQty = (weight.grams / 1000.0).toBigDecimal() -// } else { -// model.totalWeightG = weight.grams.toBigDecimal() -// } - shelfAdapter.notifyItemChanged(pos) - log("getWeightInfo: slotNo=${model.slotNo}, realWeight=${weight.grams}, temp=${data.temperature}, item:${model.toJsonString()}") - EventBus.getDefault().post(SendWeightEvent(shelfNo, weight.grams)) -// } - } - } - .onTempReport { frame -> - log("onTempReport: $frame") - updateLeftStatus(deviceName) - } - .onLog { message -> log(message) } - .start { data -> - lastDataReceivedTime = System.currentTimeMillis() - noDataWarningDialog?.takeIf { it.isShowing }?.dismiss() - log("receiveSerialPortData: $data") - } - log("onCreate: openState=$ok") - } - } - - @SuppressLint("NotifyDataSetChanged") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityHomeBinding.inflate(layoutInflater) - EventBus.getDefault().register(this) - setBackground() - setContentView(binding.root) - onBackPressedDispatcher.addCallback(this) { - - } - updateLeftStatus("") - - // 初始化 ScaleManager:注册回调、打开串口、启动接收 - initScaleManager() - - // 网络状态监听,独立协程,与串口初始化并行执行 - lifecycleScope.launch { - viewModelV2.initCabinetUiState.collect { state -> - when (state) { - is UiState.Loading -> showProgress() - is UiState.Success<*> -> updateUI(state.data) - is UiState.Error -> showError(state.msg) - else -> {} - } - } - } - - binding.root.postDelayed({ - sendCmd(START_TEMP_CTRL_CMD) - sendCmd(C_TEMP_CMD) - }, 5000) - - saveGoodsTask() - overdueTask() - - viewModelV2.initCabinet(cabinetId = App.deviceId) - } - - private val defDeviceList = listOf( - //原410货柜 - "7a991439-3a12-3ef7-809b-c0258b839473", - //原1楼餐厅货柜 - "4787e213-90ab-3e32-88e0-ac271a937751" - ) - - private fun getTokenSuccess(data: RespData<*>) { - log("getTokenSuccess: $data") - data.data?.let { - App.accessToken = it.toString() - viewModelV2.initCabinet(cabinetId = App.deviceId) - } - } - - private fun showProgress() { - Loading.show(this) - } - - private var cabinetInitResult: CabinetInitResult? = null - - @SuppressLint("NotifyDataSetChanged") - private fun updateUI(data: RespData<*>) { - binding.include.root.gone() - window?.decorView?.postDelayed({ Loading.dismiss() }, 500) - cabinetInitResult = data.data as? CabinetInitResult - if (cabinetInitResult == null) { - log("updateUI: 数据类型错误,期望 CabinetInitResult,实际类型:${data.data?.javaClass?.simpleName}") - loadEmptyView() - return - } - val cabinet = cabinetInitResult!! - //行列数量后端返回是反着的 - val columns = cabinet.horizontalRows - val rows = cabinet.verticalCount - log("updateUI: rows=$rows, columns=$columns") - deviceName = cabinet.deviceName - updateLeftStatus(deviceName) - App.canteenId = cabinet.canteenId.toString() - var tempList = cabinet.containerGoodsList - if (tempList.isNullOrEmpty()) { - loadEmptyView() - return - } - list.clear() - tempList = GridLayoutTool.initListSortV2(rows = rows, columns = columns, source = tempList) - list.addAll(tempList) - if (binding.rvShelf.adapter == null) { - initRecyclerView(columns) - } else { - shelfAdapter.notifyDataSetChanged() - } - } - - private fun showError(message: String) { - Loading.dismiss() - toast(message) - loadEmptyView() - } - - private var tipDialog: CommonDialog? = null - - /** 最后一次成功收到串口数据的时间戳(毫秒) */ - private var lastDataReceivedTime = System.currentTimeMillis() - - /** 无数据超时提示弹窗 */ - private var noDataWarningDialog: CommonDialog? = null - - /** - * 无数据看门狗:每30秒检查一次,若超过5分钟未收到数据则弹出提示。 - * 收到数据后会自动重置计时并关闭弹窗。 - */ - private val noDataWatchdogTask = object : Runnable { - override fun run() { - // 生命周期检查,防止 Activity 销毁后继续执行 - if (isFinishing || isDestroyed) return - - val elapsed = System.currentTimeMillis() - lastDataReceivedTime - if (elapsed >= 5 * 60 * 1000L) { - if (noDataWarningDialog == null) { - noDataWarningDialog = CommonDialog(this@HomeV2Activity).apply { - dialogTitle = "设备提示" - dialogContent = - "长时间未收到数据,若无法开门或秤重量不更新情况,请考虑断电重启设备" - } - } - if (noDataWarningDialog?.isShowing == false) { - noDataWarningDialog?.show() - } - } - handler.postDelayed(this, 30 * 1000L) - } - } - - /** - * 用户超时无操作时关灯 - */ - override fun onUserInactive() { - switchLight(false) - } - - override fun onDestroy() { - // 清理 Handler 所有回调,防止内存泄漏 - handler.removeCallbacksAndMessages(null) - - // 关闭并释放 Dialog 引用,防止内存泄漏 - tipDialog?.dismiss() - tipDialog = null - noDataWarningDialog?.dismiss() - noDataWarningDialog = null - - runBlocking { ScaleManager.release() } - saveTaskJob?.cancel() - overdueTaskJob?.cancel() - EventBus.getDefault().unregister(this) - super.onDestroy() - } - - private val shelfAdapter by lazy { - ShelfV2Adapter(list).apply { - setOnItemClickListener { _, _, position -> - onShelfItemClicked(position) - } - } - } - - /** - * 处理货架格子点击事件:按需开锁,然后跳转 ShelfV2Activity - */ - private fun onShelfItemClicked(position: Int) { - shelfIndex = position - lifecycleScope.launch { - if (isNeedOpenLock()) { - // 解析 slotNo 末尾数字判断锁区(1-5 号格口走锁1,其余走锁2) - val slotNum = list[position].slotNo?.filter { it.isDigit() }?.toIntOrNull() ?: 0 - val openCmd = if (slotNum in 1..5) - ScaleManager.buildOpenLock1Cmd() - else - ScaleManager.buildOpenLock2Cmd() - ScaleManager.sendCmd(openCmd) - } - launch(Intent(this@HomeV2Activity, ShelfV2Activity::class.java).also { - it.putExtra(ShelfV2Activity.SHELF_MODEL, list[position]) - }) { result -> - result?.let { onShelfActivityResult(position, it) } - } - } - } - - /** - * 处理 ShelfV2Activity 返回结果 - * TODO: 待 ShelfV2Activity 迁移到 RecordItem 后重新实现字段更新逻辑 - */ - private fun onShelfActivityResult(position: Int, intent: Intent) { - @Suppress("DEPRECATION") - val model = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getSerializableExtra(ShelfV2Activity.SHELF_MODEL, ShelfModelV2::class.java) - } else { - intent.getSerializableExtra(ShelfV2Activity.SHELF_MODEL) as? ShelfModelV2 - } ?: return - list[position].let { - it.itemType = model.itemType - it.itemName = model.itemName - it.traceCode = model.traceCode - it.cleanOrderNo = model.cleanOrderNo - it.spec = model.spec - it.foodId = model.foodId - it.storeTime = model.storeTime - it.slotStatus = model.slotStatus - } - shelfAdapter.notifyItemChanged(position) -// syncShelfGoodsToServer() - } - - private fun initRecyclerView(columns: Int) { - val layoutManager = GridLayoutTool.getLayoutManagerV2(this, columns = columns) - binding.rvShelf.let { - it.layoutManager = layoutManager - it.adapter = shelfAdapter - it.itemAnimator.let { animator -> - if (animator is DefaultItemAnimator) { - animator.supportsChangeAnimations = false - } - } - } - } - - private val handler = Handler(Looper.getMainLooper()) - - override fun onResume() { - super.onResume() - hideStatusBar() - // 启动无数据看门狗(每30秒检查一次) - handler.postDelayed(noDataWatchdogTask, 30 * 1000L) - } - - override fun onPause() { - super.onPause() - // 停止无数据看门狗 - handler.removeCallbacks(noDataWatchdogTask) - } - - @SuppressLint("NotifyDataSetChanged") - private fun loadEmptyView() { - list.clear() - shelfAdapter.notifyDataSetChanged() - binding.include?.let { - it.root.visible() - it.root.setOnClickListener { - viewModelV2.initCabinet(cabinetId = App.deviceId) - } - it.ivEmptyIcon.setImageResource(R.drawable.ic_empty_white) - it.tvEmptyContent.setTextColor(Color.WHITE) - } - -// loadTestData() - } - -// @SuppressLint("NotifyDataSetChanged") -// private fun loadTestData() { -// binding.rvShelf.layoutManager = GridLayoutManager(this, 2) -// binding.rvShelf.adapter = shelfAdapter -// binding.include.root.gone() -// list.clear() -// var tempList = (1..10).map { i -> ShelfModelV2(slotNo = i.toString()) } -// tempList = GridLayoutTool.initListSortV2(tempList) -// list.addAll(tempList) -// shelfAdapter.notifyDataSetChanged() -// } - - @Subscribe(threadMode = ThreadMode.MAIN) - fun clearEmptyShelf(event: ClearShelfEvent) { - // 用 slotNo 末尾数字与串口编号匹配 - val index = list.indexOfFirst { - it.slotNo?.filter { c -> c.isDigit() }?.toIntOrNull() == event.shelfNo - } - if (index < 0) return - list[index] = list[index].copy(itemName = "") - shelfAdapter.notifyItemChanged(index) - } - - private val taskExecutor by lazy { IntervalExecutor() } - private var saveTaskJob: Job? = null - - /** - * 保存定时任务 - */ - private fun saveGoodsTask() { - saveTaskJob = -// taskExecutor.startIntervalTaskWithInitialDelay(1 * 60 * 1000L, 5 * 60 * 1000L) { - taskExecutor.startIntervalTaskWithInitialDelay(10 * 1000L, 2 * 60 * 1000L) { - syncShelfGoodsToServer() - } - } - - private var overdueTaskJob: Job? = null - - /** - * 过期时间定时任务 - */ - private fun overdueTask() { - overdueTaskJob = taskExecutor.startIntervalTaskWithInitialDelay(5 * 1000L, 5 * 60 * 1000L) { - viewModelV2.initCabinet(cabinetId = App.deviceId) - } - } - - /** - * 将接口返回的临期状态应用到本地列表,仅在状态变化时刷新对应 item - */ - private fun applyOverdueState(items: List) { - if (items.size != list.size) return - items.forEachIndexed { index, newItem -> - val oldItem = list[index] - // slotStatus=2 表示临期预警 - if (oldItem.slotStatus != newItem.slotStatus) { - list[index] = newItem - shelfAdapter.notifyItemChanged(index) - log("更新格口 ${newItem.slotNo} 物品:${newItem.itemName} 的状态:${newItem.slotStatus}") - } - } - } - - /** - * 构建同步请求并提交到服务端 - */ - private fun syncShelfGoodsToServer() { - if (cabinetInitResult == null) { - return - } - val submitList = GridLayoutTool.submitListSortV2(list) - viewModelV2.syncCabinetData(SyncBody().apply { -// cabinetId = list[0].cabinetId - cabinetId = App.deviceId - temperature = null - humidity = null - goodsList = submitList - }) - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/activity/SettingActivity.kt b/app/src/main/java/com/shuwei/intelligent/shelves/activity/SettingActivity.kt deleted file mode 100644 index c2ad199..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/activity/SettingActivity.kt +++ /dev/null @@ -1,66 +0,0 @@ -//package com.shuwei.intelligent.shelves.activity -// -//import android.os.Bundle -//import android.os.Handler -//import android.os.Looper -//import com.shuwei.intelligent.shelves.base.BaseActivity -//import com.shuwei.intelligent.shelves.databinding.ActivitySettingBinding -//import com.shuwei.intelligent.shelves.utils.KeyboardUtil -//import java.text.SimpleDateFormat -//import java.util.Date -//import java.util.Locale -// -//class SettingActivity: BaseActivity() { -// -// private lateinit var binding: ActivitySettingBinding -// override fun onCreate(savedInstanceState: Bundle?) { -// super.onCreate(savedInstanceState) -// binding = ActivitySettingBinding.inflate(layoutInflater) -// setBackground() -// setContentView(binding.root) -// binding.btnSendCmd.setOnClickListener{ -// val cmd = binding.etInputCmd.text.toString().trim() -// if (cmd.isBlank()) { -// return@setOnClickListener -// } -// var record = binding.tvCmdRecord.text.toString().trim() -// record = cmd+"\n"+record -// binding.tvCmdRecord.text = record -// val realCmd = "${HomeActivity.HEADER}0F01${cmd}${HomeActivity.FOOTER}" -// sendCmd(realCmd) -// } -// binding.ivBack.setOnClickListener { finish() } -// binding.root.setOnClickListener { v -> -// KeyboardUtil.hideKeyboard(v) -// } -// } -// -// -// private fun updateDateTime() { -// val sdf = SimpleDateFormat(ShelfActivity.YYYY_MM_DD__EEEE_HH_MM_SS, Locale.CHINA) -// val dateTime = sdf.format(Date()) -// val arr = dateTime.split("***") -// updateLeftStatus(arr[0]) -// updateRightStatus(arr[1]) -// } -// -// private val handler = Handler(Looper.getMainLooper()) -// private val updateTask = object : Runnable { -// override fun run() { -// updateDateTime() -// handler.postDelayed(this, 1000) -// } -// } -// -// override fun onResume() { -// super.onResume() -// hideStatusBar() -// handler.post(updateTask) -// } -// -// override fun onPause() { -// super.onPause() -// handler.removeCallbacks(updateTask) -// } -// -//} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfActivity.kt b/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfActivity.kt deleted file mode 100644 index 3be5c18..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfActivity.kt +++ /dev/null @@ -1,380 +0,0 @@ -package com.shuwei.intelligent.shelves.activity - -import android.annotation.SuppressLint -import android.content.Intent -import android.os.Bundle -import android.util.Log -import android.widget.LinearLayout -import androidx.activity.viewModels -import androidx.core.view.updateLayoutParams -import androidx.core.widget.addTextChangedListener -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.GridLayoutManager -import com.chad.library.adapter4.util.setOnDebouncedItemClick -import com.scwang.smart.refresh.layout.constant.RefreshState -import com.shuwei.intelligent.shelves.App -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.serial.ScaleManager -import com.shuwei.intelligent.shelves.adapter.SearchAdapter -import com.shuwei.intelligent.shelves.base.BaseActivity -import com.shuwei.intelligent.shelves.databinding.ActivityShelfBinding -import com.shuwei.intelligent.shelves.model.ClearShelfEvent -import com.shuwei.intelligent.shelves.model.GoodsModel -import com.shuwei.intelligent.shelves.model.SendWeightEvent -import com.shuwei.intelligent.shelves.model.ShelfModel -import com.shuwei.intelligent.shelves.net.Loading -import com.shuwei.intelligent.shelves.net.NetViewModel -import com.shuwei.intelligent.shelves.net.RespData -import com.shuwei.intelligent.shelves.net.UiState -import com.shuwei.intelligent.shelves.utils.DateTimeUtil -import com.shuwei.intelligent.shelves.utils.KeyboardUtil -import com.shuwei.intelligent.shelves.utils.ext.addOnActionSearchListener -import com.shuwei.intelligent.shelves.utils.ext.clickWithDebounce -import com.shuwei.intelligent.shelves.utils.ext.dp -import com.shuwei.intelligent.shelves.utils.ext.gone -import com.shuwei.intelligent.shelves.utils.ext.toJsonString -import com.shuwei.intelligent.shelves.utils.ext.toast -import com.shuwei.intelligent.shelves.utils.ext.visible -import kotlinx.coroutines.launch -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -@SuppressLint("NotifyDataSetChanged") -class ShelfActivity : BaseActivity() { - - companion object { - private const val TAG = "ShelfActivity" - - const val YYYY_MM_DD__EEEE_HH_MM_SS = "yyyy年MM月dd日 EEEE***HH:mm:ss" - const val SHELF_MODEL = "shelfModel" - const val RECEIVER_DEVICE_INFO = "receiverDeviceInfo" - const val SHELF_WEIGHT = "shelfWeight" - const val SHELF_INDEX = "shelfIndex" - - const val PAGE_SIZE = 100 - - } - - private lateinit var binding: ActivityShelfBinding - - private var shelfModel: ShelfModel? = null - - private var clickIndex: Int = -1 - - private var realWeight: Int = 0 - private var pageNo: Int = 1 - - private val viewModel: NetViewModel by viewModels() - - - @SuppressLint("UnspecifiedRegisterReceiverFlag") - @Suppress("DEPRECATION") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityShelfBinding.inflate(layoutInflater) - setBackground() - setContentView(binding.root) - EventBus.getDefault().register(this) -// tvFoodWeight =binding.tvFoodWeight - shelfModel = intent.getSerializableExtra(SHELF_MODEL) as ShelfModel? - - shelfModel?.let { - binding.tvShelfName.text = it.shelfName - binding.tvFoodName.text = if (it.goodsName.isNullOrBlank()) "-" else it.goodsName - realWeight = it.weight?.toInt()?:0 - binding.tvFoodWeight.text = if(realWeight < 1000) "${realWeight}克" else "%.3f千克".format(realWeight/1000.0) - startTime = System.currentTimeMillis() - } - - initRecyclerView() - - binding.etInputFood.run { - addOnActionSearchListener { - if (text.isNullOrBlank()) { - toast(hint.toString()) - return@addOnActionSearchListener - } - pageNo = 1 - getGoodsList() - KeyboardUtil.hideKeyboard(context, this) - } - addTextChangedListener(afterTextChanged = { editable -> - if (editable.isNullOrBlank()) { - pageNo = 1 - getGoodsList() - } - }) - } - - binding.btnConfirm.clickWithDebounce { - if (clickIndex < 0) { - toast("请选择食材") - return@clickWithDebounce - } - val currentGoodsId = list[clickIndex].goodsId ?: "" - val data = ShelfModel( - shelfName = shelfModel?.shelfName, - goodsId = currentGoodsId, - goodsName = list[clickIndex].goodsName, - weight = realWeight.toDouble(), - overdueDay = list[clickIndex].overdueDay, -// createTime = if (shelfModel?.goodsId == currentGoodsId) null else DateTimeUtil.formatDateTime(dateTime = Date()) - putCabinetDay = DateTimeUtil.formatDateTime(dateTime = Date()) - ) - val intent = Intent().apply { - putExtra(SHELF_MODEL, data) - } - setResult(RESULT_OK, intent) - finish() - } - binding.root.setOnClickListener { v -> - KeyboardUtil.hideKeyboard(v) - } - binding.btnClearZero.setOnClickListener { - clearZero() - } - binding.btnClearEmpty.setOnClickListener { - val tempWeight = shelfModel?.weight?.toInt()?:0 - clearZero() - binding.tvFoodName.text = "-" - //binding.tvFoodWeight.text = "0克" - EventBus.getDefault().post(ClearShelfEvent(shelfModel!!.deviceNo, tempWeight)) - } - sendCmd(ScaleManager.buildGetStatusCmd()) - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.getGoodsListUiState.collect { state -> - when (state) { - is UiState.Loading -> showProgress() - is UiState.Success<*> -> updateUI(state.data) - is UiState.Error -> showError(state.msg) - else -> {} - } - } - } - } - -// registerReceiver(receiver, IntentFilter(RECEIVER_DEVICE_INFO + shelfModel?.deviceNo)) - binding.ivBack?.setOnClickListener { finish() } - binding.refreshLayout.let { - it.setEnableRefresh(true) - it.setEnableLoadMore(false) - it.setOnRefreshListener { - pageNo = 1 - getGoodsList() - } - it.setOnLoadMoreListener { getGoodsList() } - } - getGoodsList() - -// TaskManager.startDeviceTask() - } - - private fun finishRefresh() { - binding.refreshLayout.let { - if (it.state == RefreshState.Refreshing) { - it.finishRefresh(500) - } else if (binding.refreshLayout.state == RefreshState.Loading) { - it.finishLoadMore(500) - } else { - - } - } - - } - - private fun getGoodsList() { - viewModel.getGoodsList( - canteenId = App.canteenId, - goodsName = binding.etInputFood.text.trim().toString(), - pageNo = pageNo, - pageSize = PAGE_SIZE - ) - } - - private fun showProgress() { - Loading.show(this) - } - - @SuppressLint("NotifyDataSetChanged") - private fun updateUI(data: RespData<*>) { - binding.include?.root?.gone() - finishRefresh() - binding.root.postDelayed({ Loading.dismiss() }, 200) - Log.d(TAG, "updateUI: ${data.toJsonString()}") - - val goodsList = data.data as MutableList - if (data.data.isNullOrEmpty()) { - if (pageNo == 1) { - loadEmptyView() - } - return - } - if(pageNo == 1){ - list.clear() - } -// var firstOne:GoodsModel?=null -// if (pageNo == 1) { -// if (shelfModel?.goodsId.isNullOrBlank().not()) { -// firstOne = list.firstOrNull { it.goodsId == shelfModel?.goodsId } -// if (firstOne == null) { -// firstOne = GoodsModel( -// goodsId = shelfModel?.goodsId, -// goodsName = shelfModel?.goodsName, -// isClicked = true -// ) -// } -// } -// list.clear() -// } -// val records = data.data.records -// if (pageNo == 1) { -// firstOne?.let { one -> -// val filterResult = records.firstOrNull{one.goodsId == it.goodsId } -// if (filterResult != null) { -// records.remove(filterResult) -// } -// clickIndex = 0 -// list.add(one) -// } -// } - list.addAll(goodsList) - val enableLoadMore = goodsList.size >= PAGE_SIZE - binding.refreshLayout.setEnableLoadMore(enableLoadMore) - if (enableLoadMore) { - pageNo++ - } - searchAdapter.notifyDataSetChanged() - } - - private fun showError(message: String) { - finishRefresh() - Loading.dismiss() - toast(message) - if (pageNo == 1) { - loadEmptyView() - } - } - -// private val receiver = object : BroadcastReceiver() { -// override fun onReceive(context: Context?, intent: Intent?) { -// intent?.let { -// if (it.action == RECEIVER_DEVICE_INFO + shelfModel?.deviceNo) { -// val weight = it.getDoubleExtra(SHELF_WEIGHT, 0.0) -// Log.d(TAG, "getDeviceInfo:onReceive: weight=$weight") -// realWeight = (weight * 1000).toInt() -// binding.tvFoodWeight.text = "${realWeight}克" -// } -// } -// } -// } - - override fun onDestroy() { -// unregisterReceiver(receiver) - EventBus.getDefault().unregister(this) -// TaskManager.cancelDeviceTask() - super.onDestroy() - } - - private val list: MutableList = mutableListOf() - private val searchAdapter by lazy { - SearchAdapter(list).apply { - setOnDebouncedItemClick { adapter, v, position -> - this@ShelfActivity.clickIndex = position - list.forEach { it.isClicked = false } - list[position].isClicked = true - notifyDataSetChanged() - binding.tvFoodName.text = list[position].goodsName - KeyboardUtil.hideKeyboard(v.context, v) - } - } - } - - private fun initRecyclerView() { - binding.rvSearch.run { - layoutManager = GridLayoutManager(this@ShelfActivity, 2) - adapter = searchAdapter - } - } - - /** - * 覆写时钟回调:左侧状态栏显示年月日星期,右侧状态栏显示时分秒 - */ - override fun onClockTick() { - val sdf = SimpleDateFormat(YYYY_MM_DD__EEEE_HH_MM_SS, Locale.CHINA) - val arr = sdf.format(Date()).split("***") - updateLeftStatus(arr[0]) - updateRightStatus(arr[1]) - } - - override fun onResume() { - super.onResume() - hideStatusBar() - } - - override fun onPause() { - super.onPause() - } - - @SuppressLint("NotifyDataSetChanged") - private fun loadEmptyView() { - list.clear() - searchAdapter.notifyDataSetChanged() - binding.include?.let { - it.root.visible() - it.root.setOnClickListener { - pageNo = 1 - getGoodsList() - } - it.ivEmptyIcon.setImageResource(R.drawable.ic_empty_gray) - it.ivEmptyIcon.updateLayoutParams { - val swDpValue = resources?.configuration?.smallestScreenWidthDp ?: 0 - width = if (swDpValue > 600) 200.dp else 120.dp - } - } - binding.refreshLayout.run { - setEnableRefresh(false) - setEnableLoadMore(false) - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public fun receiveWeightEvent(event: SendWeightEvent) { - if (event.shelfNo == (shelfModel?.deviceNo ?: 0)) { - val intervalTime = System.currentTimeMillis() - startTime - val weight = event.weight - log("编号${event.shelfNo}货架获取重量成功:${weight}克,数据获取间隔时间为:${intervalTime}") - binding.tvFoodWeight.text = if(weight < 1000) "${weight}克" else "%.3f千克".format(weight/1000.0) - startTime = System.currentTimeMillis() - window.decorView.postDelayed({ Loading.dismiss() }, 1000) - } - } - - private fun clearZero() { - lifecycleScope.launch { - val shelfNo = shelfModel?.deviceNo ?: 0 - val zeroClearingCmd = ScaleManager.buildScaleZeroCmd(shelfNo) - log("编号${shelfNo}货架执行清零指令:${zeroClearingCmd}") - sendCmd(zeroClearingCmd) -// sendCmd( -// if (shelfNo in 1..5) ProtocolConstants.LEFT_SHELF_OPEN_CMD else ProtocolConstants.RIGHT_SHELF_OPEN_CMD -// ) - //清零 - realWeight = 0 -// binding.tvFoodWeight.text = "${realWeight}克" - - sendCmd(ScaleManager.buildGetStatusCmd()) - startTime = System.currentTimeMillis() - Loading.show(this@ShelfActivity) - window.decorView.postDelayed({ Loading.dismiss() }, 10000) - } - KeyboardUtil.hideKeyboard(window.decorView) - } - private var startTime = 0L -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfV2Activity.kt b/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfV2Activity.kt deleted file mode 100644 index 2929895..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/activity/ShelfV2Activity.kt +++ /dev/null @@ -1,384 +0,0 @@ -package com.shuwei.intelligent.shelves.activity - -import android.annotation.SuppressLint -import android.content.Intent -import android.os.Bundle -import android.widget.LinearLayout -import androidx.activity.viewModels -import androidx.core.view.updateLayoutParams -import androidx.core.widget.addTextChangedListener -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.GridLayoutManager -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.util.setOnDebouncedItemClick -import com.scwang.smart.refresh.layout.constant.RefreshState -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.adapter.CleanPackageAdapter -import com.shuwei.intelligent.shelves.adapter.MealPackageAdapter -import com.shuwei.intelligent.shelves.base.BaseActivity -import com.shuwei.intelligent.shelves.databinding.ActivityShelfV2Binding -import com.shuwei.intelligent.shelves.model.CleanPackageOption -import com.shuwei.intelligent.shelves.model.MealPackageOption -import com.shuwei.intelligent.shelves.model.ShelfModelV2 -import com.shuwei.intelligent.shelves.model.SendWeightEvent -import com.shuwei.intelligent.shelves.net.Loading -import com.shuwei.intelligent.shelves.net.NetViewModelV2 -import com.shuwei.intelligent.shelves.net.RespData -import com.shuwei.intelligent.shelves.net.UiState -import com.shuwei.intelligent.shelves.serial.ScaleManager -import com.shuwei.intelligent.shelves.utils.KeyboardUtil -import com.shuwei.intelligent.shelves.utils.ext.addOnActionSearchListener -import com.shuwei.intelligent.shelves.utils.ext.clickWithDebounce -import com.shuwei.intelligent.shelves.utils.ext.dp -import com.shuwei.intelligent.shelves.utils.ext.gone -import com.shuwei.intelligent.shelves.utils.ext.toast -import com.shuwei.intelligent.shelves.utils.ext.visible -import kotlinx.coroutines.launch -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -@SuppressLint("NotifyDataSetChanged") -class ShelfV2Activity : BaseActivity() { - - companion object { - const val SHELF_MODEL = "shelfModel" - const val YYYY_MM_DD__EEEE_HH_MM_SS = "yyyy年MM月dd日 EEEE***HH:mm:ss" - - /** itemType=1:净菜包 */ - private const val TYPE_CLEAN = 1 - - /** itemType=2:餐品净菜包 */ - private const val TYPE_MEAL = 2 - } - - private lateinit var binding: ActivityShelfV2Binding - - private var recordItem: ShelfModelV2? = null - private var realWeight: Int = 0 - private var startTime = 0L - - private val viewModel: NetViewModelV2 by viewModels() - - // 当前选中类型,默认净菜包 - private var currentType = TYPE_CLEAN - - // 净菜包列表与 Adapter - private val cleanList: MutableList = mutableListOf() - private val cleanAdapter by lazy { - CleanPackageAdapter(cleanList).apply { - setOnDebouncedItemClick { _, _, position -> - cleanList.forEachIndexed { index, option -> option.isSelected = index == position } - notifyDataSetChanged() - binding.tvFoodName.text = cleanList[position].itemName - KeyboardUtil.hideKeyboard(this@ShelfV2Activity.window.decorView) - } - } - } - - // 餐品净菜包列表与 Adapter - private val mealList: MutableList = mutableListOf() - private val mealAdapter by lazy { - MealPackageAdapter(mealList).apply { - setOnDebouncedItemClick { _, _, position -> - mealList.forEachIndexed { index, option -> option.isSelected = index == position } - notifyDataSetChanged() - binding.tvFoodName.text = mealList[position].itemName - KeyboardUtil.hideKeyboard(this@ShelfV2Activity.window.decorView) - } - } - } - - @Suppress("DEPRECATION") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityShelfV2Binding.inflate(layoutInflater) - setBackground() - setContentView(binding.root) - EventBus.getDefault().register(this) - - recordItem = intent.getSerializableExtra(SHELF_MODEL) as? ShelfModelV2 - recordItem?.let { - binding.tvShelfName.text = it.slotNo - binding.tvFoodName.text = if (it.itemName.isNullOrBlank()) "-" else it.itemName - val weightG = it.weight?.toDouble() ?: 0.0 - realWeight = (weightG * 1000.0).toInt() - binding.tvFoodWeight.text = if (weightG >= 1.0) "%.3f千克".format(weightG) - else "${realWeight}克" - startTime = System.currentTimeMillis() - } - - initChipGroup() - initRecyclerView() - initSearchBox() - initButtons() - observeViewModel() - - sendCmd(ScaleManager.buildGetStatusCmd()) - loadList() - } - - private fun initChipGroup() { - binding.chipGroupType.setOnCheckedStateChangeListener { _, checkedIds -> - currentType = when { - checkedIds.contains(R.id.chipClean) -> TYPE_CLEAN - checkedIds.contains(R.id.chipMeal) -> TYPE_MEAL - else -> currentType - } - // 切换时清空搜索框并重新加载列表 - binding.etInputFood.setText("") - switchAdapter() - loadList() - } - } - - private fun switchAdapter() { - val adapter: BaseQuickAdapter<*, *> = - if (currentType == TYPE_CLEAN) cleanAdapter else mealAdapter - binding.rvSearch.adapter = adapter - } - - private fun initRecyclerView() { - binding.rvSearch.run { - layoutManager = GridLayoutManager(this@ShelfV2Activity, 2) - adapter = cleanAdapter - } - binding.refreshLayout.run { - setEnableRefresh(true) - setEnableLoadMore(false) - setOnRefreshListener { loadList() } - } - } - - private fun initSearchBox() { - binding.etInputFood.run { - addOnActionSearchListener { - loadList() - KeyboardUtil.hideKeyboard(context, this) - } - addTextChangedListener(afterTextChanged = { editable -> - if (editable.isNullOrBlank()) loadList() - }) - } - binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) } - } - - private fun initButtons() { - binding.ivBack.setOnClickListener { finish() } - binding.btnClearZero.setOnClickListener { - Loading.show(this@ShelfV2Activity) - clearZero() - window.decorView.postDelayed({ Loading.dismiss() }, 10000) - } - binding.btnClearEmpty.setOnClickListener { v -> - clearZero() - binding.tvFoodName.text = "-" - - Loading.show(this@ShelfV2Activity) - v.postDelayed({ - Loading.dismiss() - // 3 秒后自动关闭 Activity 并回传空值 - val emptyRecord = recordItem?.also { - it.itemName = "" - //4-空置 - it.slotStatus = 4 -// it.totalWeightG = null -// it.actualQty = null - it.weight = null - it.itemType = 0 - it.traceCode = null - it.storeTime = null - it.spec = null - it.specLabel = null - it.cleanOrderNo = null - } - val result = Intent().apply { - putExtra(SHELF_MODEL, emptyRecord) - } - setResult(RESULT_OK, result) - finish() - }, 3000) - } - binding.btnConfirm.clickWithDebounce { - var shelfModelV2: ShelfModelV2? = null - if (currentType == TYPE_CLEAN) { - val item = cleanList.firstOrNull { it.isSelected } - if (item == null) { - toast("请选择净菜包"); return@clickWithDebounce - } - shelfModelV2 = item.toShelfModelV2(recordItem).also { - //1-存放中 - it.slotStatus = 1 - } - } else { - val item = mealList.firstOrNull { it.isSelected } - if (item == null) { - toast("请选择餐品净菜包"); return@clickWithDebounce - } - shelfModelV2 = item.toShelfModelV2(recordItem).also { - //1-存放中 - it.slotStatus = 1 - } - } - // 将选中结果回传给上层 Activity - val result = Intent().apply { - putExtra(SHELF_MODEL, shelfModelV2) - } - setResult(RESULT_OK, result) - finish() - } - } - - private fun observeViewModel() { - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { - viewModel.cleanPackageOptionsUiState.collect { state -> - when (state) { - is UiState.Loading -> showProgress() - is UiState.Success<*> -> updateCleanList(state.data) - is UiState.Error -> showError(state.msg) - else -> {} - } - } - } - launch { - viewModel.mealPackageOptionsUiState.collect { state -> - when (state) { - is UiState.Loading -> showProgress() - is UiState.Success<*> -> updateMealList(state.data) - is UiState.Error -> showError(state.msg) - else -> {} - } - } - } - } - } - } - - private fun loadList() { - val keyword = binding.etInputFood.text.trim().toString().ifBlank { null } - if (currentType == TYPE_CLEAN) { - viewModel.getCleanPackageOptions(keyword = keyword) - } else { - viewModel.getMealPackageOptions(keyword = keyword) - } - } - - private fun showProgress() { - Loading.show(this) - } - - @SuppressLint("NotifyDataSetChanged") - private fun updateCleanList(data: RespData<*>) { - finishRefresh() - binding.include?.root?.gone() - binding.root.postDelayed({ Loading.dismiss() }, 200) - @Suppress("UNCHECKED_CAST") - val items = data.data as? List - if (items.isNullOrEmpty()) { - loadEmptyView(); return - } - cleanList.clear() - cleanList.addAll(items) - cleanAdapter.notifyDataSetChanged() - } - - @SuppressLint("NotifyDataSetChanged") - private fun updateMealList(data: RespData<*>) { - finishRefresh() - binding.include?.root?.gone() - binding.root.postDelayed({ Loading.dismiss() }, 200) - @Suppress("UNCHECKED_CAST") - val items = data.data as? List - if (items.isNullOrEmpty()) { - loadEmptyView(); return - } - mealList.clear() - mealList.addAll(items) - mealAdapter.notifyDataSetChanged() - } - - private fun showError(message: String) { - finishRefresh() - Loading.dismiss() - toast(message) - loadEmptyView() - } - - @SuppressLint("NotifyDataSetChanged") - private fun loadEmptyView() { - cleanList.clear() - mealList.clear() - cleanAdapter.notifyDataSetChanged() - mealAdapter.notifyDataSetChanged() - binding.include?.let { - it.root.visible() - it.root.setOnClickListener { loadList() } - it.ivEmptyIcon.setImageResource(R.drawable.ic_empty_gray) - it.ivEmptyIcon.updateLayoutParams { - val swDpValue = resources?.configuration?.smallestScreenWidthDp ?: 0 - width = if (swDpValue > 600) 200.dp else 120.dp - } - } - binding.refreshLayout.run { - setEnableRefresh(false) - setEnableLoadMore(false) - } - } - - private fun finishRefresh() { - binding.refreshLayout.let { - if (it.state == RefreshState.Refreshing) it.finishRefresh(500) - else if (it.state == RefreshState.Loading) it.finishLoadMore(500) - } - } - - private fun clearZero() { - lifecycleScope.launch { - val slotNum = recordItem?.slotNo?.filter { it.isDigit() }?.toIntOrNull() ?: 0 - val zeroClearingCmd = ScaleManager.buildScaleZeroCmd(slotNum) - log("格口${recordItem?.slotNo}执行清零指令:$zeroClearingCmd") - sendCmd(zeroClearingCmd) - realWeight = 0 - sendCmd(ScaleManager.buildGetStatusCmd()) - startTime = System.currentTimeMillis() - } - KeyboardUtil.hideKeyboard(window.decorView) - } - - override fun onClockTick() { - val sdf = SimpleDateFormat(YYYY_MM_DD__EEEE_HH_MM_SS, Locale.CHINA) - val arr = sdf.format(Date()).split("***") - updateLeftStatus(arr[0]) - updateRightStatus(arr[1]) - } - - override fun onResume() { - super.onResume() - hideStatusBar() - } - - override fun onDestroy() { - EventBus.getDefault().unregister(this) - super.onDestroy() - } - - @Subscribe(threadMode = ThreadMode.MAIN) - fun receiveWeightEvent(event: SendWeightEvent) { - val slotNum = recordItem?.slotNo?.filter { it.isDigit() }?.toIntOrNull() ?: return - if (event.shelfNo != slotNum) return - val intervalTime = System.currentTimeMillis() - startTime - val weight = event.weight - log("格口${recordItem?.slotNo}获取重量:${weight}克,间隔:${intervalTime}ms") - binding.tvFoodWeight.text = if (weight < 1000) "${weight}克" - else "%.3f千克".format(weight / 1000.0) - startTime = System.currentTimeMillis() - window.decorView.postDelayed({ Loading.dismiss() }, 1000) - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/CleanPackageAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/CleanPackageAdapter.kt deleted file mode 100644 index 638a07a..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/CleanPackageAdapter.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.shuwei.intelligent.shelves.adapter - -import android.content.Context -import android.content.res.ColorStateList -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat -import androidx.core.graphics.toColorInt -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.databinding.ListItemSearchBinding -import com.shuwei.intelligent.shelves.model.CleanPackageOption - -class CleanPackageAdapter(list: MutableList) : - BaseQuickAdapter(list) { - - inner class VH(val binding: ListItemSearchBinding) : QuickViewHolder(binding.root) - - override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { - val binding = ListItemSearchBinding.inflate(LayoutInflater.from(context), parent, false) - return VH(binding) - } - - override fun onBindViewHolder(holder: VH, position: Int, item: CleanPackageOption?) { - item ?: return - val isSelected = item.isSelected - holder.binding.btnFoodName.run { - text = " ${item.itemName}" - setTextColor(getColor(if (isSelected) R.color.shelf_name_blue else R.color.black999)) - strokeColor = ColorStateList.valueOf( - (if (isSelected) "#4969F5" else "#E6E6E6").toColorInt() - ) - } - } - - private fun getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/MealPackageAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/MealPackageAdapter.kt deleted file mode 100644 index 29cafe5..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/MealPackageAdapter.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.shuwei.intelligent.shelves.adapter - -import android.content.Context -import android.content.res.ColorStateList -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat -import androidx.core.graphics.toColorInt -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.databinding.ListItemSearchBinding -import com.shuwei.intelligent.shelves.model.MealPackageOption - -class MealPackageAdapter(list: MutableList) : - BaseQuickAdapter(list) { - - inner class VH(val binding: ListItemSearchBinding) : QuickViewHolder(binding.root) - - var selectedId: Long = -1L - - override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { - val binding = ListItemSearchBinding.inflate(LayoutInflater.from(context), parent, false) - return VH(binding) - } - - override fun onBindViewHolder(holder: VH, position: Int, item: MealPackageOption?) { - item ?: return - val isSelected = item.isSelected - holder.binding.btnFoodName.run { - text = " ${item.itemName}" - setTextColor(getColor(if (isSelected) R.color.shelf_name_blue else R.color.black999)) - strokeColor = ColorStateList.valueOf( - (if (isSelected) "#4969F5" else "#E6E6E6").toColorInt() - ) - } - } - - private fun getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt deleted file mode 100644 index 141673f..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.shuwei.intelligent.shelves.adapter - -import android.content.Context -import android.content.res.ColorStateList -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat -import androidx.core.graphics.toColorInt -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.databinding.ListItemSearchBinding -import com.shuwei.intelligent.shelves.model.GoodsModel - -class SearchAdapter(list: MutableList) : - BaseQuickAdapter(list) { - - inner class VH(var binding: ListItemSearchBinding) : QuickViewHolder(binding.root) - - override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { - val inflater = LayoutInflater.from(context) - val binding = ListItemSearchBinding.inflate(inflater, parent, false) - return VH(binding) - } - - override fun onBindViewHolder(holder: VH, position: Int, item: GoodsModel?) { - val binding = holder.binding - binding.btnFoodName.run { - text = " ${item!!.goodsName}" - setTextColor( - getColor(if (item.isClicked) R.color.shelf_name_blue else R.color.black999) - ) - val btnStrokeColor = if (item.isClicked) "#4969F5" else "#E6E6E6" - strokeColor = ColorStateList.valueOf(btnStrokeColor.toColorInt()) - } -// val bgDrawable = createCustomDrawable( -// solidColor = "#FFFFFF", -// strokeWidth = 2.dp, -// strokeColor = if (item!!.isClicked) "#4969F5" else "#E6E6E6", -// radius = 12.dp -// ) -// binding.root.background = bgDrawable - - } - - private fun getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) - - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt deleted file mode 100644 index 1d06d13..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt +++ /dev/null @@ -1,117 +0,0 @@ -package com.shuwei.intelligent.shelves.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.databinding.ListItemShelfBinding -import com.shuwei.intelligent.shelves.model.ShelfModel -import com.shuwei.intelligent.shelves.utils.DateTimeUtil -import com.shuwei.intelligent.shelves.utils.ext.gone -import com.shuwei.intelligent.shelves.utils.ext.visible -import java.util.Date -import kotlin.math.abs - -class ShelfAdapter(list: MutableList) : - BaseQuickAdapter(list) { - - inner class VH(var binding: ListItemShelfBinding) : QuickViewHolder(binding.root) - - override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { - val inflater = LayoutInflater.from(context) - val binding = ListItemShelfBinding.inflate(inflater, parent, false) - return VH(binding) - } - - private fun stringToDate(createTime: String?): Date? { - if (createTime.isNullOrBlank()) { - return null - } - return DateTimeUtil.stringToDate(createTime) - } - - override fun onBindViewHolder(holder: VH, position: Int, item: ShelfModel?) { - val shelfNo = item!!.deviceNo - //货架- - item.shelfName = "${if (shelfNo < 10) "0${shelfNo}" else "$shelfNo"}" - val weight = item.weight ?: 0.0 - val binding = holder.binding - if (item.overdueDay.isNullOrBlank()) { - binding.ivStaleFood.gone() - } else { - runCatching { -// val shelfDate = stringToDate(item.putCabinetDay) - binding.ivStaleFood.run { - if (item.overdue == true) visible() else gone() - } -// if (shelfDate == null) { -// binding.ivStaleFood.gone() -// } else { -// val days = item.overdueDay!!.toInt() -// val resultDate = DateTimeUtil.addDays(shelfDate, days) -// if (resultDate.before(Date())) { -// binding.ivStaleFood.visible() -// } else { -// binding.ivStaleFood.gone() -// } -// } - }.onFailure { - binding.ivStaleFood.gone() - } - } - //?.setImageResource() - binding.tvFoodWeight.run { - setTextColor(getColor(R.color.food_weight_orange)) - //val showWeight = if (weight == 0.toDouble()) "0克" else "%.3f千克".format(weight) - text = if(abs(weight) < 1000) "${weight.toInt()}克" else "%.3f千克".format(weight/1000.0) - //"${(weight*1000).roundToInt()}克" - } - //val isBlankShelf = weight <= 0 - val isBlankShelf = item.goodsName.isNullOrBlank() - if (isBlankShelf) { - binding.layoutCard.setCardBackgroundColor(getColor(R.color.bg_card_blue)) - binding.tvShelfName.run { - setTextColor(getColor(R.color.shelf_name_white)) - text = item.shelfName - } - binding.tvFoodName.run { - setTextColor(getColor(R.color.white)) - text = "空" - } -// binding.tvFoodWeight.run { -// setTextColor(getColor(R.color.food_weight_blue)) -// text = "0千克" -// } - binding.tvStoreDate.run { - setTextColor(getColor(R.color.food_weight_blue)) - text = "-" - } - return - } - binding.layoutCard.setCardBackgroundColor(getColor(R.color.bg_card_white)) - binding.tvShelfName.run { - setTextColor(getColor(R.color.shelf_name_blue)) - text = item.shelfName - } - binding.tvFoodName.run { - setTextColor(getColor(R.color.food_name_black)) - text = item.goodsName - } -// binding.tvFoodWeight.run { -// setTextColor(getColor(R.color.food_weight_orange)) -//// text = "${weight/1000F}千克" -// text = "${weight}克" -// } - binding.tvStoreDate.run { - setTextColor(getColor(R.color.black999)) - text = item.putCabinetDay - } - } - - private fun getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfV2Adapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfV2Adapter.kt deleted file mode 100644 index 27b1c9a..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfV2Adapter.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.shuwei.intelligent.shelves.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat -import com.chad.library.adapter4.BaseQuickAdapter -import com.chad.library.adapter4.viewholder.QuickViewHolder -import com.shuwei.intelligent.shelves.R -import com.shuwei.intelligent.shelves.databinding.ListItemShelfBinding -import com.shuwei.intelligent.shelves.model.ShelfModelV2 -import com.shuwei.intelligent.shelves.utils.ext.gone -import com.shuwei.intelligent.shelves.utils.ext.visible -import kotlin.math.abs - -class ShelfV2Adapter(list: MutableList) : - BaseQuickAdapter(list) { - - inner class VH(val binding: ListItemShelfBinding) : QuickViewHolder(binding.root) - - override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { - val binding = ListItemShelfBinding.inflate(LayoutInflater.from(context), parent, false) - return VH(binding) - } - - override fun onBindViewHolder(holder: VH, position: Int, item: ShelfModelV2?) { - item ?: return - val binding = holder.binding - - // 格口编号 - binding.tvShelfName.text = item.slotNo?.padStart(2, '0') - - // 临期预警(slotStatus=2)显示过期图标 - if (item.slotStatus.toInt() == 2) binding.ivStaleFood.visible() - else binding.ivStaleFood.gone() - -// // 重量:itemType=2 用 totalWeightG(g),itemType=1 用 actualQty×1000(g) -// val weightG = if (item.itemType == 1) (item.actualQty?.toDouble() ?: 0.0) * 1000.0 -// else item.totalWeightG?.toDouble() ?: 0.0 - - val weightG = item.weight?.toDouble() ?: 0.0 - binding.tvFoodWeight.run { - setTextColor(getColor(R.color.food_weight_orange)) - text = if (abs(weightG) >= 1.0) "%.3f千克".format(weightG) - else "${(weightG * 1000.0).toInt()}克" - } - - val isBlank = item.itemName.isNullOrBlank() - if (isBlank) { - binding.layoutCard.setCardBackgroundColor(getColor(R.color.bg_card_blue)) - binding.tvShelfName.setTextColor(getColor(R.color.shelf_name_white)) - binding.tvFoodName.run { - setTextColor(getColor(R.color.white)) - text = "空" - } - binding.tvStoreDate.run { - setTextColor(getColor(R.color.food_weight_blue)) - text = "-" - } - return - } - - binding.layoutCard.setCardBackgroundColor(getColor(R.color.bg_card_white)) - binding.tvShelfName.setTextColor(getColor(R.color.shelf_name_blue)) - binding.tvFoodName.run { - setTextColor(getColor(R.color.food_name_black)) - text = item.itemName - } - binding.tvStoreDate.run { - setTextColor(getColor(R.color.black999)) - text = item.storeTime - } - } - - private fun getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/CabinetInitResult.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/CabinetInitResult.kt deleted file mode 100644 index 583713c..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/CabinetInitResult.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -/** - * 货柜初始化接口(4.1)响应体 - */ -data class CabinetInitResult( - val canteenId: Long = 0, - val canteenName: String = "", - val deviceName: String = "", - val area: String = "", - val horizontalRows:Int = 0, - val verticalCount:Int = 0, - val containerGoodsList: List? = null, -) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/CleanPackageOption.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/CleanPackageOption.kt deleted file mode 100644 index dd4b880..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/CleanPackageOption.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import com.shuwei.intelligent.shelves.utils.DateTimeUtil -import java.math.BigDecimal -import java.util.Date - -/** - * 净菜包下拉选项,对应接口 4.2.1(itemType=1) - */ -data class CleanPackageOption( - val id: Long = 0, - val itemName: String = "", - /** 净菜订单号,sync 时作为 cleanOrderNo 回传 */ - val orderNo: String = "", - val packageSpec: String? = null, - /** 关联菜品 id */ - val foodId: Long? = null, - /** 需求份数 */ - val needCount: Int? = null, - /** 需求计量(kg) */ - val needQtyKg: BigDecimal? = null, - /** 保质期至,格式 yyyy-MM-dd */ - val expiryDate: String? = null, - var isSelected: Boolean = false -) { - /** 将净菜包选项转换为格口记录 */ - fun toShelfModelV2(model: ShelfModelV2? = null) = (model ?: ShelfModelV2()).also { - it.itemType = 1 - it.itemName = itemName - it.cleanOrderNo = orderNo - it.spec = packageSpec - it.foodId = foodId - it.storeTime = DateTimeUtil.formatDateTime(dateTime = Date()) - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/DeviceConfigInfo.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/DeviceConfigInfo.kt deleted file mode 100644 index 5f496bb..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/DeviceConfigInfo.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -class DeviceConfigInfo { - var appPackageUrl:String? = null - var canteenId:String? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt deleted file mode 100644 index f6d9f3d..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import java.io.Serializable - -data class GoodsModel( - var goodsId: String? = null, - var goodsName: String? = null, - var overdueDay: String? = null, - var isClicked: Boolean = false -) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt deleted file mode 100644 index 0c4ad0a..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -data class GoodsRecord( - val total: Int = 0, - val size: Int = 0, - val page: Int = 0, - val records: MutableList? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/MealPackageOption.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/MealPackageOption.kt deleted file mode 100644 index 4bcef32..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/MealPackageOption.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import com.shuwei.intelligent.shelves.utils.DateTimeUtil -import java.math.BigDecimal -import java.util.Date - -/** - * 餐品净菜包下拉选项,对应接口 4.2.2(itemType=2) - */ -data class MealPackageOption( - val id: Long = 0, - val itemName: String = "", - /** 净菜订单号,sync 时作为 cleanOrderNo 回传 */ - val orderNo: String = "", - val packageSpec: String? = null, - /** 关联菜品 id */ - val foodId: Long? = null, - /** 需求份数 */ - val needCount: Int? = null, - /** 需求计量(kg) */ - val needQtyKg: BigDecimal? = null, - /** 保质期至,格式 yyyy-MM-dd(包装完成后有值) */ - val expiryDate: String? = null, - var isSelected: Boolean = false -) { - /** 将餐品净菜包选项转换为格口记录 */ - fun toShelfModelV2(model: ShelfModelV2? = null) = (model ?: ShelfModelV2()).also { - it.itemType = 2 - it.itemName = itemName - it.cleanOrderNo = orderNo - it.spec = packageSpec - it.foodId = foodId - it.storeTime = DateTimeUtil.formatDateTime(dateTime = Date()) - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt deleted file mode 100644 index f35042b..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -class ShelfBody { - - var deviceId: String = "" - var canteenId: String = "" - var temperature: String? = null - var humidity: String = "0" - var goodsList: List? = null - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt deleted file mode 100644 index 71c2f13..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import java.io.Serializable - -data class ShelfModel( - var id: String? = null, - var deviceNo: Int = 0, - var shelfName: String? = null, - var goodsId: String? = "", - var goodsName: String? = null, - var deviceId: String? = null, - var weight: Double = 0.0, - var weightBak: Double = 0.0, - var createTime: String? = null, - var putCabinetDay: String? = null, - var updateTime: String? = null, - var overdueDay: String? = null, - var temperature: String? = null, - var humidity: String = "0", - var overdue:Boolean ?= false -) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModelV2.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModelV2.kt deleted file mode 100644 index 7d9adfa..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModelV2.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import java.io.Serializable -import java.math.BigDecimal - -/** - * 格口存放记录,对应接口 4.1 货柜初始化返回的 containerGoodsList 元素 - */ -data class ShelfModelV2( - var id: Long = 0, - /** 类型:1-食材净菜 / 2-餐品净菜包 */ - var itemType: Int = 0, - /** 格口编号 */ - var slotNo: String? = "", - /** 格口所在柜子编号 */ - var cabinetId: String? = "", - /** 智能柜名称 */ - var cabinetName: String? = "", - var area: String = "", - /** 溯源码 */ - var traceCode: String? = "", - /** 关联净菜订单号 */ - var cleanOrderNo: String? = "", - /** 物料名称 */ - var itemName: String? = "", - /** 订单量 kg(itemType=1) */ - var orderQty: BigDecimal? = null, - /** 实收量 kg(itemType=1) */ -// var actualQty: BigDecimal? = null, - /** 差异量 kg(itemType=1,可为负) */ - var diffQty: BigDecimal? = null, - /** 规格(itemType=2,如:标准份) */ - var spec: String? = null, - var specLabel: String? = null, - /** 包数(itemType=2) */ - var pkgCount: Int? = null, - /** 总重量 g(itemType=2) */ -// var totalWeightG: BigDecimal? = null, - /** 统一重量字段,单位千克 */ - var weight: BigDecimal? = null, - /** 验收结果:1-合格 / 2-轻微差异 / 3-不合格 / 4-待验 */ - var checkResult: Short? = null, - /** 存储温度(℃) */ - var temperature: BigDecimal? = null, - /** 存储湿度(%) */ - var humidity: BigDecimal? = null, - /** 剩余保质期(小时) */ - var shelfLifeRemain: Int? = null, - var storeTime: String? = null, - /** 格口状态:1-存放中 / 2-临期预警 / 3-温度超标 / 4-空置 / 5-异常 */ - var slotStatus: Short = 0, - /** 绑定菜品 id(itemType=2) */ - var foodId: Long? = null, - var unit: String? = null, - var remark: String? = null, - var canteenId: Long? = null, - var isClicked: Boolean = false -) : Serializable diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt deleted file mode 100644 index b533bd0..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -data class ShelfResult( - val placeId: String = "", - val canteenName: String = "", - val deviceName: String = "", - val containerGoodsList: List? = null -) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncBody.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncBody.kt deleted file mode 100644 index 32e3468..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncBody.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import java.math.BigDecimal - -/** - * 全量同步整柜数据请求体,对应接口 4.3 - * 注意:goodsList 为空或不传时,后端会软删除整柜所有格口数据 - */ -data class SyncBody( - var cabinetId: String?=null, - var temperature: BigDecimal? = null, - var humidity: BigDecimal? = null, - var goodsList: List? = null, -) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncItem.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncItem.kt deleted file mode 100644 index 4274138..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/SyncItem.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.shuwei.intelligent.shelves.model - -import java.math.BigDecimal - -/** - * 全量同步单格口数据,对应接口 4.3 goodsList 元素 - */ -data class SyncItem( - val slotNo: String, - /** 类型:1-食材净菜 / 2-餐品净菜包 */ - val itemType: Short? = null, - val itemName: String? = null, - /** 关联净菜订单号(从下拉选项 orderNo 取值回传) */ - val cleanOrderNo: String? = null, - /** 绑定菜品 id(itemType=2) */ - val foodId: Long? = null, - /** 订单量 kg(itemType=1) */ - val orderQty: BigDecimal? = null, - /** 实收量 kg(itemType=1,与 totalWeightG 二选一) */ - val actualQty: BigDecimal? = null, - /** 总重量 g(itemType=2,后端自动换算为 kg 存储) */ - val totalWeightG: BigDecimal? = null, - /** 规格:1-标准份 / 2-大份 / 3-小份(itemType=2) */ - val spec: Int? = null, - val pkgCount: Int? = null, - /** 验收结果:1-合格 / 2-轻微差异 / 3-不合格 / 4-待验 */ - val checkResult: Short? = null, - /** 格口状态:1-存放中 / 2-临期预警 / 3-温度超标 / 4-空置 / 5-异常 */ - val slotStatus: Short? = null, - /** 剩余保质期(小时) */ - val shelfLifeRemain: Int? = null, - /** 存入时间,仅新增时生效,不传则取当前时间 */ - val storeTime: String? = null, - val remark: String? = null, -) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt deleted file mode 100644 index a4be911..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.shuwei.intelligent.shelves.net - -import com.shuwei.intelligent.shelves.App -import com.shuwei.intelligent.shelves.model.DeviceConfigInfo -import com.shuwei.intelligent.shelves.model.GoodsModel -import com.shuwei.intelligent.shelves.model.ShelfBody -import com.shuwei.intelligent.shelves.model.ShelfResult -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Query -import retrofit2.http.Url - -interface ApiService { -// /** -// * device获取token -// */ -// @GET("/sys/getEquipmentToken") -// suspend fun getDeviceToken( -// @Query("qrcodeId") qrcodeId: String, -// @Query("appVersion") appVersion: String = App.appVersion -// ): RespData -// -// /** -// *获取配置信息 -// */ -// @GET("/equipment/stEquipment/queryByEquipmentCode") -// suspend fun getDeviceInfo( -// @Query("equipmentCode") equipmentCode: String, -// @Query("appVersion") appVersion: String = App.appVersion -// ): RespData -// -// @GET -// suspend fun getAccessToken( -// @Url url: String = UrlConfig.GET_ACCESS_TOKEN, -// @Query("qrcodeId") qrcodeId: String -// ): RespData - - @GET - suspend fun getShelfList( - @Url url: String = UrlConfig.GET_SHELF_LIST, - @Query("deviceId") deviceId: String - ): RespData - - @GET - suspend fun getGoodsList( - @Url url: String = UrlConfig.GET_GOODS_LIST, - @Query("canteenId") canteenId: String = "0", - @Query("goodsName") goodsName: String? = null, - @Query("pageNo") pageNo: Int = 1, - @Query("pageSize") pageSize: Int = 50 - ): RespData?> - - @POST - suspend fun saveShelfGoodsList( - @Url url: String = UrlConfig.SAVE_SHELF_GOODS_LIST, - @Body body: ShelfBody - ): RespData - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiServiceV2.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiServiceV2.kt deleted file mode 100644 index 63912c0..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiServiceV2.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.shuwei.intelligent.shelves.net - -import com.shuwei.intelligent.shelves.model.CabinetInitResult -import com.shuwei.intelligent.shelves.model.CleanPackageOption -import com.shuwei.intelligent.shelves.model.MealPackageOption -import com.shuwei.intelligent.shelves.model.SyncBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query -import retrofit2.http.Url - -interface ApiServiceV2 { - - /** - * 4.1 货柜初始化 - * 设备启动、Token 刷新后、首页重试时调用 - */ - @GET - suspend fun initCabinet( - @Url url: String = UrlConfig.CABINET_INIT, - @Query("cabinetId") cabinetId: String - ): RespData - - /** - * 4.2.1 净菜包下拉列表(itemType=1) - */ - @GET - suspend fun getCleanPackageOptions( - @Url url: String = UrlConfig.CLEAN_PACKAGE_OPTIONS, - @Query("keyword") keyword: String? = null - ): RespData> - - /** - * 4.2.2 餐品净菜包下拉列表(itemType=2) - */ - @GET - suspend fun getMealPackageOptions( - @Url url: String = UrlConfig.MEAL_PACKAGE_OPTIONS, - @Query("keyword") keyword: String? = null - ): RespData> - - /** - * 4.3 全量同步整柜数据(定时上报) - * 警告:body.goodsList 为 null 或空列表时,后端会软删除整柜所有格口数据 - */ - @POST - suspend fun syncCabinetData( - @Url url: String = UrlConfig.CABINET_RECORD_SYNC, - @Body body: SyncBody - ): RespData -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt index 97da647..c383630 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt @@ -34,22 +34,7 @@ class DynamicBaseUrlInterceptor : Interceptor { } } -val apiService: ApiService = Retrofit.Builder() - .baseUrl("http://placeholder/") - .client(HttpManager.instance.client) - .addConverterFactory(GsonConverterFactory.create()) - .build() - .create(ApiService::class.java) - -/** v1.1 接口专用实例,使用轻量拦截器,不携带旧鉴权 Token */ -val apiServiceV2: ApiServiceV2 = Retrofit.Builder() - .baseUrl("http://placeholder/") - .client(HttpManager.instance.cabinetClient) - .addConverterFactory(GsonConverterFactory.create()) - .build() - .create(ApiServiceV2::class.java) - -/** V3 接口专用实例,与 V2 共用 cabinetClient(同款拦截器) */ +/** V3 接口专用实例 */ val apiServiceV3: ApiServiceV3 = Retrofit.Builder() .baseUrl(GlobalData.appBaseUrl) .client(HttpManager.instance.cabinetClient) @@ -58,38 +43,8 @@ val apiServiceV3: ApiServiceV3 = Retrofit.Builder() .create(ApiServiceV3::class.java) class HttpManager private constructor() { - val client: OkHttpClient by lazy { - OkHttpClient.Builder() - .apply { - connectTimeout(30, TimeUnit.SECONDS) - readTimeout(30, TimeUnit.SECONDS) - writeTimeout(30, TimeUnit.SECONDS) - sslSocketFactory(createSSLSocketFactory(), TrustAllCerts()) - hostnameVerifier { _, _ -> true } -// addInterceptor(LoggingInterceptor()) - addInterceptor(DynamicBaseUrlInterceptor()) - addNetworkInterceptor(HttpLoggingInterceptor(logger = { - Log.d("HttpManager","okhttp logger ==>${it}") - }).apply { - level = - if (BuildConfig.DEBUG) { - HttpLoggingInterceptor.Level.BODY - } else { - HttpLoggingInterceptor.Level.NONE - } - }) -// addInterceptor { chain -> -// val request = chain.request().newBuilder() -// .header("x-access-token", App.accessToken) -// .build() -// chain.proceed(request) -// } - addInterceptor(RequestInterceptor()) - } - .build() - } - /** v1.1 接口专用 OkHttpClient,仅注入 Content-Type、Accept、X-DEVICE-CODE */ + /** 接口专用 OkHttpClient,注入 Content-Type、Accept、X-DEVICE-CODE、authorization */ val cabinetClient: OkHttpClient by lazy { OkHttpClient.Builder() .apply { diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt deleted file mode 100644 index f62ffc1..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt +++ /dev/null @@ -1,149 +0,0 @@ -package com.shuwei.intelligent.shelves.net - -import android.util.Log -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.shuwei.intelligent.shelves.App -import com.shuwei.intelligent.shelves.model.ShelfBody -import com.shuwei.intelligent.shelves.utils.ext.toJsonString -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch - -class NetViewModel : ViewModel() { - - private val _getShelfListUiState = MutableStateFlow(UiState.Initial) - val getShelfListUiState: StateFlow = _getShelfListUiState - - private val _getGoodsListUiState = MutableStateFlow(UiState.Initial) - val getGoodsListUiState: StateFlow = _getGoodsListUiState - - private val _getAccessTokenUiState = MutableStateFlow(UiState.Initial) - val getAccessTokenUiState: StateFlow = _getAccessTokenUiState - - private val _getDeviceTokenUiState = MutableStateFlow(UiState.Initial) - val getDeviceTokenUiState: StateFlow = _getDeviceTokenUiState - - private val _getDeviceConfigUiState = MutableStateFlow(UiState.Initial) - val getDeviceConfigUiState: StateFlow = _getDeviceConfigUiState - - private val _updateOverdueStateUiState = MutableStateFlow(UiState.Initial) - val updateOverdueStateUiState: StateFlow = _updateOverdueStateUiState - -// fun getDeviceToken(deviceId: String) { -// viewModelScope.launch { -// _getDeviceTokenUiState.value = UiState.Loading -// runCatching { -// val response = apiService.getDeviceToken(qrcodeId = deviceId) -// if (response.isSuccess()) { -// _getDeviceTokenUiState.value = UiState.Success(response) -// } else { -// _getDeviceTokenUiState.value = UiState.Error(response.msg ?: "请求失败") -// } -// }.onFailure { -// _getDeviceTokenUiState.value = UiState.Error(it.message ?: "请求异常") -// } -// } -// } - -// fun getDeviceConfig(deviceId: String, deviceToken: String) { -// viewModelScope.launch { -// _getDeviceConfigUiState.value = UiState.Loading -// runCatching { -// val response = apiService.getDeviceInfo(equipmentCode = deviceId) -// if (response.isSuccess()) { -// _getDeviceConfigUiState.value = UiState.Success(response) -// } else { -// _getDeviceConfigUiState.value = UiState.Error(response.msg ?: "请求失败") -// } -// }.onFailure { -// _getDeviceConfigUiState.value = UiState.Error(it.message ?: "请求异常") -// } -// } -// } - -// fun getAccessToken(deviceId: String) { -// viewModelScope.launch { -// _getAccessTokenUiState.value = UiState.Loading -// runCatching { -// val response = apiService.getAccessToken(qrcodeId = deviceId) -// if (response.isSuccess()) { -// _getAccessTokenUiState.value = UiState.Success(response) -// } else { -// _getAccessTokenUiState.value = UiState.Error(response.msg ?: "请求失败") -// } -// }.onFailure { -// _getAccessTokenUiState.value = UiState.Error(it.message ?: "请求异常") -// } -// } -// } - - fun getShelfList(deviceId: String) { - viewModelScope.launch { - _getShelfListUiState.value = UiState.Loading - runCatching { - val response = apiService.getShelfList(deviceId = deviceId) - if (response.isSuccess()) { - _getShelfListUiState.value = UiState.Success(response) - } else { - _getShelfListUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _getShelfListUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - fun updateOverdueState() { - viewModelScope.launch { - runCatching { - val response = apiService.getShelfList(deviceId = App.deviceId) - if (response.isSuccess()) { - _updateOverdueStateUiState.value = UiState.Success(response) - } else { - _updateOverdueStateUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _updateOverdueStateUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - fun getGoodsList( - canteenId: String = "", - goodsName: String = "", - pageNo: Int = 1, - pageSize: Int = 50, - ) { - viewModelScope.launch { - _getGoodsListUiState.value = UiState.Loading - runCatching { - val response = apiService.getGoodsList( - canteenId = canteenId, - goodsName = goodsName, - pageNo = pageNo, - pageSize = pageSize - ) - if (response.isSuccess()) { - _getGoodsListUiState.value = UiState.Success(response) - } else { - _getGoodsListUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _getGoodsListUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - fun saveShelfGoodsList(body: ShelfBody) { - viewModelScope.launch { - runCatching { - val resp = apiService.saveShelfGoodsList(body = body) - Log.d("NetViewModel", "saveShelfGoodsList,performSync: resp:${resp.toJsonString()}") - }.onFailure { - it.printStackTrace() - Log.d("NetViewModel", "saveShelfGoodsList异常:${it.message}") - } - } - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModelV2.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModelV2.kt deleted file mode 100644 index 1e9adeb..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModelV2.kt +++ /dev/null @@ -1,99 +0,0 @@ -package com.shuwei.intelligent.shelves.net - -import android.util.Log -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.shuwei.intelligent.shelves.model.CabinetInitResult -import com.shuwei.intelligent.shelves.model.CleanPackageOption -import com.shuwei.intelligent.shelves.model.MealPackageOption -import com.shuwei.intelligent.shelves.model.SyncBody -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch - -class NetViewModelV2 : ViewModel() { - - private val _initCabinetUiState = MutableStateFlow(UiState.Initial) - val initCabinetUiState: StateFlow = _initCabinetUiState - - private val _cleanPackageOptionsUiState = MutableStateFlow(UiState.Initial) - val cleanPackageOptionsUiState: StateFlow = _cleanPackageOptionsUiState - - private val _mealPackageOptionsUiState = MutableStateFlow(UiState.Initial) - val mealPackageOptionsUiState: StateFlow = _mealPackageOptionsUiState - - private val _syncCabinetUiState = MutableStateFlow(UiState.Initial) - val syncCabinetUiState: StateFlow = _syncCabinetUiState - - /** 4.1 货柜初始化 */ - fun initCabinet(cabinetId: String) { - viewModelScope.launch { - _initCabinetUiState.value = UiState.Loading - runCatching { - val response = apiServiceV2.initCabinet(cabinetId = cabinetId) - if (response.isSuccess()) { - _initCabinetUiState.value = UiState.Success(response) - } else { - _initCabinetUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _initCabinetUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - /** 4.2.1 净菜包下拉列表(itemType=1) */ - fun getCleanPackageOptions(keyword: String? = null) { - viewModelScope.launch { - _cleanPackageOptionsUiState.value = UiState.Loading - runCatching { - val response = apiServiceV2.getCleanPackageOptions(keyword = keyword) - if (response.isSuccess()) { - _cleanPackageOptionsUiState.value = UiState.Success(response) - } else { - _cleanPackageOptionsUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _cleanPackageOptionsUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - /** 4.2.2 餐品净菜包下拉列表(itemType=2) */ - fun getMealPackageOptions(keyword: String? = null) { - viewModelScope.launch { - _mealPackageOptionsUiState.value = UiState.Loading - runCatching { - val response = apiServiceV2.getMealPackageOptions(keyword = keyword) - if (response.isSuccess()) { - _mealPackageOptionsUiState.value = UiState.Success(response) - } else { - _mealPackageOptionsUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - _mealPackageOptionsUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } - - /** - * 4.3 全量同步整柜数据 - * 警告:body.goodsList 为 null 或空列表时,后端会软删除整柜所有格口数据 - */ - fun syncCabinetData(body: SyncBody) { - viewModelScope.launch { - _syncCabinetUiState.value = UiState.Loading - runCatching { - val response = apiServiceV2.syncCabinetData(body = body) - if (response.isSuccess()) { - _syncCabinetUiState.value = UiState.Success(response) - } else { - _syncCabinetUiState.value = UiState.Error(response.msg ?: "请求失败") - } - }.onFailure { - Log.e("NetViewModelV2", "syncCabinetData 异常:${it.message}") - _syncCabinetUiState.value = UiState.Error(it.message ?: "请求异常") - } - } - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/RequestInterceptor.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/RequestInterceptor.kt deleted file mode 100644 index b44c995..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/net/RequestInterceptor.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.shuwei.intelligent.shelves.net - -import android.text.TextUtils -import com.shuwei.intelligent.shelves.App -import okhttp3.Interceptor -import okhttp3.Request -import okhttp3.Response - -/** - * 请求拦截器 - */ -class RequestInterceptor : Interceptor { - override fun intercept(chain: Interceptor.Chain): Response { - val originalRequest = chain.request() - val requestBuilder = originalRequest.newBuilder() - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("X-Access-Token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiJiZTE1NDgzMS0zNDY2LTNiYTItYTJlYS01NzY1MmM5MTlmZWQiLCJ0eXBlIjoiNCIsInVzZXJJZCI6IjAwMDAwMDAwMDAwMDAwMDAwMDEifQ.sN40cOC-O5WQFrF4IDUs8fFlkNdUKLbJt_rHyTsgYYM") - .header("X-DEVICE-CODE", App.deviceId) - .header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d") - - val newRequest = requestBuilder.build() - - return chain.proceed(newRequest) - } - -// private fun getToken(originRequest: Request): String { -// val tokenParam = originRequest.header("X-Access-Token") -// if (!TextUtils.isEmpty(tokenParam)) return tokenParam!! -// // 从本地获取token的逻辑 -// val spUtil = SPUtil.getInstance(context = App.getContext()) -// return spUtil.get(GlobalKey.KEY_TOKEN, "") as String -//// return "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6MTQ2LCJ1c2VyTmFtZSI6IjEzNjgxNDQ4ODU2IiwibmFtZSI6IuW-kOejiiIsInBhc3N3b3JkIjoiOTllOTQ1ZmVjZmZjNWIzNDI4MmUwNDRlODYyMzdjM2UxZjU5OWY5OCIsInNhbHQiOiI0NmEzMzUzYWU4OTA0MDYxYjMzODU5ZWNlYTBlMGE2NyIsInBob25lIjoiMTM2ODE0NDg4NTYiLCJzdGF0dXMiOjEsInVzZXJUeXBlIjoyLCJjcmVhdGVVc2VyTm8iOiIxNDEiLCJjcmVhdGVUaW1lIjoxNjI2OTQzNDE2MDAwLCJ1cGRhdGVVc2VyTm8iOiIxNDEiLCJ1cGRhdGVUaW1lIjoxNjI2OTQzNDE2MDAwLCJpc0RlbCI6ZmFsc2UsImVhSWQiOjk5LCJlYUlkTGlzdCI6Ijk5IiwiaXNTaG9wTWFuYWdlciI6dHJ1ZSwidXNlck5vIjoiMWY5Nzk5ZWMtODlkYi00MWYyLTk1YTEtY2UzNTA3Y2QyMTU2In0.f7wImPgBOYMV0AqRchnXGPkUWZN9dFJ9gLPsaB8uNldd21IfXLjJl8y-FiWVuVUvlwUvGpgqGDFR1JKj5H7amw" -// } -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncDeviceTask.kt b/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncDeviceTask.kt deleted file mode 100644 index 8ffe599..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncDeviceTask.kt +++ /dev/null @@ -1,32 +0,0 @@ -//package com.shuwei.intelligent.shelves.task -// -//import android.content.Context -//import android.util.Log -//import androidx.work.CoroutineWorker -//import androidx.work.WorkerParameters -//import com.shuwei.intelligent.shelves.activity.HomeActivity -//import com.shuwei.intelligent.shelves.serial.SerialPortManager -// -//class SyncDeviceTask(appContext: Context, workerParams: WorkerParameters) : -// CoroutineWorker(appContext, workerParams) { -// -// companion object { -// private const val TAG = "SyncDeviceTask" -// } -// -// override suspend fun doWork(): Result { -// return try { -// // 执行后台任务逻辑 -// Log.d(TAG, "doWork: ----------SyncDeviceTask----------") -// SerialPortManager.send(HomeActivity.DEVICE_INFO_CMD) -// -// TaskManager.startDeviceTask() -// -// Result.success() -// } catch (e: Exception) { -// e.printStackTrace() -// Result.retry() -// } -// } -// -//} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt b/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt deleted file mode 100644 index 2a3a808..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt +++ /dev/null @@ -1,67 +0,0 @@ -//package com.shuwei.intelligent.shelves.task -// -//import android.content.Context -//import android.util.Log -//import androidx.work.CoroutineWorker -//import androidx.work.WorkerParameters -//import com.shuwei.intelligent.shelves.App -//import com.shuwei.intelligent.shelves.activity.HomeActivity -//import com.shuwei.intelligent.shelves.model.ShelfBody -//import com.shuwei.intelligent.shelves.net.apiService -//import com.shuwei.intelligent.shelves.utils.ext.toJsonString -//import kotlinx.coroutines.Dispatchers -//import kotlinx.coroutines.withContext -// -//class SyncTask(appContext: Context, workerParams: WorkerParameters) : -// CoroutineWorker(appContext, workerParams) { -// -// companion object { -// private const val TAG = "SyncTask" -// } -// -// override suspend fun doWork(): Result { -// return try { -// // 执行后台任务逻辑 -// performSync() -// -// TaskManager.startTask() -// -// Result.success() -// } catch (e: Exception) { -// e.printStackTrace() -// Result.retry() -// } -// } -// -// private suspend fun performSync() { -// withContext(Dispatchers.IO) { -// val list = HomeActivity.list -// Log.d(TAG, "performSync: list:${list.toJsonString()}") -// val submitList = list.sortedBy { it.deviceNo } -// submitList.forEach { -// if (it.goodsId.isNullOrBlank()) { -// it.weight = it.weightBak -// } -// } -//// submitList.forEach { -//// it.temperature = HomeActivity.showTemperatureC -//// it.humidity = HomeActivity.showHumidity -//// } -// val body = ShelfBody().also { -// it.deviceId = App.deviceId -// it.canteenId = App.canteenId -// it.temperature = HomeActivity.showTemperatureC -// it.humidity = HomeActivity.showHumidity -// it.goodsList = submitList -// } -// Log.d(TAG, "performSync: body:${body.toJsonString()}") -// try { -// val resp = apiService.saveShelfGoodsList(body = body) -// Log.d(TAG, "performSync: resp:${resp.toJsonString()}") -// } catch (e: Exception) { -// e.printStackTrace() -// } -// } -// } -// -//} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/task/TaskManager.kt b/app/src/main/java/com/shuwei/intelligent/shelves/task/TaskManager.kt deleted file mode 100644 index 3e4a086..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/task/TaskManager.kt +++ /dev/null @@ -1,59 +0,0 @@ -//package com.shuwei.intelligent.shelves.task -// -//import androidx.work.ExistingWorkPolicy -//import androidx.work.OneTimeWorkRequestBuilder -//import androidx.work.WorkManager -//import com.shuwei.intelligent.shelves.App -//import java.util.concurrent.TimeUnit -// -//object TaskManager { -// const val TASK_NAME = "IntelligentShelvesSyncTask" -// const val DEVICE_TASK_NAME = "IntelligentShelvesDeviceTask" -// -// fun startTask() { -// val nextRequest = OneTimeWorkRequestBuilder() -// .setInitialDelay(2, TimeUnit.MINUTES) -//// .setInitialDelay(30, TimeUnit.SECONDS) -//// .setInitialDelay(10, TimeUnit.MINUTES) -//// .setInputData(inputData) -// .build() -// WorkManager.getInstance(App.getInstance()) -// .enqueueUniqueWork(TASK_NAME, ExistingWorkPolicy.REPLACE, nextRequest) -// -//// val constraints = Constraints.Builder() -//// .setRequiredNetworkType(NetworkType.CONNECTED) -//// .setRequiresBatteryNotLow(true) -//// .build() -//// val syncRequest = PeriodicWorkRequestBuilder( -//// 3L, TimeUnit.MINUTES, // 最小间隔15分钟 -//// 3L, TimeUnit.MINUTES // 弹性时间窗口 -//// ) -//// .setConstraints(constraints) -//// .build() -//// WorkManager.getInstance(App.get()) -//// .enqueueUniquePeriodicWork( -//// TASK_NAME, -//// ExistingPeriodicWorkPolicy.KEEP, -//// syncRequest -//// ) -// } -// -// fun cancelTask() { -// WorkManager.getInstance(App.getInstance()) -// .cancelUniqueWork(TASK_NAME) -// } -// -// fun startDeviceTask() { -// val nextRequest = OneTimeWorkRequestBuilder() -// .setInitialDelay(2, TimeUnit.MINUTES) -// .build() -// WorkManager.getInstance(App.getInstance()) -// .enqueueUniqueWork(DEVICE_TASK_NAME, ExistingWorkPolicy.REPLACE, nextRequest) -// } -// -// fun cancelDeviceTask() { -// WorkManager.getInstance(App.getInstance()) -// .cancelUniqueWork(DEVICE_TASK_NAME) -// } -// -//} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/Constant.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/Constant.kt deleted file mode 100644 index bd38c5a..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/Constant.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.shuwei.intelligent.shelves.utils - -/** - * 命令常亮定义 - */ -object Constant { - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/F2C.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/F2C.kt deleted file mode 100644 index 3977ba4..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/F2C.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.shuwei.intelligent.shelves.utils - -fun f2C(fahrenheit: Double): Double { - return (fahrenheit - 32) * 5 / 9 -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/GridLayoutTool.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/GridLayoutTool.kt deleted file mode 100644 index 5fa90b1..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/GridLayoutTool.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.shuwei.intelligent.shelves.utils - -import android.content.Context -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.shuwei.intelligent.shelves.App -import com.shuwei.intelligent.shelves.model.ShelfModel -import com.shuwei.intelligent.shelves.model.ShelfModelV2 -import com.shuwei.intelligent.shelves.serial.ProtocolConstants -import com.sw.scalefusion.shelf.model.SlotModel - -object GridLayoutTool { - - /** - * 设备2列,10格 - */ - private val device2Columns = ProtocolConstants.device2Columns - - /** - * 设备3列,15格,左侧1列竖向编号1、2、3、4、5,右侧2列5行编号为6-7、8-9、10-11、12-13、14-15 - */ - private val device3Columns = ProtocolConstants.device3Columns - - fun getLayoutManager(context: Context): RecyclerView.LayoutManager? { - return if (device2Columns.contains(App.deviceId)) { - GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false) - } else if (device3Columns.contains(App.deviceId)) { - GridLayoutManager(context, 3, GridLayoutManager.VERTICAL, false) - } else { - null - } - } - - fun getLayoutManagerV2(context: Context, columns: Int) = GridLayoutManager(context, columns, GridLayoutManager.VERTICAL, false) - - /** - * 初始化list显示顺序 - */ - fun initListSort(source: List): List { - val map = source.associateBy { it.deviceNo } - return if (device3Columns.contains(App.deviceId)) { - // 按全局定义的显示顺序取对应数据,找不到则跳过 - ProtocolConstants.device3ColumnsOrder.mapNotNull { map[it] } - } else if (device2Columns.contains(App.deviceId)) { - ProtocolConstants.device2ColumnsOrder.mapNotNull { map[it] } - } else { - source - } - } - - fun initListSortV2(rows:Int, columns:Int, source: List): List { - val map = source.associateBy { it.slotNo?.toIntOrNull()?:0 } - if (rows != 5) return source - return when (columns) { - 3 -> { - // 3列顺序 - ProtocolConstants.device3ColumnsOrder.mapNotNull { map[it] } - } - 2 -> { - // 2列顺序 - ProtocolConstants.device2ColumnsOrder.mapNotNull { map[it] } - } - else -> { - //没有则默认 - source - } - } - } - fun submitListSortV2(source: List): List { - return source.sortedBy { it.slotNo?.toIntOrNull()?:0 } - } - - fun initListSortV3(rows: Int, columns: Int, source: List): List { - val map = source.associateBy { it.slotNo.toIntOrNull() ?: 0 } - if (rows != 5) return source - return when (columns) { - 3 -> ProtocolConstants.device3ColumnsOrder.mapNotNull { map[it] } - 2 -> ProtocolConstants.device2ColumnsOrder.mapNotNull { map[it] } - else -> source - } - } - - fun submitListSortV3(source: List): List { - return source.sortedBy { it.slotNo.toIntOrNull() ?: 0 } - } - - /** - * 提交接口list顺序 - */ - fun submitListSort(source: List): List { - return source.sortedBy { it.deviceNo } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/HexUtils.java b/app/src/main/java/com/shuwei/intelligent/shelves/utils/HexUtils.java deleted file mode 100644 index 37b58ac..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/HexUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.shuwei.intelligent.shelves.utils; - - -public class HexUtils { - - /** - * 将有符号十六进制字符串转换为十进制整数 - * @param hex 十六进制字符串(支持负数补码表示) - * @return 对应的十进制整数 - */ - public static int signedHexToDec(String hex) { - // 验证输入格式 - if (hex == null || hex.isEmpty()) { - throw new IllegalArgumentException("输入不能为空"); - } - - if (!hex.matches("[0-9A-Fa-f]+")) { - throw new IllegalArgumentException("无效的十六进制格式: " + hex); - } - - // 转换为无符号长整型 - long unsignedValue = Long.parseLong(hex, 16); - - // 判断是否为负数(最高位为1) - int bitLength = hex.length() * 4; // 每个十六进制字符对应4位 - long signBitMask = 1L << (bitLength - 1); - - if ((unsignedValue & signBitMask) != 0) { - // 负数:计算补码 - long maxValue = (1L << bitLength) - 1; - return (int) (unsignedValue - (maxValue + 1)); - } else { - // 正数:直接转换 - return (int) unsignedValue; - } - } - - /** - * 测试方法 - */ - public static void main(String[] args) { - // 测试用例 - String[] testCases = { - "FF", // -1 (8位) - "FFFE", // -2 (16位) - "FFFFFFFE", // -2 (32位) - "7F", // 127 - "80", // -128 - "7FFF", // 32767 - "8000" // -32768 - }; - - System.out.println("有符号十六进制转换测试:"); - for (String hex : testCases) { - try { - int result = signedHexToDec(hex); - System.out.println(hex + " -> " + result); - } catch (Exception e) { - System.out.println(hex + " -> 错误: " + e.getMessage()); - } - } - } -} - diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/QRCodeUtil.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/QRCodeUtil.kt deleted file mode 100644 index b05a2ca..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/QRCodeUtil.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.shuwei.intelligent.shelves.utils - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Color -import com.google.zxing.BarcodeFormat -import com.google.zxing.EncodeHintType -import com.google.zxing.WriterException -import com.google.zxing.common.BitMatrix -import com.google.zxing.qrcode.QRCodeWriter -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel - - -/** - * 二维码生成工具类 - */ -object QRCodeUtil { - - /** - * 生成二维码(默认大小) - * @param content 二维码内容 - * @return 生成的二维码Bitmap - */ - @JvmOverloads - fun generateQRCode(content: String, size: Int = 500): Bitmap? { - return generateQRCode(content, size, Color.BLACK, Color.WHITE) - } - - /** - * 生成二维码(自定义颜色) - * @param content 二维码内容 - * @param size 二维码边长(像素) - * @param colorCode 二维码颜色 - * @param backgroundColor 背景颜色 - * @return 生成的二维码Bitmap - */ - fun generateQRCode( - content: String, - size: Int, - colorCode: Int, - backgroundColor: Int - ): Bitmap? { - if (content.isEmpty()) { - return null - } - - return try { - val hints = mutableMapOf().apply { - put(EncodeHintType.CHARACTER_SET, "UTF-8") - put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) // 纠错级别 - put(EncodeHintType.MARGIN, 1) // 边距 - } - - val bitMatrix = QRCodeWriter().encode( - content, - BarcodeFormat.QR_CODE, - size, - size, - hints - ) - - val pixels = IntArray(size * size).apply { - for (y in 0 until size) { - for (x in 0 until size) { - this[y * size + x] = if (bitMatrix.get(x, y)) colorCode else backgroundColor - } - } - } - - Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply { - setPixels(pixels, 0, size, 0, 0, size, size) - } - - } catch (e: WriterException) { - e.printStackTrace() - null - } - } - - /** - * 生成带Logo的二维码 - * @param content 二维码内容 - * @param size 二维码边长(像素) - * @param logo Logo Bitmap - * @return 带Logo的二维码Bitmap - */ - fun generateQRCodeWithLogo(content: String, size: Int, logo: Bitmap?): Bitmap? { - val qrCode = generateQRCode(content, size) ?: return null - logo ?: return qrCode - - val logoSize = size / 5 // Logo大小约为二维码的1/5 - val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, false) - - val offset = (size - logoSize) / 2 - return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply { - val canvas = Canvas(this) - canvas.drawBitmap(qrCode, 0f, 0f, null) - canvas.drawBitmap(scaledLogo, offset.toFloat(), offset.toFloat(), null) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/SerialPortHelper.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/SerialPortHelper.kt deleted file mode 100644 index b071891..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/SerialPortHelper.kt +++ /dev/null @@ -1,57 +0,0 @@ -//package com.shuwei.intelligent.shelves.utils -// -// -//import android.serialport.* -////import io.github.jeadyx.jserialport.SerialPort -//import java.io.File -//import java.io.IOException -//import java.io.InputStream -//import java.io.OutputStream -// -//class SerialPortHelper( -// private val devicePath: String = "/dev/ttyS1", -// private val baudRate: Int = 115200 -//) { -// private var serialPort: SerialPort? = null -// private var inputStream: InputStream? = null -// private var outputStream: OutputStream? = null -// -// // 打开串口 -// fun open(): Boolean { -// return try { -// serialPort = SerialPort(File(devicePath), baudRate, 0) -// inputStream = serialPort?.inputStream -// outputStream = serialPort?.outputStream -// true -// } catch (e: IOException) { -// false -// } -// } -// -// // 发送数据 -// fun send(data: ByteArray): Boolean { -// return try { -// outputStream?.write(data) -// outputStream?.flush() -// true -// } catch (e: IOException) { -// false -// } -// } -// -// // 接收数据(需在子线程调用) -// fun receive(buffer: ByteArray): Int { -// return inputStream?.read(buffer) ?: -1 -// } -// -// // 关闭串口 -// fun close() { -// try { -// inputStream?.close() -// outputStream?.close() -// serialPort?.close() -// } catch (e: IOException) { -// e.printStackTrace() -// } -// } -//} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/StaleFoodRule.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/StaleFoodRule.kt deleted file mode 100644 index 033d7a3..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/StaleFoodRule.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.shuwei.intelligent.shelves.utils - -import android.util.SparseArray -import androidx.core.util.containsKey -import com.shuwei.intelligent.shelves.model.ShelfModel - -object StaleFoodRule { - - private val shelfMap = SparseArray() - -// fun load(list: MutableList) { -// if (list.isEmpty()) { -// return -// } -// list.forEach { -// shelfMap.put(it.deviceNo, it) -// } -// } - - fun judge(item: ShelfModel, block:(Boolean)-> Unit = {}) { - val deviceNo = item.deviceNo - if (!shelfMap.containsKey(deviceNo)) { - //首次设置数据 - shelfMap.put(deviceNo, item) - return - } - val lastItem = shelfMap.get(deviceNo) - if (lastItem.goodsId != item.goodsId) { - //柜子商品更换 - shelfMap.put(deviceNo, item) - return - } - //同一产品 - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/TemperatureInfoHK70MsgBodyUnpack.java b/app/src/main/java/com/shuwei/intelligent/shelves/utils/TemperatureInfoHK70MsgBodyUnpack.java deleted file mode 100644 index 50dfe5e..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/TemperatureInfoHK70MsgBodyUnpack.java +++ /dev/null @@ -1,282 +0,0 @@ -package com.shuwei.intelligent.shelves.utils; - -//import cn.hutool.core.util.HexUtil; -//import cn.hutool.core.util.StrUtil; -//import com.chengyi.framework.utils.HexUtils; -//import lombok.Data; -//import lombok.extern.slf4j.Slf4j; - -/** - * @Author: NThink - * @Date: 2021/12/10 - * @Description: 鸿科HK70温控器信息消息解包 - */ -public class TemperatureInfoHK70MsgBodyUnpack { - - // 柜温探头温度 - private Double gwttTemp; - - // 蒸发探头温度 - private Double zfttTemp; - - // 冷凝探头温度 - private Double lnttTemp; - - // 停机温度 - private Double tjTemp; - - // 开机温度回差 - private Double kjTempRange; - - // 压缩机启动延时 - private Integer ysjStartDelay; - - // 首次通电压缩机启动延时 - private Integer ysjStartDelayFirst; - - // 柜温探头补偿 - private Double gwttbcTemp; - - // 停机温度可设置的最小值 - private Double tjTempMin; - - // 停机温度可设置的最大值 - private Double tjTempMax; - - // 压缩机最大待机时间 - private Integer ysjMaxWait; - - // 压缩机最短运行时间 - private Integer ysjMinWork; - - // 蒸发器探头状态 - private Integer zfttStatus; - - // 自动除霜周期 - private Integer zdcszq; - - // 除霜过程显示 - private Integer csWorkShow; - - // 除霜最长时间 - private Integer cszcsj; - - // 除霜中止温度 - private Double cszzTemp; - - // 除霜类型 - private Integer csType; - - // 风机运行模式 - private Integer fanWorkType; - - // 风机首次启动延时 - private Integer fanFirstStartDelay; - - // 滴水后风机启动延时 - private Integer fanStartDelayAfterDrip; - - // 开关机状态 - private String powerStatus; - - // 制冷状态 - private String coolStatus; - - // 除霜状态 - private String csStatus; - - // 滴水状态 - private String dsStatus; - - // 柜温探头报警 - private String gwttAlarm; - - // 除霜探头报警 - private String csttAlarm; - - // 冷凝探头报警 - private String lnttAlarm; - - // 终端ID - private String imei; - - // 固件版本 - private String version; - - // 命令次数 - private Integer cmdCount; - - public TemperatureInfoHK70MsgBodyUnpack(String body) { - // ===================== 寄存器内容:110字节 ===================== - String jcqContent = body.substring(0, 220); - // 柜温探头温度 [0, 4] - double gwttTemp = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(0, 4)) * 0.1)); -// setGwttTemp(gwttTemp); -// // 蒸发探头温度 [4, 8] -// double zfttTemp = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(4, 8)) * 0.1)); -// setZfttTemp(zfttTemp); -// // 冷凝探头温度 [8, 12] -// double lnttTemp = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(8, 12)) * 0.1)); -// setLnttTemp(lnttTemp); -// // 停机温度 [12, 16] -// double tjTemp = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(12, 16)) * 1.0)); -// setTjTemp(tjTemp); -// // 开机温度回差 [16, 20] -// double kjwdhc = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(16, 20)) * 0.1)); -// setKjTempRange(kjwdhc); -// // 压缩机启动延时 [20, 24] -// int ysjqdys = Integer.parseInt(jcqContent.substring(20, 24), 16); -// setYsjStartDelay(ysjqdys); -// // 首次通电压缩机启动延时 [24, 28] -// int ysjqdysFirst = Integer.parseInt(jcqContent.substring(24, 28), 16); -// setYsjStartDelayFirst(ysjqdysFirst); -// // 柜温探头补偿 [28, 32] -// double gwttbc = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(28, 32)) * 0.1)); -// setGwttbcTemp(gwttbc); -// // 停机温度可设置的最小值 [32, 36] -// double tjTempMin = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(32, 36)) * 1.0)); -// setTjTempMin(tjTempMin); -// // 停机温度可设置的最大值 [36, 40] -// double tjTempMax = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(36, 40)) * 1.0)); -// setTjTempMin(tjTempMax); -// // 压缩机最大待机时间 [40, 44] -// int ysjzddjsj = Integer.parseInt(jcqContent.substring(40, 44), 16); -// setYsjMaxWait(ysjzddjsj); -// // 压缩机最短运行时间 [44, 48] -// int ysjzdyxsj = Integer.parseInt(jcqContent.substring(44, 48), 16); -// setYsjMinWork(ysjzdyxsj); -// // 蒸发器探头选择 [48, 52] -// int zfqtt = Integer.parseInt(jcqContent.substring(48, 52), 16); -// setZfttStatus(zfqtt); -// // TODO 蒸发器探头补偿 [52, 56] -// // TODO 自动除霜周期计算方式 [56, 60] -// // 自动除霜周期 [60, 64] -// int zdcszq = Integer.parseInt(jcqContent.substring(60, 64), 16); -// setZdcszq(zdcszq); -// // 除霜过程显示选择 [64, 68] -// int csgcxx = Integer.parseInt(jcqContent.substring(64, 68), 16); -// setCsWorkShow(csgcxx); -// // 除霜最长时间 [68, 72] -// int cszcsj = Integer.parseInt(jcqContent.substring(68, 72), 16); -// setCszcsj(cszcsj); -// // 除霜终止温度 [72, 76] -// double cszzwd = Double.parseDouble(String.format("%.1f", HexUtils.signedHexToDec(jcqContent.substring(72, 76)) * 1.0)); -// setCszzTemp(cszzwd); -// // TODO 除霜滴水时间 [76, 80] -// // TODO 除霜后柜温显示延时 [80, 84] -// // TODO 除霜启动延迟 [84, 88] -// // 除霜类型选择 [88, 92] -// int cslx = Integer.parseInt(jcqContent.substring(88, 92), 16); -// setCsType(cslx); -// // TODO 辅热提前启动时间 [92, 96] -// // TODO 强制除霜温度 [96, 100] -// // 风机运行模式 [100, 104] -// int fjyxms = Integer.parseInt(jcqContent.substring(100, 104), 16); -// setFanWorkType(fjyxms); -// // 风机首次启动延时 [104, 108] -// int fjscqdys = Integer.parseInt(jcqContent.substring(104, 108), 16); -// setFanFirstStartDelay(fjscqdys); -// // 滴水后风机启动延时 [108, 112] -// int dshfjqdys = Integer.parseInt(jcqContent.substring(108, 112), 16); -// setFanStartDelayAfterDrip(dshfjqdys); -// // TODO 风机工作最低温度 [112, 116] -// // TODO 风机工作最高温度 [116, 120] -// // TODO 风机循环开启时间 [120, 124] -// // TODO 风机循环关闭时间 [124, 128] -// // TODO 比例制冷压缩机停止时间 [128, 132] -// // TODO 比例制冷压缩机运行时间 [132, 136] -// // TODO 蜂鸣音报警 [136, 140] -// // TODO 柜温低温报警(绝对温度) [140, 144] -// // TODO 柜温高温报警(绝对温度) [144, 148] -// // TODO 柜温报警延时 [148, 152] -// // TODO 上电首次柜温报警延时 [152, 156] -// // TODO 辅助继电器功能选择 [156, 160] -// // TODO 门开关控制输出选择 [160, 164] -// // TODO 开门时蜂鸣器响应延时 [164, 168] -// // TODO 第三探头功能选择 [168, 172] -// // TODO 冷凝器高温报警启动值 [172, 176] -// // TODO 冷凝器高温报警下回差 [176, 180] -// // TODO 冷凝器高温保护启动值 [180, 184] -// // TODO 实时时钟功能开关 [不上报] -// // TODO 非营业模式开启时间 [不上报] -// // TODO 非营业模式关闭时间 [不上报] -// // TODO 非营业模式温度增量 [不上报] -// // TODO 非营业模式灯光开启时间 [不上报] -// // TODO 节假日设置 [不上报] -// // TODO 节假日非营业模式开启时间 [不上报] -// // TODO 除雾自动控制模式 [184, 188] -// // TODO 除雾自动开启时间 [188, 192] -// // TODO 除雾自动关闭时间 [192, 196] -// // TODO 开关机自动控制模式 [不上报] -// // TODO 自动开机时间 [不上报] -// // TODO 自动关机时间 [不上报] -// // TODO 单位选择 [196, 200] -// // TODO 柜温每升高 1℃显示延时 [204, 208] -// // TODO 显示分辨率选择 [208, 212] -// // TODO 机器地址 [212, 216] -// // TODO 管理员密码设定 [216, 220] -// -// // ===================== 状态位解析:4字节 ===================== -// // 1.状态信息 -// String statusHexStr = body.substring(220, 224); -// statusHexStr = HexUtils.reverse(statusHexStr); -// String statusBitStr = HexUtils.hexString2binaryString(statusHexStr); -// statusBitStr = StrUtil.reverse(statusBitStr); -// // 机组运行状态 0:停止 1:运行 [0, 1] -// String powerStatus = "0".equals(statusBitStr.substring(0, 1)) ? "close" : "open"; -// setPowerStatus(powerStatus); -// // TODO 自检状态 0:停止 1:运行 [1, 2] -// // 压缩机运行状态 0:停止 1:运行 [2, 3] -// String coolStatus = "0".equals(statusBitStr.substring(3, 4)) ? "close" : "open"; -// setCoolStatus(coolStatus); -// // 除霜状态 0:停止 1:运行 [3, 4] -// String csStatus = "0".equals(statusBitStr.substring(10, 11)) ? "close" : "open"; -// setCsStatus(csStatus); -// // 滴水状态 0:关闭 1:运行中 [4, 5] -// String dsStatus = "0".equals(statusBitStr.substring(12, 13)) ? "close" : "open"; -// setDsStatus(dsStatus); -// // TODO 风机状态 0:停止 1:运行 [5, 6] -// // TODO 除露状态 0:停止 1:运行 [6, 7] -// // TODO 灯光状态 0:停止 1:运行 [7, 8] -// // TODO 除霜加热或电磁阀状态 0:停止 1:运行 [8, 9] -// // TODO 辅助加热状态 0:停止 1:运行 [9, 10] -// // TODO 报警状态 0:停止 1:运行 [10, 11] -// // TODO 开门状态 0:停止 1:运行 [11, 12] -// // TODO 非营业(节能)状态 0:停止 1:运行 [12, 13] -// // TODO 节假日状态 0:停止 1:运行 [13, 14] -// // TODO 保留 0:停止 1:运行 [14, 15] -// // TODO 保留 0:停止 1:运行 [15, 16] -// -// // 2.报警信息 -// String alarmHexStr = body.substring(224, 228); -// String alarmBitStr = HexUtils.hexString2binaryString(alarmHexStr); -// alarmBitStr = StrUtil.reverse(alarmBitStr); -// // 柜温探头故障 0:无报警 1:报警 -// String gwttAlarm = "0".equals(alarmBitStr.substring(0, 1)) ? "normal" : "alarm"; -// setGwttAlarm(gwttAlarm); -// // 除霜探头故障 0:无报警 1:报警 -// String csAlarm = "0".equals(alarmBitStr.substring(1, 2)) ? "normal" : "alarm"; -// setCsttAlarm(csAlarm); -// // 冷凝探头故障 0:无报警 1:报警 -// String lnttAlarm = "0".equals(alarmBitStr.substring(2, 3)) ? "normal" : "alarm"; -// setLnttAlarm(lnttAlarm); -// // TODO 柜温高温报警 0:无报警 1:报警 -// // TODO 柜温低温报警 0:无报警 1:报警 -// // TODO 冷凝高温报警 0:无报警 1:报警 -// // TODO 冷凝保护报警 0:无报警 1:报警 -// // TODO 门打开报警 0:无报警 1:报警 -// // TODO 时钟故障报警 0:无报警 1:报警 -// -// // 终端ID 15字节 -// setImei(HexUtil.decodeHexStr(body.substring(228, 258))); -// // 固件版本 5字节 -// setVersion(HexUtil.decodeHexStr(body.substring(258, 268))); -// // 命令次数 -// setCmdCount(Integer.parseInt(body.substring(268, 270), 16)); - } - - public static void main(String[] args) { -// String reverse = HexUtils.reverse("8000"); -// System.out.println(reverse); - } -} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/DrawableExt.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/DrawableExt.kt deleted file mode 100644 index e65cd55..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/DrawableExt.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.shuwei.intelligent.shelves.utils.ext - -import android.graphics.Color -import android.graphics.drawable.Drawable -import android.graphics.drawable.GradientDrawable -import androidx.core.graphics.toColorInt - -interface DrawableDsl { - fun shape(init: ShapeDsl.() -> Unit) -} - -interface ShapeDsl { - fun solidColor(color: Int) - fun stroke(width: Int, color: Int) - fun cornerRadius(radius: Float) -} - -class DrawableBuilder : DrawableDsl { - val drawables = mutableListOf() - - override fun shape(init: ShapeDsl.() -> Unit) { - val shape = ShapeDrawable() - init(shape) - drawables.add(shape) - } -} - -class ShapeDrawable : ShapeDsl { - var color: Int? = null - var strokeWidth: Int? = null - var strokeColor: Int? = null - var cornerRadius: Float? = null - - override fun solidColor(color: Int) { - this.color = color - } - - override fun stroke(width: Int, color: Int) { - this.strokeWidth = width - this.strokeColor = color - } - - override fun cornerRadius(radius: Float) { - this.cornerRadius = radius - } -} - -fun createCustomDrawable( - solidColor: String, - strokeWidth: Int, - strokeColor: String, - radius: Int -): Drawable { - val builder = DrawableBuilder() - builder.shape { - solidColor(solidColor.toColorInt()) - stroke(strokeWidth, strokeColor.toColorInt()) - cornerRadius(radius.toFloat()) - } - - return convertToDrawable(builder.drawables[0]) -} - -fun convertToDrawable(shapeDrawable: ShapeDrawable): Drawable { - val drawable = GradientDrawable() - shapeDrawable.color?.let { drawable.setColor(it) } - shapeDrawable.cornerRadius?.let { drawable.cornerRadius = it } - shapeDrawable.strokeWidth?.let { drawable.setStroke(it, shapeDrawable.strokeColor ?: Color.BLACK) } - return drawable -} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/SpannableExt.kt b/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/SpannableExt.kt deleted file mode 100644 index bce4b9f..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/utils/ext/SpannableExt.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.shuwei.intelligent.shelves.utils.ext - -import android.text.SpannableStringBuilder -import android.text.Spanned - - -inline fun buildSpannableString(builderAction: SpannableStringBuilder.() -> Unit): SpannableStringBuilder { - return SpannableStringBuilder().apply(builderAction) -} - -fun SpannableStringBuilder.appendText(text: String, vararg spans: Any): SpannableStringBuilder { - val start = length - append(text) - spans.forEach { span -> - setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) - } - return this -} - -fun SpannableStringBuilder.withSpan(span: Any, block: SpannableStringBuilder.() -> Unit) { - val start = length - block() - setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) -} diff --git a/app/src/main/res/drawable-xxxhdpi/close.png b/app/src/main/res/drawable-xxxhdpi/close.png deleted file mode 100644 index 9aab2c6..0000000 Binary files a/app/src/main/res/drawable-xxxhdpi/close.png and /dev/null differ diff --git a/app/src/main/res/drawable/loading_spinner.xml b/app/src/main/res/drawable/loading_spinner.xml deleted file mode 100644 index 7ad8f85..0000000 --- a/app/src/main/res/drawable/loading_spinner.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ripple_effect.xml b/app/src/main/res/drawable/ripple_effect.xml deleted file mode 100644 index f176362..0000000 --- a/app/src/main/res/drawable/ripple_effect.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/shape_dialog_small.xml b/app/src/main/res/drawable/shape_dialog_small.xml deleted file mode 100644 index cdc268a..0000000 --- a/app/src/main/res/drawable/shape_dialog_small.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml deleted file mode 100644 index 51db701..0000000 --- a/app/src/main/res/layout/activity_home.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_shelf.xml b/app/src/main/res/layout/activity_shelf.xml deleted file mode 100644 index aca4625..0000000 --- a/app/src/main/res/layout/activity_shelf.xml +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_shelf_v2.xml b/app/src/main/res/layout/activity_shelf_v2.xml deleted file mode 100644 index 73311c8..0000000 --- a/app/src/main/res/layout/activity_shelf_v2.xml +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/list_item_shelf.xml b/app/src/main/res/layout/list_item_shelf.xml deleted file mode 100644 index d40843c..0000000 --- a/app/src/main/res/layout/list_item_shelf.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/local.properties b/local.properties index 0fe14f2..ad55396 100644 --- a/local.properties +++ b/local.properties @@ -4,5 +4,5 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Tue Jan 13 10:38:32 CST 2026 -sdk.dir=C\:\\Users\\HUAWEI\\AppData\\Local\\Android\\Sdk +#Fri Jun 26 09:17:18 CST 2026 +sdk.dir=D\:\\Android\\sdk