fix(scale): 优化秤数据同步及格口显示顺序
- 增加秤号到列表索引的映射,提升心跳回调数据定位效率 - 调整重量数据处理逻辑,减少索引查找开销 - 按设备物理布局重排格口列表,解决多列设备显示错乱问题 - 定义同步间隔和首次同步延迟常量,统一定时任务配置 - 调整重量上报心跳间隔为1秒,提升秤数据实时性 - 清空列表时同步清理秤号映射,防止脏数据影响展示 - 优化空格口清理逻辑,改用映射位置快速更新对应项
This commit is contained in:
@@ -76,8 +76,8 @@ object ScaleManager {
|
|||||||
/** 当前设备激活码,非空时收到激活请求自动应答 */
|
/** 当前设备激活码,非空时收到激活请求自动应答 */
|
||||||
private var activateCode: String = ""
|
private var activateCode: String = ""
|
||||||
|
|
||||||
/** 心跳应答:心跳上报间隔(秒),默认5秒 */
|
/** 心跳应答:心跳上报间隔(秒),默认1秒,保证重量更新实时性 */
|
||||||
var heartbeatInterval: Int = 5
|
var heartbeatInterval: Int = 1
|
||||||
|
|
||||||
/** 心跳应答:开锁后未开门自动落锁时间(秒),默认6秒 */
|
/** 心跳应答:开锁后未开门自动落锁时间(秒),默认6秒 */
|
||||||
var lockTimeout: Int = 6
|
var lockTimeout: Int = 6
|
||||||
|
|||||||
@@ -46,12 +46,20 @@ import org.greenrobot.eventbus.ThreadMode
|
|||||||
|
|
||||||
class HomeV3Activity : BaseActivity() {
|
class HomeV3Activity : BaseActivity() {
|
||||||
|
|
||||||
companion object {}
|
companion object {
|
||||||
|
/** 重量同步后台间隔(秒) */
|
||||||
|
private const val SYNC_INTERVAL_SECONDS = 30L
|
||||||
|
/** 首次同步延迟(秒) */
|
||||||
|
private const val SYNC_INITIAL_DELAY_SECONDS = 10L
|
||||||
|
}
|
||||||
|
|
||||||
override val enableRightStatusMenu: Boolean = true
|
override val enableRightStatusMenu: Boolean = true
|
||||||
|
|
||||||
private val list: MutableList<SlotModel> = mutableListOf()
|
private val list: MutableList<SlotModel> = mutableListOf()
|
||||||
|
|
||||||
|
/** 秤号(slotNo 数字部分)→ list 索引 的快速查找表,心跳回调中 O(1) 定位 */
|
||||||
|
private val scaleIndexToPosition = mutableMapOf<Int, Int>()
|
||||||
|
|
||||||
private var shelfIndex = 0
|
private var shelfIndex = 0
|
||||||
|
|
||||||
private fun isNeedOpenLock() = App.deviceId == "4787e213-90ab-3e32-88e0-ac271a937751"
|
private fun isNeedOpenLock() = App.deviceId == "4787e213-90ab-3e32-88e0-ac271a937751"
|
||||||
@@ -72,15 +80,12 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
.init(activateCode = ProtocolConstants.ACTIVE_MAP[App.deviceId] ?: "")
|
.init(activateCode = ProtocolConstants.ACTIVE_MAP[App.deviceId] ?: "")
|
||||||
.onHeartbeat { _, data ->
|
.onHeartbeat { _, data ->
|
||||||
data.weights.forEach { weight ->
|
data.weights.forEach { weight ->
|
||||||
val shelfNo = weight.index
|
val pos = scaleIndexToPosition[weight.index] ?: return@forEach
|
||||||
val pos = list.indexOfFirst {
|
val model = list[pos]
|
||||||
it.slotNo.filter { c -> c.isDigit() }.toIntOrNull() == shelfNo
|
|
||||||
}
|
|
||||||
val model = list.getOrNull(pos) ?: return@forEach
|
|
||||||
model.weight = weight.grams / 1000.0
|
model.weight = weight.grams / 1000.0
|
||||||
shelfAdapter.notifyItemChanged(pos)
|
shelfAdapter.notifyItemChanged(pos)
|
||||||
log("getWeightInfo: slotNo=${model.slotNo}, realWeight=${weight.grams}, temp=${data.temperature}")
|
log("getWeightInfo: slotNo=${model.slotNo}, realWeight=${weight.grams}, temp=${data.temperature}")
|
||||||
EventBus.getDefault().post(SendWeightEvent(shelfNo, weight.grams))
|
EventBus.getDefault().post(SendWeightEvent(weight.index, weight.grams))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onTempReport { frame ->
|
.onTempReport { frame ->
|
||||||
@@ -158,7 +163,8 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
log("updateUI: slots=${slots.size}, rows=$rows, columns=$columns")
|
log("updateUI: slots=${slots.size}, rows=$rows, columns=$columns")
|
||||||
|
|
||||||
list.clear()
|
list.clear()
|
||||||
list.addAll(slots)
|
list.addAll(reorderSlotsByDeviceLayout(slots, columns, rows))
|
||||||
|
buildScaleIndexMap()
|
||||||
|
|
||||||
val displayMetrics = resources.displayMetrics
|
val displayMetrics = resources.displayMetrics
|
||||||
// 减去 RecyclerView + item 自身的 margin
|
// 减去 RecyclerView + item 自身的 margin
|
||||||
@@ -172,6 +178,64 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按设备物理布局重排格口列表。
|
||||||
|
*
|
||||||
|
* API 返回的 slots 按 slotNo 升序排列。FlexboxLayoutManager(FlexDirection.COLUMN)
|
||||||
|
* 按列填充(先填满第一列 5 行,再换第二列),3 列设备需要重排才能正确显示:
|
||||||
|
*
|
||||||
|
* 期望显示: 列填充需要的列表序:
|
||||||
|
* [1] [6] [7] [1, 2, 3, 4, 5, ← 第1列
|
||||||
|
* [2] [8] [9] 6, 8, 10, 12, 14, ← 第2列
|
||||||
|
* [3][10] [11] 7, 9, 11, 13, 15] ← 第3列
|
||||||
|
* [4][12] [13]
|
||||||
|
* [5][14] [15]
|
||||||
|
*
|
||||||
|
* 2 列设备 API 原序 [1..10] 列填充后恰好正确,无需重排。
|
||||||
|
*
|
||||||
|
* @param slots API 返回的格口列表(按 slotNo 升序)
|
||||||
|
* @param columns 列数(API horizontalRows)
|
||||||
|
* @param rows 行数(API verticalCount)
|
||||||
|
*/
|
||||||
|
private fun reorderSlotsByDeviceLayout(
|
||||||
|
slots: List<SlotModel>,
|
||||||
|
columns: Int,
|
||||||
|
rows: Int
|
||||||
|
): List<SlotModel> {
|
||||||
|
// 2 列及以下无需重排,API 原序列填充后恰好正确
|
||||||
|
if (columns <= 2) return ArrayList(slots)
|
||||||
|
|
||||||
|
// 按 slotNo 数字部分建立查找表
|
||||||
|
val slotMap = HashMap<Int, SlotModel>(slots.size)
|
||||||
|
for (slot in slots) {
|
||||||
|
val num = slot.slotNo.filter { it.isDigit() }.toIntOrNull() ?: continue
|
||||||
|
slotMap[num] = slot
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = ArrayList<SlotModel>(slots.size)
|
||||||
|
for (displayCol in 0 until columns) {
|
||||||
|
for (displayRow in 0 until rows) {
|
||||||
|
// 物理布局 → FlexDirection.COLUMN 列填充所需的列表位置
|
||||||
|
val slotNo = when (displayCol) {
|
||||||
|
0 -> displayRow + 1 // 左列: 1,2,3,4,5
|
||||||
|
1 -> rows + 1 + displayRow * 2 // 中列: 6,8,10,12,14
|
||||||
|
else -> rows + 2 + displayRow * 2 // 右列: 7,9,11,13,15
|
||||||
|
}
|
||||||
|
slotMap[slotNo]?.let { result.add(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 预建秤号→列表索引映射表,供心跳回调 O(1) 查找 */
|
||||||
|
private fun buildScaleIndexMap() {
|
||||||
|
scaleIndexToPosition.clear()
|
||||||
|
list.forEachIndexed { pos, model ->
|
||||||
|
val scaleNo = model.slotNo.filter { it.isDigit() }.toIntOrNull() ?: return@forEachIndexed
|
||||||
|
scaleIndexToPosition[scaleNo] = pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showError(message: String) {
|
private fun showError(message: String) {
|
||||||
Loading.dismiss()
|
Loading.dismiss()
|
||||||
toast(message)
|
toast(message)
|
||||||
@@ -302,6 +366,7 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun loadEmptyView() {
|
private fun loadEmptyView() {
|
||||||
list.clear()
|
list.clear()
|
||||||
|
scaleIndexToPosition.clear()
|
||||||
shelfAdapter.notifyDataSetChanged()
|
shelfAdapter.notifyDataSetChanged()
|
||||||
binding.include?.let {
|
binding.include?.let {
|
||||||
it.root.visible()
|
it.root.visible()
|
||||||
@@ -319,10 +384,7 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun clearEmptyShelf(event: ClearShelfEvent) {
|
fun clearEmptyShelf(event: ClearShelfEvent) {
|
||||||
val index = list.indexOfFirst {
|
val index = scaleIndexToPosition[event.shelfNo] ?: return
|
||||||
it.slotNo?.filter { c -> c.isDigit() }?.toIntOrNull() == event.shelfNo
|
|
||||||
}
|
|
||||||
if (index < 0) return
|
|
||||||
list[index] = list[index].copy(materName = "")
|
list[index] = list[index].copy(materName = "")
|
||||||
shelfAdapter.notifyItemChanged(index)
|
shelfAdapter.notifyItemChanged(index)
|
||||||
}
|
}
|
||||||
@@ -332,7 +394,10 @@ class HomeV3Activity : BaseActivity() {
|
|||||||
|
|
||||||
private fun saveGoodsTask() {
|
private fun saveGoodsTask() {
|
||||||
saveTaskJob =
|
saveTaskJob =
|
||||||
taskExecutor.startIntervalTaskWithInitialDelay(10 * 1000L, 1 * 60 * 1000L) {
|
taskExecutor.startIntervalTaskWithInitialDelay(
|
||||||
|
SYNC_INITIAL_DELAY_SECONDS * 1000L,
|
||||||
|
SYNC_INTERVAL_SECONDS * 1000L
|
||||||
|
) {
|
||||||
syncShelfGoodsToServer()
|
syncShelfGoodsToServer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user