添加了供应商列表和搜索物品分页功能
This commit is contained in:
@@ -3,6 +3,7 @@ package com.sw.inbound.ext
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.round
|
||||
|
||||
fun Float.toFormattedString(decimalPlaces: Int = 2): String {
|
||||
return when (this) {
|
||||
@@ -32,12 +33,12 @@ fun Double.toSafeBigDecimal(): BigDecimal {
|
||||
*/
|
||||
private fun Double.roundToDouble(decimalPlaces: Int): Double {
|
||||
val factor = 10.0.pow(decimalPlaces)
|
||||
return kotlin.math.round(this * factor) / factor
|
||||
return round(this * factor) / factor
|
||||
}
|
||||
|
||||
private fun Float.roundToDouble(decimalPlaces: Int): Double {
|
||||
val factor = 10.0.pow(decimalPlaces)
|
||||
return kotlin.math.round(this * factor) / factor
|
||||
return round(this * factor) / factor
|
||||
}
|
||||
|
||||
fun Float?.toSafeString(unitName: String?): String {
|
||||
@@ -101,4 +102,4 @@ fun BigDecimal.toFormattedString(): String {
|
||||
|
||||
fun Int.toFormattedString(): String {
|
||||
return this.toString()
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,21 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -50,6 +56,9 @@ import com.sw.inbound.ui.theme.AppTypography.grayTextStyle
|
||||
import com.sw.inbound.ui.weight.BottomActionBar
|
||||
import com.sw.inbound.ui.weight.TopTitleBar
|
||||
import com.sw.inbound.viewmodel.PurchaseOrderViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
|
||||
@Preview(
|
||||
widthDp = 1920,
|
||||
@@ -66,11 +75,32 @@ fun PurchaseOrderScreen(
|
||||
viewModel: PurchaseOrderViewModel = hiltViewModel<PurchaseOrderViewModel>()
|
||||
) {
|
||||
val products by viewModel.supplierList.collectAsState()
|
||||
val lazyListState = rememberLazyListState()
|
||||
val canLoadMore by viewModel.canLoadMore.collectAsState()
|
||||
val isMoreLoading by viewModel.isMoreLoading.collectAsState()
|
||||
var pageNum by remember { mutableIntStateOf(1) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.getOrderList()
|
||||
}
|
||||
|
||||
// 检测是否滚动到底部
|
||||
LaunchedEffect(lazyListState) {
|
||||
snapshotFlow { lazyListState.layoutInfo }
|
||||
.map { layoutInfo ->
|
||||
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
lastVisibleItem?.index == layoutInfo.totalItemsCount - 1
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.collect { reachedEnd ->
|
||||
Timber.d("加载更多 reachedEnd = $reachedEnd, isMoreLoading = $isMoreLoading, canLoadMore = $canLoadMore")
|
||||
if (reachedEnd && !isMoreLoading && canLoadMore) {
|
||||
pageNum++
|
||||
viewModel.getOrderList(pageNum = pageNum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
TopTitleBar()
|
||||
Box(
|
||||
@@ -101,6 +131,7 @@ fun PurchaseOrderScreen(
|
||||
LazyRow(
|
||||
modifier = modifier
|
||||
.padding(10.dp),
|
||||
state = lazyListState,
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(30.dp)
|
||||
) {
|
||||
@@ -114,6 +145,19 @@ fun PurchaseOrderScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (isMoreLoading) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillParentMaxHeight()
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -34,6 +38,7 @@ import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -238,6 +243,11 @@ fun ContentRightView(
|
||||
@Composable
|
||||
fun ProductIdentification(viewModel: SelfProcurementViewModel) {
|
||||
val searchResultList by viewModel.searchListItems.collectAsState()
|
||||
// 需要搜索的信息
|
||||
var searchInfo by remember { mutableStateOf("") }
|
||||
var pageNum by remember { mutableIntStateOf(1) }
|
||||
val isMoreLoading by viewModel.isMoreLoading.collectAsState()
|
||||
val canLoadMore by viewModel.canLoadMore.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -252,10 +262,18 @@ fun ProductIdentification(viewModel: SelfProcurementViewModel) {
|
||||
) {
|
||||
// 菜品识别
|
||||
IdentityView(list = searchResultList, showSearchView = true, onSearchClick = {
|
||||
searchInfo = it
|
||||
viewModel.searchGoodsInfoList(it)
|
||||
}, onOptionSelected = {
|
||||
viewModel.updateSelectedItemWithSearch(it)
|
||||
})
|
||||
}, onLoadMore = {
|
||||
Timber.d("加载更多 canLoadMore = $canLoadMore")
|
||||
if (!canLoadMore) {
|
||||
return@IdentityView
|
||||
}
|
||||
pageNum++
|
||||
viewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum)
|
||||
}, isMoreLoading = isMoreLoading, canLoadMore = canLoadMore)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Row(
|
||||
@@ -615,12 +633,16 @@ private fun SelfProductEditView(
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
text = selectedItem!!.goodsNameStr,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = AppTypography.black141428TextStyle.bold().withSize(30.sp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
RowInputLayout(
|
||||
label = "仓库",
|
||||
@@ -757,7 +779,7 @@ private fun SelfProductEditView(
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(30.dp),
|
||||
modifier = Modifier
|
||||
|
||||
@@ -27,6 +27,9 @@ fun IdentityView(
|
||||
showSearchView: Boolean = false,
|
||||
onSearchClick: (String) -> Unit = {},
|
||||
onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {},
|
||||
onLoadMore: (Int) -> Unit = {},
|
||||
isMoreLoading: Boolean = false,
|
||||
canLoadMore: Boolean = true
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
@@ -59,7 +62,10 @@ fun IdentityView(
|
||||
modifier = Modifier
|
||||
.height(64.dp)
|
||||
.width(192.dp), options = list,
|
||||
onOptionSelected = onOptionSelected
|
||||
onOptionSelected = onOptionSelected,
|
||||
onLoadMore = onLoadMore,
|
||||
isMoreLoading = isMoreLoading,
|
||||
canLoadMore = canLoadMore
|
||||
)
|
||||
} else {
|
||||
SingleSelectButtonGroup(
|
||||
|
||||
@@ -11,13 +11,17 @@ import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -31,6 +35,9 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@@ -62,16 +69,43 @@ fun SingleSelectButtonGroup(
|
||||
onOptionSelected: (SearchGoodsInfo.Record) -> Unit,
|
||||
horizontalSpacing: Dp = 13.dp,
|
||||
verticalSpacing: Dp = 13.dp,
|
||||
unSelectedTextStyle: TextStyle = AppTypography.gray96a0aaTextStyle
|
||||
unSelectedTextStyle: TextStyle = AppTypography.gray96a0aaTextStyle,
|
||||
onLoadMore: (Int) -> Unit = {},
|
||||
isMoreLoading: Boolean = false,
|
||||
canLoadMore: Boolean = true
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var selectedOption by remember { mutableStateOf(options.firstOrNull() ?: "") }
|
||||
|
||||
val lazyGridState = rememberLazyGridState()
|
||||
// val canLoadMore by viewModel.canLoadMore.collectAsState()
|
||||
// val isMoreLoading by viewModel.isMoreLoading.collectAsState()
|
||||
var pageNum by remember { mutableIntStateOf(1) }
|
||||
|
||||
// 检测是否滚动到底部
|
||||
LaunchedEffect(lazyGridState) {
|
||||
snapshotFlow { lazyGridState.layoutInfo }
|
||||
.map { layoutInfo ->
|
||||
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
lastVisibleItem?.index == layoutInfo.totalItemsCount - 1
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.collect { reachedEnd ->
|
||||
Timber.d("加载更多 reachedEnd = $reachedEnd, isMoreLoading = $isMoreLoading, canLoadMore = $canLoadMore")
|
||||
if (reachedEnd && !isMoreLoading && canLoadMore) {
|
||||
pageNum++
|
||||
onLoadMore(pageNum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定义颜色
|
||||
val selectedColor = Color(0xFFD9E3F9)
|
||||
val unselectedColor = Color(0xFFDCDCF0)
|
||||
|
||||
|
||||
LazyVerticalGrid(
|
||||
state = lazyGridState,
|
||||
columns = GridCells.Fixed(2), // 每行2列
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
|
||||
@@ -16,6 +16,10 @@ import java.io.IOException
|
||||
abstract class BaseViewModel(
|
||||
private val repository: RemoteRepository
|
||||
) : ViewModel() {
|
||||
|
||||
/**
|
||||
* 带进度条的请求
|
||||
*/
|
||||
protected fun launchWithLoading(block: suspend () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
@@ -30,6 +34,9 @@ abstract class BaseViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不带进度条的请求
|
||||
*/
|
||||
protected fun launch(block: suspend () -> Unit) {
|
||||
viewModelScope.launch() {
|
||||
try {
|
||||
|
||||
@@ -21,17 +21,45 @@ class PurchaseOrderViewModel @Inject constructor(
|
||||
private val _supplierList = MutableStateFlow<List<SupplierInfo?>>(emptyList())
|
||||
val supplierList: StateFlow<List<SupplierInfo?>> = _supplierList
|
||||
|
||||
/**
|
||||
* 是否可以加载更多
|
||||
*/
|
||||
private val _canLoadMore = MutableStateFlow(true)
|
||||
val canLoadMore: StateFlow<Boolean> = _canLoadMore
|
||||
|
||||
fun getOrderList(pageNum: Int = 0, pageSize: Int = 20) {
|
||||
launchWithLoading {
|
||||
val response = repository.getReceiveList(pageNum, pageSize)
|
||||
if (response.isSuccess()) {
|
||||
response.data?.records?.let {
|
||||
_supplierList.value = it
|
||||
/**
|
||||
* 是否显示进度条
|
||||
*/
|
||||
private val _isMoreLoading = MutableStateFlow(false)
|
||||
val isMoreLoading = _isMoreLoading
|
||||
|
||||
|
||||
/**
|
||||
* 获取采购订单-供应商列表
|
||||
*/
|
||||
fun getOrderList(pageNum: Int = 1, pageSize: Int = 5) {
|
||||
if (pageNum != 1) {
|
||||
launch {
|
||||
_isMoreLoading.value = true
|
||||
val response = repository.getReceiveList(pageNum, pageSize)
|
||||
_isMoreLoading.value = false
|
||||
if (response.isSuccess()) {
|
||||
response.data?.records?.let {
|
||||
_canLoadMore.value = it.size >= pageSize
|
||||
_supplierList.value = _supplierList.value + it
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
launchWithLoading {
|
||||
val response = repository.getReceiveList(pageNum, pageSize)
|
||||
if (response.isSuccess()) {
|
||||
response.data?.records?.let {
|
||||
_supplierList.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,18 @@ class SelfProcurementViewModel @Inject constructor(
|
||||
*/
|
||||
private val _amountUserInput = MutableStateFlow<Boolean>(false)
|
||||
|
||||
/**
|
||||
* 是否可以加载更多
|
||||
*/
|
||||
private val _canLoadMore = MutableStateFlow(true)
|
||||
val canLoadMore: StateFlow<Boolean> = _canLoadMore
|
||||
|
||||
/**
|
||||
* 是否显示进度条
|
||||
*/
|
||||
private val _isMoreLoading = MutableStateFlow(false)
|
||||
val isMoreLoading = _isMoreLoading
|
||||
|
||||
/**
|
||||
* 更新全局仓库
|
||||
*/
|
||||
@@ -237,15 +249,24 @@ class SelfProcurementViewModel @Inject constructor(
|
||||
|
||||
fun searchGoodsInfoList(
|
||||
goodsName: String,
|
||||
pageNo: Int = 0,
|
||||
pageNo: Int = 1,
|
||||
pageSize: Int = 10
|
||||
) {
|
||||
launch {
|
||||
if (pageNo > 1) {
|
||||
_isMoreLoading.value = true
|
||||
}
|
||||
val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize)
|
||||
_isMoreLoading.value = false
|
||||
if (response.isSuccess()) {
|
||||
val data = response.data
|
||||
if (data != null) {
|
||||
_searchListItems.value = data.records ?: emptyList<SearchGoodsInfo.Record>()
|
||||
data?.records?.let {
|
||||
_canLoadMore.value = data.records.size >= pageSize
|
||||
if (pageNo > 1) {
|
||||
_searchListItems.value = _searchListItems.value + data.records
|
||||
} else {
|
||||
_searchListItems.value = data.records
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_searchListItems.value = emptyList<SearchGoodsInfo.Record>()
|
||||
|
||||
Reference in New Issue
Block a user