|
@@ -9,6 +9,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|
|
import androidx.compose.foundation.lazy.itemsIndexed
|
|
|
import androidx.compose.material.icons.Icons
|
|
|
import androidx.compose.material.icons.filled.ArrowBack
|
|
|
+import androidx.compose.material.icons.filled.Clear
|
|
|
import androidx.compose.material.icons.filled.Delete
|
|
|
import androidx.compose.material3.*
|
|
|
import androidx.compose.ui.graphics.Color
|
|
@@ -29,48 +30,49 @@ import androidx.compose.ui.Alignment
|
|
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
|
import com.example.pda.model.ContainerItemDetail
|
|
|
import kotlinx.coroutines.launch
|
|
|
-
|
|
|
-// 托盘屏幕,用于托盘扫描和物料信息显示
|
|
|
+// 托盘详情界面 - 修复关键问题
|
|
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
|
@Composable
|
|
|
-
|
|
|
fun ContainerItems(
|
|
|
- container: String, // 新增参数
|
|
|
+ container: String,
|
|
|
onBack: () -> Unit,
|
|
|
+ navToOutOperation: (String) -> Unit
|
|
|
) {
|
|
|
val viewModel: InventoryViewModel = viewModel()
|
|
|
- val uiState = viewModel.uiState.collectAsState()
|
|
|
+ val uiState by viewModel.uiState.collectAsState()
|
|
|
+ val containerDetails by viewModel.containerItemsDetails.collectAsState()
|
|
|
+
|
|
|
val snackbarHostState = remember { SnackbarHostState() }
|
|
|
val coroutineScope = rememberCoroutineScope()
|
|
|
- val inputIp = remember { mutableStateOf("") }
|
|
|
- val containerState = remember { mutableStateOf(container) }
|
|
|
- var showInput by remember { mutableStateOf(container.isBlank()) }
|
|
|
|
|
|
+ val containerState = remember(container) { mutableStateOf(container) }
|
|
|
+ var showInput by remember {
|
|
|
+ mutableStateOf(container.isBlank())
|
|
|
+ }
|
|
|
+ val inputIp = remember { mutableStateOf("") }
|
|
|
|
|
|
- // 自动加载数据(当传入的 container 非空时)
|
|
|
+ // 自动加载数据
|
|
|
LaunchedEffect(container) {
|
|
|
if (container.isNotBlank()) {
|
|
|
viewModel.getContainerDetail(container)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 根据 viewModel 状态显示 Snackbar(保持不变)
|
|
|
- LaunchedEffect(uiState.value) {
|
|
|
- when (val currentState = uiState.value) {
|
|
|
+ // 状态处理
|
|
|
+ LaunchedEffect(uiState) {
|
|
|
+ when (val currentState = uiState) {
|
|
|
is InventoryViewModel.UiState.Success -> {
|
|
|
coroutineScope.launch {
|
|
|
snackbarHostState.showSnackbar(currentState.message)
|
|
|
viewModel.resetState()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
is InventoryViewModel.UiState.Error -> {
|
|
|
coroutineScope.launch {
|
|
|
snackbarHostState.showSnackbar("错误:${currentState.message}")
|
|
|
viewModel.resetState()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
else -> {}
|
|
|
}
|
|
|
}
|
|
@@ -96,6 +98,26 @@ fun ContainerItems(
|
|
|
Text("信泰PDA—托盘详情")
|
|
|
}
|
|
|
},
|
|
|
+ actions = {
|
|
|
+ // 出库操作按钮
|
|
|
+ IconButton(
|
|
|
+ onClick = {
|
|
|
+ if (containerDetails.isNotEmpty()) {
|
|
|
+ navToOutOperation(containerState.value)
|
|
|
+ } else {
|
|
|
+ coroutineScope.launch {
|
|
|
+ snackbarHostState.showSnackbar("没有可出库的批次")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ) {
|
|
|
+ Icon(
|
|
|
+ painter = painterResource(id = R.drawable.ic_out),
|
|
|
+ contentDescription = "出库操作",
|
|
|
+ tint = Color.White
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
colors = TopAppBarDefaults.topAppBarColors(
|
|
|
containerColor = Color(0xFFBCD0C5),
|
|
|
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
|
@@ -108,118 +130,175 @@ fun ContainerItems(
|
|
|
modifier = Modifier
|
|
|
.padding(innerPadding)
|
|
|
.fillMaxSize()
|
|
|
- .padding(24.dp)
|
|
|
+ .padding(16.dp)
|
|
|
) {
|
|
|
-
|
|
|
- // 输入区域(仅当需要时显示)
|
|
|
+ // 输入区域
|
|
|
if (showInput || containerState.value.isBlank()) {
|
|
|
Row(
|
|
|
modifier = Modifier
|
|
|
.fillMaxWidth()
|
|
|
- .padding(8.dp),
|
|
|
+ .padding(bottom = 16.dp),
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- TextField(
|
|
|
+ OutlinedTextField(
|
|
|
value = inputIp.value,
|
|
|
onValueChange = { inputIp.value = it },
|
|
|
label = { Text("请输入托盘编码") },
|
|
|
+ modifier = Modifier.weight(1f),
|
|
|
+ trailingIcon = {
|
|
|
+ IconButton(
|
|
|
+ onClick = {
|
|
|
+ if (inputIp.value.isNotBlank()) {
|
|
|
+ containerState.value = inputIp.value
|
|
|
+ viewModel.getContainerDetail(containerState.value)
|
|
|
+ showInput = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ) {
|
|
|
+ Icon(Icons.Default.Search, "搜索")
|
|
|
+ }
|
|
|
+ }
|
|
|
)
|
|
|
- IconButton(
|
|
|
- onClick = {
|
|
|
- containerState.value = inputIp.value
|
|
|
- viewModel.getContainerDetail(containerState.value)
|
|
|
- showInput = false
|
|
|
- },
|
|
|
- ) {
|
|
|
- Icon(Icons.Default.Search, "确定")
|
|
|
- }
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 托盘编码显示与删除按钮
|
|
|
+ // 托盘编码显示与操作
|
|
|
Row(
|
|
|
modifier = Modifier
|
|
|
.fillMaxWidth()
|
|
|
- .padding(8.dp),
|
|
|
+ .padding(bottom = 16.dp),
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
Text(
|
|
|
text = "托盘编码:${containerState.value}",
|
|
|
+ style = MaterialTheme.typography.titleLarge,
|
|
|
modifier = Modifier.weight(1f)
|
|
|
)
|
|
|
- IconButton(
|
|
|
- onClick = {
|
|
|
- containerState.value = ""
|
|
|
- showInput = true
|
|
|
- },
|
|
|
- ) {
|
|
|
- Icon(Icons.Default.Delete, "删除")
|
|
|
+ if (!showInput) {
|
|
|
+ IconButton(
|
|
|
+ onClick = {
|
|
|
+ containerState.value = ""
|
|
|
+ showInput = true
|
|
|
+ },
|
|
|
+ ) {
|
|
|
+ Icon(Icons.Default.Clear, "清除托盘编码")
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 显示批次数据
|
|
|
- ContainerItemList(data = viewModel.containerItemsDetails.collectAsState().value)
|
|
|
+ ContainerItemList(data = containerDetails)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+// 批次列表显示 - 优化版
|
|
|
@Composable
|
|
|
private fun ContainerItemList(data: List<ContainerItemDetail>) {
|
|
|
- LazyColumn(modifier = Modifier.fillMaxSize()) {
|
|
|
- itemsIndexed(data) { index, item ->
|
|
|
- Card(
|
|
|
- modifier = Modifier
|
|
|
- .fillMaxWidth()
|
|
|
- .padding(2.dp),
|
|
|
- elevation = CardDefaults.cardElevation(2.dp)
|
|
|
+ if (data.isEmpty()) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxSize()
|
|
|
+ .padding(16.dp),
|
|
|
+ contentAlignment = Alignment.Center
|
|
|
+ ) {
|
|
|
+ Text("没有找到批次数据", style = MaterialTheme.typography.titleMedium)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ LazyColumn(
|
|
|
+ modifier = Modifier.fillMaxSize(),
|
|
|
+ verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
|
+ ) {
|
|
|
+ itemsIndexed(data) { index, item ->
|
|
|
+ OutOperationItemCard(
|
|
|
+ index = index,
|
|
|
+ item = item
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 批次项卡片 - 提取为独立组件
|
|
|
+@Composable
|
|
|
+private fun OutOperationItemCard(
|
|
|
+ index: Int,
|
|
|
+ item: ContainerItemDetail
|
|
|
+) {
|
|
|
+ val remaining = item.goods_in_qty - item.goods_out_qty
|
|
|
+
|
|
|
+ Card(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ elevation = CardDefaults.cardElevation(4.dp)
|
|
|
+ ) {
|
|
|
+ Column(
|
|
|
+ modifier = Modifier.padding(16.dp)
|
|
|
+ ) {
|
|
|
+ Row(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ horizontalArrangement = Arrangement.SpaceBetween
|
|
|
) {
|
|
|
- Column(modifier = Modifier.padding(4.dp)) {
|
|
|
- Text(
|
|
|
- "id:${index + 1}",
|
|
|
- style = MaterialTheme.typography.bodySmall
|
|
|
- )
|
|
|
- Spacer(Modifier.height(1.dp))
|
|
|
- Divider(thickness = 0.8.dp)
|
|
|
- Text(
|
|
|
- "物料批次:${item.batch_number}",
|
|
|
- style = MaterialTheme.typography.titleMedium
|
|
|
- )
|
|
|
- Spacer(Modifier.height(1.dp))
|
|
|
- Divider(thickness = 1.2.dp)
|
|
|
- Row(
|
|
|
- horizontalArrangement = Arrangement.SpaceBetween,
|
|
|
- modifier = Modifier.fillMaxWidth()
|
|
|
- ) {
|
|
|
- Text(
|
|
|
- "物料编码:${item.goods_code}",
|
|
|
- style = MaterialTheme.typography.bodyMedium
|
|
|
- )
|
|
|
- Text(
|
|
|
- "物料名称:${item.goods_desc}",
|
|
|
- style = MaterialTheme.typography.bodyMedium
|
|
|
- )
|
|
|
- }
|
|
|
- Spacer(Modifier.height(1.dp))
|
|
|
- Divider(thickness = 1.2.dp)
|
|
|
- Row(
|
|
|
- horizontalArrangement = Arrangement.SpaceBetween,
|
|
|
- modifier = Modifier.fillMaxWidth()
|
|
|
- ) {
|
|
|
- Text(
|
|
|
- "组盘数量:${item.goods_in_qty}",
|
|
|
+ Text("#${index + 1}", style = MaterialTheme.typography.labelMedium)
|
|
|
+ Text("items_: ${item.id}", style = MaterialTheme.typography.labelMedium)
|
|
|
+ }
|
|
|
|
|
|
- )
|
|
|
- Text(
|
|
|
- "已出库数量:${item.goods_out_qty}",
|
|
|
+ Spacer(Modifier.height(6.dp))
|
|
|
+ Divider()
|
|
|
+ Spacer(Modifier.height(6.dp))
|
|
|
|
|
|
- )
|
|
|
- }
|
|
|
+ Text(
|
|
|
+ "批次: ${item.batch_number}",
|
|
|
+ style = MaterialTheme.typography.titleMedium
|
|
|
+ )
|
|
|
|
|
|
+ Spacer(Modifier.height(6.dp))
|
|
|
+
|
|
|
+ Row(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ horizontalArrangement = Arrangement.SpaceBetween
|
|
|
+ ) {
|
|
|
+ Column {
|
|
|
+ Text("物料编码", style = MaterialTheme.typography.labelSmall)
|
|
|
+ Text(item.goods_code, style = MaterialTheme.typography.bodyMedium)
|
|
|
+ }
|
|
|
+ Column {
|
|
|
+ Text("物料名称", style = MaterialTheme.typography.labelSmall)
|
|
|
+ Text(item.goods_desc, style = MaterialTheme.typography.bodyMedium)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ Spacer(Modifier.height(2.dp))
|
|
|
+ Divider(thickness = 1.5.dp)
|
|
|
+
|
|
|
+
|
|
|
+ // 数量信息网格
|
|
|
+ Row(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ horizontalArrangement = Arrangement.SpaceAround
|
|
|
+ ) {
|
|
|
+ QuantityInfoCard(title = "组盘", value = item.goods_in_qty.toString(), backgroundColor = Color(0xFFE3F2FD))
|
|
|
+ QuantityInfoCard(title = "出库", value = item.goods_out_qty.toString(), backgroundColor = Color(0xFFFFF8E1))
|
|
|
+ QuantityInfoCard(title = "剩余", value = remaining.toString(), backgroundColor = Color(0xFFE8F5E9))
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 数量信息卡片组件
|
|
|
+@Composable
|
|
|
+private fun QuantityInfoCard(title: String, value: String, backgroundColor: Color) {
|
|
|
+ Card(
|
|
|
+ modifier = Modifier.size(60.dp),
|
|
|
+ colors = CardDefaults.cardColors(containerColor = backgroundColor)
|
|
|
+ ) {
|
|
|
+ Column(
|
|
|
+ modifier = Modifier.padding(8.dp),
|
|
|
+ horizontalAlignment = Alignment.CenterHorizontally,
|
|
|
+ verticalArrangement = Arrangement.Center
|
|
|
+ ) {
|
|
|
+ Text(title, style = MaterialTheme.typography.labelMedium)
|
|
|
+ Spacer(Modifier.height(2.dp))
|
|
|
+ Text(value, style = MaterialTheme.typography.titleMedium)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|