添加了供应商列表和搜索物品分页功能

This commit is contained in:
zxj
2025-07-11 15:53:17 +08:00
parent 7459bd205a
commit f1283ba11e
8 changed files with 182 additions and 19 deletions
@@ -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>()