diff --git a/app/src/main/java/com/sw/inbound/di/NetworkModule.kt b/app/src/main/java/com/sw/inbound/di/NetworkModule.kt index 91cc2d0..55a86d0 100644 --- a/app/src/main/java/com/sw/inbound/di/NetworkModule.kt +++ b/app/src/main/java/com/sw/inbound/di/NetworkModule.kt @@ -20,7 +20,7 @@ import javax.inject.Singleton object NetworkModule { // private const val BASE_URL = "https://127.0.0.1" -// private const val BASE_URL = "https://vip.shuziweidao.com" +// private const val BASE_URL = "https://yyjk.shuziweidao.com/gateway/" private const val BASE_URL = "http://192.168.1.237:9002/" // private const val BASE_URL = "https://vip.shuziweidao.com/gateway/" diff --git a/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt b/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt index 316c395..8ddd194 100644 --- a/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt +++ b/app/src/main/java/com/sw/inbound/sdk/SensorScaleUtils.kt @@ -116,6 +116,7 @@ object SensorScaleUtils { * 去皮置零 */ fun tare() { + Timber.d("tare isOpened = $isOpened") if (!isOpened) return mSensorScale?.tare { Timber.d("去皮置零操作成功") diff --git a/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt b/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt index f17b42d..effe5c9 100644 --- a/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt +++ b/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt @@ -98,6 +98,16 @@ fun ReceiptProductScreen( } } + val lifecycleOwner = LocalLifecycleOwner.current + DisposableEffect(lifecycleOwner) { + Timber.d("开始传感器采集") + viewModel.startSensorScale() + onDispose { + Timber.d("停止传感器采集") + viewModel.stopSensorScale() + } + } + Column(modifier = modifier) { TopTitleBar() Box( @@ -241,6 +251,10 @@ fun TabScreen(viewModel: ReceiptViewModel) { val tabs = listOf("未确认(${purchaseUnadjustedList.size})", "已确认(${purchaseAdjustList.size})") + LaunchedEffect(purchaseUnadjustedList) { + viewModel.updateReceiptList(purchaseUnadjustedList) + } + Column( modifier = Modifier .background( @@ -493,7 +507,6 @@ private fun AdjustedRowInputLayout( @Composable fun ReceiptRightView(modifier: Modifier = Modifier, viewModel: ReceiptViewModel) { - val searchResultList by viewModel.searchListItems.collectAsState() val selectedItem by viewModel.selectedItem.collectAsState() Column( modifier = modifier @@ -507,7 +520,11 @@ fun ReceiptRightView(modifier: Modifier = Modifier, viewModel: ReceiptViewModel) ) { if (selectedItem == null) { Spacer(modifier = Modifier.height(30.dp)) - IdentityView(list = searchResultList, showSearchView = false, onOptionSelected = {}) + IdentityView( + showSearchView = false, + onOptionSelected = {}, + baseViewModel = viewModel + ) } else { ReceiptProductEditView(viewModel) } @@ -525,16 +542,6 @@ private fun ReceiptProductEditView( ) { val selectedItem by viewModel.selectedItem.collectAsState() val warehouseTypeList = GlobalData.warehouseTypeList - val lifecycleOwner = LocalLifecycleOwner.current - - DisposableEffect(lifecycleOwner) { - Timber.d("开始传感器采集") - viewModel.startSensorScale() - onDispose { - Timber.d("停止传感器采集") - viewModel.stopSensorScale() - } - } selectedItem?.let { Column( diff --git a/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt b/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt index a9d7745..8b6e87b 100644 --- a/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt +++ b/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt @@ -24,10 +24,6 @@ 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 @@ -256,13 +252,7 @@ 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() - + val selectedItem by viewModel.selectedItem.collectAsState() Column( modifier = Modifier .width(457.dp) @@ -275,19 +265,9 @@ fun ProductIdentification(viewModel: SelfProcurementViewModel) { .fillMaxWidth() ) { // 菜品识别 - IdentityView(list = searchResultList, showSearchView = true, onSearchClick = { - searchInfo = it - viewModel.searchGoodsInfoList(it) - }, onOptionSelected = { + IdentityView(showSearchView = true, onOptionSelected = { viewModel.updateSelectedItemWithSearch(it) - }, onLoadMore = { - Timber.d("加载更多 canLoadMore = $canLoadMore") - if (!canLoadMore) { - return@IdentityView - } - pageNum++ - viewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum) - }, isMoreLoading = isMoreLoading, canLoadMore = canLoadMore) + }, checkedItem = selectedItem, baseViewModel = viewModel) } Spacer(modifier = Modifier.height(10.dp)) Row( @@ -873,7 +853,9 @@ private fun SelfProductEditView( textColor = colorResource(R.color.green), borderColor = colorResource(R.color.green), onClick = { + viewModel.updateLastPhotoUri(null) viewModel.updateSelectedItem(null) + viewModel.updateIdentityList(emptyList()) }) CustomButton( modifier = Modifier diff --git a/app/src/main/java/com/sw/inbound/ui/weight/CameraCaptureLayout.kt b/app/src/main/java/com/sw/inbound/ui/weight/CameraCaptureLayout.kt index ad941d7..550f439 100644 --- a/app/src/main/java/com/sw/inbound/ui/weight/CameraCaptureLayout.kt +++ b/app/src/main/java/com/sw/inbound/ui/weight/CameraCaptureLayout.kt @@ -1,18 +1,12 @@ package com.sw.inbound.ui.weight import android.net.Uri -import android.view.ViewGroup -import android.widget.LinearLayout import android.widget.Toast -import androidx.camera.core.ImageCapture -import androidx.camera.core.ImageCaptureException import androidx.camera.view.CameraController import androidx.camera.view.LifecycleCameraController -import androidx.camera.view.PreviewView import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -21,7 +15,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -37,8 +30,6 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.content.ContextCompat import androidx.lifecycle.compose.LocalLifecycleOwner import coil.compose.AsyncImage import com.sw.inbound.GlobalData @@ -47,8 +38,8 @@ import com.sw.inbound.ext.dashedBorder import com.sw.inbound.ui.theme.AppTypography import com.sw.inbound.utils.FileUtils import com.sw.inbound.utils.ToastUtils +import com.sw.inbound.utils.rememberPhotoCapture import timber.log.Timber -import java.io.File /** * 相机预览 -默认不预览,支持拍照 @@ -72,6 +63,24 @@ fun CameraCaptureLayout( } } + // 创建拍照工具实例 + val (photoCaptureHelper, takePhoto) = rememberPhotoCapture( + cameraController = cameraController, + onSuccess = { savedUri -> + // 处理拍照成功的逻辑 + photoUri = savedUri + Timber.d("photoUri = $photoUri") + Toast.makeText(context, "图片已保存", Toast.LENGTH_SHORT).show() + showCamera = false + GlobalData.imageUri = photoUri + }, + onError = { error -> + // 处理拍照失败的逻辑 + Toast.makeText(context, error, Toast.LENGTH_SHORT).show() + GlobalData.imageUri = null + } + ) + Column( modifier = modifier .width(428.dp) @@ -165,38 +174,7 @@ fun CameraCaptureLayout( ToastUtils.showToast("请先开启图片预览") return@CustomButton } - val executor = ContextCompat.getMainExecutor(context) - val cacheDir = context.cacheDir - val photoFile = File.createTempFile( - "IMG_${System.currentTimeMillis()}", - ".jpg", - cacheDir - ) - - val cacheOutputOptions = - ImageCapture.OutputFileOptions.Builder(photoFile).build() - cameraController.takePicture( - cacheOutputOptions, - executor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { - val savedUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile) - photoUri = savedUri - Timber.d("photoUri = $photoUri") - Toast.makeText(context, "图片已保存", Toast.LENGTH_SHORT).show() - showCamera = false - GlobalData.imageUri = photoUri - } - - override fun onError(exception: ImageCaptureException) { - GlobalData.imageUri = null - Toast.makeText( - context, - "拍照失败: ${exception.message}", - Toast.LENGTH_SHORT - ).show() - } - }) + takePhoto() }, borderColor = colorResource(R.color.green), textColor = colorResource(R.color.white), @@ -212,53 +190,4 @@ fun CameraCaptureLayout( cameraController.bindToLifecycle(lifecycleOwner) onDispose { } } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun CameraContent(modifier: Modifier, cameraController: LifecycleCameraController) { - val lifecycleOwner = LocalLifecycleOwner.current - - Box( - modifier = modifier, - contentAlignment = Alignment.Center, - ) { - //在Compose中使用View系统中的PreviewView - AndroidView( - modifier = Modifier - .fillMaxSize(), - factory = { context -> - PreviewView(context).apply { - //设置布局宽度和高度占据全屏 - layoutParams = LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - //设置背景颜色 - setBackgroundColor(android.graphics.Color.BLACK) - //设置渲染的实现模式 - implementationMode = PreviewView.ImplementationMode.COMPATIBLE - //设置缩放方式 - scaleType = PreviewView.ScaleType.FILL_START - }.also { - it.controller = cameraController - cameraController.bindToLifecycle(lifecycleOwner) - } - }, - onReset = {}, - onRelease = { - Timber.d("cameraController.unbind()") - cameraController.unbind() - } - ) - - Image( - modifier = Modifier - .fillMaxSize() - .padding(30.dp), - painter = painterResource(R.mipmap.ic_scan), - contentDescription = "扫描" - ) - } - -} +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/ui/weight/CameraPreview.kt b/app/src/main/java/com/sw/inbound/ui/weight/CameraPreview.kt index b834d16..60c4a8b 100644 --- a/app/src/main/java/com/sw/inbound/ui/weight/CameraPreview.kt +++ b/app/src/main/java/com/sw/inbound/ui/weight/CameraPreview.kt @@ -1,5 +1,6 @@ package com.sw.inbound.ui.weight +import android.net.Uri import androidx.camera.view.LifecycleCameraController import androidx.camera.view.PreviewView import androidx.compose.foundation.Image @@ -11,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView +import coil.compose.AsyncImage import com.sw.inbound.R /** @@ -19,7 +21,8 @@ import com.sw.inbound.R @Composable fun CameraPreview( controller: LifecycleCameraController, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + photoUri: Uri? = null ) { Box(modifier = modifier) { AndroidView( @@ -31,6 +34,13 @@ fun CameraPreview( }, modifier = Modifier.fillMaxSize() ) + if (photoUri != null) { + AsyncImage( + modifier = Modifier.fillMaxSize(), + model = photoUri, + contentDescription = "照片", + ) + } Image( modifier = Modifier .fillMaxSize() diff --git a/app/src/main/java/com/sw/inbound/ui/weight/IdentityView.kt b/app/src/main/java/com/sw/inbound/ui/weight/IdentityView.kt index 1158c0b..6f58b26 100644 --- a/app/src/main/java/com/sw/inbound/ui/weight/IdentityView.kt +++ b/app/src/main/java/com/sw/inbound/ui/weight/IdentityView.kt @@ -1,5 +1,6 @@ package com.sw.inbound.ui.weight +import android.widget.Toast import androidx.camera.view.CameraController import androidx.camera.view.LifecycleCameraController import androidx.compose.foundation.layout.Column @@ -8,39 +9,103 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableDoubleStateOf +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.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.LocalLifecycleOwner import com.sw.inbound.ext.medium +import com.sw.inbound.model.request.PurchaseWarehouseParam import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.ui.theme.AppTypography +import com.sw.inbound.utils.InteractionUtils.Debouncer +import com.sw.inbound.utils.rememberPhotoCapture +import com.sw.inbound.viewmodel.BaseViewModel +import timber.log.Timber /** * 菜品识别组件 */ @Composable fun IdentityView( - list: List, showSearchView: Boolean = false, - onSearchClick: (String) -> Unit = {}, onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {}, - onLoadMore: (Int) -> Unit = {}, - isMoreLoading: Boolean = false, - canLoadMore: Boolean = true + checkedItem: PurchaseWarehouseParam? = null, + baseViewModel: BaseViewModel, ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current + val weightInfo by baseViewModel.weightInfo.collectAsState() + val identityList by baseViewModel.identityListItems.collectAsState() + val searchList by baseViewModel.searchListItems.collectAsState() +// var lastWeight by remember { mutableStateOf(null) } + var lastWeight by remember { mutableDoubleStateOf(0.0) } + val lastPhotoUri by baseViewModel.lastPhotoUri.collectAsState() + var pageNum by remember { mutableIntStateOf(1) } + val isMoreLoading by baseViewModel.isMoreLoading.collectAsState() + val canLoadMore by baseViewModel.canLoadMore.collectAsState() + var list = if (identityList.isNotEmpty()) { + identityList + } else { + searchList + } + val debouncer = remember { Debouncer(2000) } + // CameraX 控制器 val cameraController = remember { LifecycleCameraController(context).apply { - setEnabledUseCases(CameraController.IMAGE_CAPTURE) - bindToLifecycle(lifecycleOwner) + // 必须设置有效的用例 + setEnabledUseCases( + CameraController.IMAGE_CAPTURE or + CameraController.VIDEO_CAPTURE + ) } } + // 需要搜索的信息 + var searchInfo by remember { mutableStateOf("") } + // 创建拍照工具实例 + val (photoCaptureHelper, takePhoto) = rememberPhotoCapture( + cameraController = cameraController, + onSuccess = { savedUri -> + // 处理拍照成功的逻辑 + baseViewModel.updateLastPhotoUri(savedUri) + Timber.d("photoUri = $savedUri") + baseViewModel.getIdentityList(savedUri) + }, + onError = { error -> + // 处理拍照失败的逻辑 + Toast.makeText(context, error, Toast.LENGTH_SHORT).show() + baseViewModel.updateLastPhotoUri(null) + } + ) + + // 绑定生命周期 + DisposableEffect(lifecycleOwner) { + cameraController.bindToLifecycle(lifecycleOwner) + onDispose { /* 清理资源 */ } + } + + LaunchedEffect(weightInfo) { + Timber.d("LaunchedEffect weightInfo1 = $weightInfo, lastWeight = $lastWeight") + if (weightInfo - lastWeight > 1) { + Timber.d("weightInfo2 = $weightInfo") + debouncer.debounce { + takePhoto() + } + } + lastWeight = weightInfo + } + Column( modifier = Modifier .fillMaxSize(), @@ -50,11 +115,15 @@ fun IdentityView( modifier = Modifier .width(397.dp) .height(298.dp), - controller = cameraController + controller = cameraController, + photoUri = lastPhotoUri ) if (showSearchView) { Spacer(modifier = Modifier.height(30.dp)) - CustomSearchView(onSearchClick = onSearchClick) + CustomSearchView(onSearchClick = { + searchInfo = it + baseViewModel.searchGoodsInfoList(it) + }) } Spacer(modifier = Modifier.height(30.dp)) if (showSearchView) { @@ -63,7 +132,15 @@ fun IdentityView( .height(64.dp) .width(192.dp), options = list, onOptionSelected = onOptionSelected, - onLoadMore = onLoadMore, + onLoadMore = { + Timber.d("加载更多 canLoadMore = $canLoadMore") + if (!canLoadMore) { + return@SingleSelectButtonGroup + } + pageNum++ + baseViewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum) + }, + checkedItem = list.find { it.goodsId == checkedItem?.goodsId }, isMoreLoading = isMoreLoading, canLoadMore = canLoadMore ) diff --git a/app/src/main/java/com/sw/inbound/ui/weight/ReceiptUnadjustedListView.kt b/app/src/main/java/com/sw/inbound/ui/weight/ReceiptUnadjustedListView.kt index 837a19b..2e95add 100644 --- a/app/src/main/java/com/sw/inbound/ui/weight/ReceiptUnadjustedListView.kt +++ b/app/src/main/java/com/sw/inbound/ui/weight/ReceiptUnadjustedListView.kt @@ -96,7 +96,7 @@ fun ReceiptUnadjustedListView( key = { index, it -> it.id ?: index }) { index, it -> val checkedBg = - if (selectIndex == index) Gray_DCDCF0 else Color.Transparent + if (/*selectIndex == index ||*/ checkedItem?.id == it.id) Gray_DCDCF0 else Color.Transparent Row( modifier = Modifier .background(color = checkedBg) diff --git a/app/src/main/java/com/sw/inbound/ui/weight/SingleSelectButtonGroup.kt b/app/src/main/java/com/sw/inbound/ui/weight/SingleSelectButtonGroup.kt index 89f1edb..f21b744 100644 --- a/app/src/main/java/com/sw/inbound/ui/weight/SingleSelectButtonGroup.kt +++ b/app/src/main/java/com/sw/inbound/ui/weight/SingleSelectButtonGroup.kt @@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.padding 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.itemsIndexed import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text @@ -72,10 +72,11 @@ fun SingleSelectButtonGroup( unSelectedTextStyle: TextStyle = AppTypography.gray96a0aaTextStyle, onLoadMore: (Int) -> Unit = {}, isMoreLoading: Boolean = false, - canLoadMore: Boolean = true + canLoadMore: Boolean = true, + checkedItem: SearchGoodsInfo.Record? = null ) { val context = LocalContext.current - var selectedOption by remember { mutableStateOf(options.firstOrNull() ?: "") } + var selectedItem by remember { mutableStateOf(options.firstOrNull() ?: "") } val lazyGridState = rememberLazyGridState() var pageNum by remember { mutableIntStateOf(1) } @@ -109,26 +110,27 @@ fun SingleSelectButtonGroup( horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), verticalArrangement = Arrangement.spacedBy(verticalSpacing) ) { - items(items = options, key = { it.goodsId ?: it.goodsCode!! }) { option -> + itemsIndexed(items = options, key = { index, it -> index }) { index, item -> + val isChecked = item.goodsId == checkedItem?.goodsId Box( modifier = modifier .border( width = 2.dp, shape = RoundedCornerShape(10.dp), - color = if (option == selectedOption) selectedColor else unselectedColor, + color = if (isChecked) selectedColor else unselectedColor, ) .clip(RoundedCornerShape(10.dp)) - .background(if (option == selectedOption) selectedColor else Color.Transparent) + .background(if (isChecked) selectedColor else Color.Transparent) .clickable { - selectedOption = option - onOptionSelected(option) +// selectedItem = item + onOptionSelected(item) }, contentAlignment = Alignment.Center // .padding(vertical = 20.dp) ) { Text( - text = option.goodsNameStr, - style = if (option == selectedOption) AppTypography.BlueTextStyle else unSelectedTextStyle, + text = item.goodsNameStr, + style = if (isChecked) AppTypography.BlueTextStyle else unSelectedTextStyle, modifier = Modifier // .width(192.dp) // .height(64.dp) diff --git a/app/src/main/java/com/sw/inbound/utils/InteractionUtils.kt b/app/src/main/java/com/sw/inbound/utils/InteractionUtils.kt index 798aef1..953552f 100644 --- a/app/src/main/java/com/sw/inbound/utils/InteractionUtils.kt +++ b/app/src/main/java/com/sw/inbound/utils/InteractionUtils.kt @@ -63,65 +63,27 @@ object InteractionUtils { // ======================== 防抖处理 ======================== /** - * 防抖处理器 + * 防抖工具类 + * @param delayMillis 防抖延迟时间(毫秒) */ - class Debouncer( - private val delayMillis: Long = 300L, - private val coroutineScope: CoroutineScope - ) { - private var debounceJob: Job? = null + class Debouncer(private val delayMillis: Long) { + private var lastActionTime = 0L /** * 执行防抖操作 + * @param block 要执行的代码块 + * @return Boolean 是否实际执行了操作 */ - fun debounce(value: T, action: (T) -> Unit) { - debounceJob?.cancel() - debounceJob = coroutineScope.launch { - delay(delayMillis) - action(value) - } - } - } - - /** - * 记住防抖处理器 - */ - @Composable - fun rememberDebouncer( - delayMillis: Long = 300L, - coroutineScope: CoroutineScope = rememberCoroutineScope() - ): Debouncer { - return remember { Debouncer(delayMillis, coroutineScope) } - } - - // ======================== 节流处理 ======================== - - /** - * 节流处理器 - */ - class Throttler(private val timeoutMs: Long = 300L) { - private var lastRunTime: Long = 0 - - /** - * 执行节流操作 - */ - fun throttle(block: () -> Unit) { - val now = System.currentTimeMillis() - if (now - lastRunTime > timeoutMs) { - lastRunTime = now + fun debounce(block: () -> Unit): Boolean { + val currentTime = System.currentTimeMillis() + if (currentTime - lastActionTime >= delayMillis) { + lastActionTime = currentTime block() + return true } + return false } } - - /** - * 记住节流处理器 - */ - @Composable - fun rememberThrottler(timeoutMs: Long = 300L): Throttler { - return remember { Throttler(timeoutMs) } - } - // ======================== 双击检测 ======================== /** diff --git a/app/src/main/java/com/sw/inbound/utils/PhotoCaptureHelper.kt b/app/src/main/java/com/sw/inbound/utils/PhotoCaptureHelper.kt new file mode 100644 index 0000000..66308b1 --- /dev/null +++ b/app/src/main/java/com/sw/inbound/utils/PhotoCaptureHelper.kt @@ -0,0 +1,100 @@ +package com.sw.inbound.utils + +import android.content.Context +import android.net.Uri +import androidx.camera.core.ImageCapture +import androidx.camera.core.ImageCaptureException +import androidx.camera.view.CameraController +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.ContextCompat +import timber.log.Timber +import java.io.File + +/** + * 拍照工具类 + * @param context Context 上下文 + * @param cameraController CameraController 相机控制器 + * @param onSuccess (Uri) -> Unit 拍照成功回调 + * @param onError (String) -> Unit 拍照失败回调 + */ +class PhotoCaptureHelper( + private val context: Context, + private val cameraController: CameraController, + private val onSuccess: (Uri) -> Unit = {}, + private val onError: (String) -> Unit = {} +) { + + /** + * 拍照方法 + * @param fileNamePrefix 文件名前缀,默认为"IMG_" + * @param fileExtension 文件扩展名,默认为".jpg" + */ + fun takePhoto( + fileNamePrefix: String = "IMG_", + fileExtension: String = ".jpg" + ) { + Timber.d("开始拍照采集") + + try { + val executor = ContextCompat.getMainExecutor(context) + val cacheDir = context.cacheDir + val photoFile = File.createTempFile( + "${fileNamePrefix}${System.currentTimeMillis()}", + fileExtension, + cacheDir + ) + + val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build() + + cameraController.takePicture( + outputOptions, + executor, + object : ImageCapture.OnImageSavedCallback { + override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { + val photoUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile) + Timber.d("照片保存成功: $photoUri") + onSuccess(photoUri) + } + + override fun onError(exception: ImageCaptureException) { + val errorMsg = "拍照失败: ${exception.message}" + Timber.e(exception, errorMsg) + onError(errorMsg) + } + } + ) + } catch (e: Exception) { + val errorMsg = "创建临时文件失败: ${e.message}" + Timber.e(e, errorMsg) + onError(errorMsg) + } + } +} + +/** + * 用于Compose的拍照Hook + * @param cameraController CameraController 相机控制器 + * @param onSuccess (Uri) -> Unit 拍照成功回调 + * @param onError (String) -> Unit 拍照失败回调 + * @return Pair Unit> 返回工具类实例和拍照函数 + */ +@Composable +fun rememberPhotoCapture( + cameraController: CameraController, + onSuccess: (Uri) -> Unit = {}, + onError: (String) -> Unit = {} +): Pair Unit> { + val context = LocalContext.current + val photoCaptureHelper = remember { + PhotoCaptureHelper( + context = context, + cameraController = cameraController, + onSuccess = onSuccess, + onError = onError + ) + } + + return Pair(photoCaptureHelper) { photoCaptureHelper.takePhoto() } +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/viewmodel/BaseViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/BaseViewModel.kt index 8354599..511152d 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/BaseViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/BaseViewModel.kt @@ -1,13 +1,19 @@ package com.sw.inbound.viewmodel +import android.net.Uri import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.sw.inbound.GlobalData import com.sw.inbound.model.response.ApiResponse import com.sw.inbound.model.response.DictType +import com.sw.inbound.model.response.GoodsInfo +import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.network.LoadingState import com.sw.inbound.repository.RemoteRepository +import com.sw.inbound.sdk.SensorScaleUtils import com.sw.inbound.utils.ToastUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import retrofit2.HttpException import timber.log.Timber @@ -16,6 +22,40 @@ import java.io.IOException abstract class BaseViewModel( private val repository: RemoteRepository ) : ViewModel() { + // 需要拍照 + private val _takePhotoState = MutableStateFlow(false) + val takePhotoState: StateFlow = _takePhotoState + + // 称重结果 + private val _weightInfo = MutableStateFlow(0.0) + val weightInfo: StateFlow = _weightInfo + + // 搜索物品列表 + private val _searchListItems = MutableStateFlow>(emptyList()) + val searchListItems: StateFlow> = _searchListItems + + // 识别列表 + private val _identityListItems = MutableStateFlow>(emptyList()) + val identityListItems: StateFlow> = _identityListItems + + // 待收货的列表 用于识别时从中获取 + private val _receiptList = MutableStateFlow>(emptyList()) + + // 拍照uri + private val _lastPhotoUri = MutableStateFlow(null) + val lastPhotoUri: StateFlow = _lastPhotoUri + + /** + * 是否可以加载更多 + */ + private val _canLoadMore = MutableStateFlow(true) + val canLoadMore: StateFlow = _canLoadMore + + /** + * 是否显示进度条 + */ + private val _isMoreLoading = MutableStateFlow(false) + val isMoreLoading = _isMoreLoading /** * 带进度条的请求 @@ -67,6 +107,107 @@ abstract class BaseViewModel( ToastUtils.showToast(message) } + fun startSensorScale() { + Timber.d("开始称重") + SensorScaleUtils.startScale(callback = { weight -> + _weightInfo.value = weight + handleSensorScale(weight) + }) + } + + fun stopSensorScale() { + Timber.d("关闭称重") + SensorScaleUtils.stopContinuousRead() + } + + abstract fun handleSensorScale(weight: Double) + + fun updateCanLoadMore(canLoad: Boolean) { + _canLoadMore.value = canLoad + } + + fun updateLastPhotoUri(photoUri: Uri?) { + _lastPhotoUri.value = photoUri + } + + fun updateReceiptList(list: List) { + _receiptList.value = list.map { goods -> + SearchGoodsInfo.Record( + goodsId = goods.goodId, + goodsName = goods.goodName + ) + } + } + + fun updateIdentityList(list: List) { + _identityListItems.value = list + } + + /** + * 获取识别列表 + */ + fun getIdentityList(photoUri: Uri) { + Timber.d("getIdentityList") + launchWithLoading { + _searchListItems.value = emptyList() + // 有收货列表,则返回收货列表 + if (_receiptList.value.isNotEmpty()) { + _identityListItems.value = _receiptList.value + if (_identityListItems.value.isNotEmpty()) { + handleIdentityItem(_identityListItems.value[0]) + } + } else { + val response = repository.searchGoodsInfoList("", 1, 10) + if (parseResponse(response)) { + _identityListItems.value = response.result?.records ?: emptyList() + if (_identityListItems.value.isNotEmpty()) { + handleIdentityItem(_identityListItems.value[0]) + } + } + } + } + } + + /** + * 处理识别后要选中的值 + */ + open fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {} + + fun updateMoreLoading(moreLoading: Boolean) { + _isMoreLoading.value = moreLoading + } + + /** + * 搜索物品 + */ + fun searchGoodsInfoList( + goodsName: String, + pageNo: Int = 1, + pageSize: Int = 10 + ) { + launch { + if (pageNo > 1) { + _isMoreLoading.value = true + } + _identityListItems.value = emptyList() + val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize) + _isMoreLoading.value = false + if (parseResponse(response)) { + val data = response.result + 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() + } + } + } + fun getDictType() { Timber.d("获取所有字典列表") launchWithLoading { diff --git a/app/src/main/java/com/sw/inbound/viewmodel/PurchaseOrderViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/PurchaseOrderViewModel.kt index a826daf..8a5cdfc 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/PurchaseOrderViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/PurchaseOrderViewModel.kt @@ -21,32 +21,18 @@ class PurchaseOrderViewModel @Inject constructor( */ private val _supplierList = MutableStateFlow>(emptyList()) val supplierList: StateFlow> = _supplierList - - /** - * 是否可以加载更多 - */ - private val _canLoadMore = MutableStateFlow(true) - val canLoadMore: StateFlow = _canLoadMore - - /** - * 是否显示进度条 - */ - private val _isMoreLoading = MutableStateFlow(false) - val isMoreLoading = _isMoreLoading - - /** * 获取采购订单-供应商列表 */ fun getOrderList(pageNum: Int = 1, pageSize: Int = 5) { if (pageNum != 1) { launch { - _isMoreLoading.value = true + updateMoreLoading(true) val response = repository.getReceiveList(pageNum, pageSize) - _isMoreLoading.value = false + updateMoreLoading(false) if (parseResponse(response)) { response.result?.records?.let { - _canLoadMore.value = it.size >= pageSize + updateCanLoadMore(it.size >= pageSize) Timber.d("加载更多 canLoadMore =${it.size >= pageSize}") _supplierList.value = _supplierList.value + it } @@ -63,5 +49,9 @@ class PurchaseOrderViewModel @Inject constructor( } } } + + override fun handleSensorScale(weight: Double) { + + } } diff --git a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt index ba16d1a..fbba48c 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt @@ -10,7 +10,6 @@ import com.sw.inbound.model.response.GoodsInfo import com.sw.inbound.model.response.PurchaseInfo import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.repository.RemoteRepository -import com.sw.inbound.sdk.SensorScaleUtils import com.sw.inbound.utils.ToastUtils import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -63,10 +62,6 @@ class ReceiptViewModel @Inject constructor( private val _selectedItem = MutableStateFlow(null) val selectedItem: StateFlow = _selectedItem - // 搜索物品列表 - private val _searchListItems = MutableStateFlow>(emptyList()) - val searchListItems: StateFlow> = _searchListItems - // 收货请求结果 private val _receiptResult = MutableStateFlow(false) val receiptResult: StateFlow = _receiptResult @@ -109,6 +104,16 @@ class ReceiptViewModel @Inject constructor( } } + override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) { + val firstItem = unadjustedOrders.value.find { order -> + order.goodId == goodsInfo.goodsId + } + updateLastPhotoUri(null) + updateIdentityList(emptyList()) + _selectedItem.value = firstItem +// updateSelectedItemWithSwitch(firstItem) + } + /** * 更新选中的item */ @@ -237,75 +242,67 @@ class ReceiptViewModel @Inject constructor( _amountUserInput.value = boolean } - fun startSensorScale() { - Timber.d("开始称重") - SensorScaleUtils.startScale(callback = { weight -> - val currentItem = _selectedItem.value - - currentItem?.let { info -> - // 用户输入数量后不再通过重量反算 - if (_countUserInput.value) { - _selectedItem.value = info.copy( - goodsWeight = weight.toSafeBigDecimal(), - ) - return@startScale - } - var consumeValue = currentItem.consumeValue?.toDouble() ?: 1.0 - var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0 - if (consumeValue == 0.0) { - consumeValue = 1.0 - } - if (purchaseValue == 0.0) { - purchaseValue = 1.0 - } - val count = - weight * 1000 / consumeValue / purchaseValue - val finalCount = count.toSafeFloat(currentItem.unitName) - Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") - // 计算单价 - val finalPrice = when { - finalCount == 0f -> { - 0f - } - - _amountUserInput.value && !_priceUserInput.value -> { - info.recPriceExItem!!.div(finalCount).toSafeFloat() - } - - else -> 0f - } - // 计算金额 - val finalAmount = when { - finalCount == 0f -> { - 0f - } - - _priceUserInput.value && !_amountUserInput.value -> { - finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat() - } - - else -> 0f - } + override fun handleSensorScale(weight: Double) { + val currentItem = _selectedItem.value + currentItem?.let { info -> + // 用户输入数量后不再通过重量反算 + if (_countUserInput.value) { _selectedItem.value = info.copy( goodsWeight = weight.toSafeBigDecimal(), - // 收货数量 - receivedNumTemp = finalCount.toFormattedString(), - receivedNum = finalCount, - // 单价 - newRecUnitPriceTaxIn = if (_priceUserInput.value) info.newRecUnitPriceTaxIn else finalPrice, - newRecUnitPriceTaxInTemp = if (_priceUserInput.value) info.newRecUnitPriceTaxInTemp else finalPrice.toFormattedString(), - // 金额 - recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount, - recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(), ) + return } - }) - } + var consumeValue = currentItem.consumeValue?.toDouble() ?: 1.0 + var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0 + if (consumeValue == 0.0) { + consumeValue = 1.0 + } + if (purchaseValue == 0.0) { + purchaseValue = 1.0 + } + val count = + weight * 1000 / consumeValue / purchaseValue + val finalCount = count.toSafeFloat(currentItem.unitName) + Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") + // 计算单价 + val finalPrice = when { + finalCount == 0f -> { + 0f + } - fun stopSensorScale() { - Timber.d("关闭称重") - SensorScaleUtils.stopContinuousRead() + _amountUserInput.value && !_priceUserInput.value -> { + info.recPriceExItem!!.div(finalCount).toSafeFloat() + } + + else -> 0f + } + // 计算金额 + val finalAmount = when { + finalCount == 0f -> { + 0f + } + + _priceUserInput.value && !_amountUserInput.value -> { + finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat() + } + + else -> 0f + } + + _selectedItem.value = info.copy( + goodsWeight = weight.toSafeBigDecimal(), + // 收货数量 + receivedNumTemp = finalCount.toFormattedString(), + receivedNum = finalCount, + // 单价 + newRecUnitPriceTaxIn = if (_priceUserInput.value) info.newRecUnitPriceTaxIn else finalPrice, + newRecUnitPriceTaxInTemp = if (_priceUserInput.value) info.newRecUnitPriceTaxInTemp else finalPrice.toFormattedString(), + // 金额 + recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount, + recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(), + ) + } } fun partialReceipt(uploadInfo: UploadInfo) { diff --git a/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt index b246eea..d1aeac6 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt @@ -11,7 +11,6 @@ import com.sw.inbound.model.request.PurchaseWarehouseParam import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.repository.RemoteRepository -import com.sw.inbound.sdk.SensorScaleUtils import com.sw.inbound.utils.ContextUtils import com.sw.inbound.utils.FileUtils import com.sw.inbound.utils.ToastUtils @@ -68,13 +67,6 @@ class SelfProcurementViewModel @Inject constructor( private val _showAddPurchaseUnitDialog = MutableStateFlow(false) val showAddPurchaseUnitDialog: StateFlow = _showAddPurchaseUnitDialog - // 搜索物品列表 - private val _searchListItems = MutableStateFlow>(emptyList()) - val searchListItems: StateFlow> = _searchListItems - - // 称重结果 - private val _weightInfo = MutableStateFlow(0.0) - val weightInfo: StateFlow = _weightInfo // 是否可以下拉 private val _dropdownTextChange = MutableStateFlow(false) @@ -95,18 +87,6 @@ class SelfProcurementViewModel @Inject constructor( */ private val _amountUserInput = MutableStateFlow(false) - /** - * 是否可以加载更多 - */ - private val _canLoadMore = MutableStateFlow(true) - val canLoadMore: StateFlow = _canLoadMore - - /** - * 是否显示进度条 - */ - private val _isMoreLoading = MutableStateFlow(false) - val isMoreLoading = _isMoreLoading - /** * 更新全局仓库 */ @@ -114,76 +94,65 @@ class SelfProcurementViewModel @Inject constructor( _globalWarehouse.value = dictType } - /** - * 开始称重 - */ - fun startSensorScale() { - Timber.d("开始称重") - SensorScaleUtils.startScale(callback = { weight -> - val currentItem = _selectedItem.value + override fun handleSensorScale(weight: Double) { + val currentItem = _selectedItem.value - currentItem?.let { info -> - val selectUnitType = currentItem.selectUnitType - // 用户输入数量后不再通过重量反算 - if (_countUserInput.value || selectUnitType == null) { - _selectedItem.value = info.copy( - goodsWeight = weight.toSafeBigDecimal(), - ) - return@startScale - } + currentItem?.let { info -> + val selectUnitType = currentItem.selectUnitType + // 用户输入数量后不再通过重量反算 + if (_countUserInput.value || selectUnitType == null) { + _selectedItem.value = info.copy( + goodsWeight = weight.toSafeBigDecimal(), + ) + return + } // val selectUnitType = currentItem.selectUnitType // if (selectUnitType == null) return@startScale - var consumeValue = selectUnitType.consumeValue?.toDouble() ?: 1.0 - var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0 - if (consumeValue == 0.0) { - consumeValue = 1.0 - } - if (purchaseValue == 0.0) { - purchaseValue = 1.0 - } - val count = - weight * 1000 / consumeValue / purchaseValue - val finalCount = count.toSafeDouble(currentItem.unitName) - Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") - - Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ") - // 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入 - val finalPrice = - if (finalCount == 0.0) { - 0.0 - } else if (_amountUserInput.value && !_priceUserInput.value) { - info.goodsPrice.div(finalCount).toSafeDouble() - } else 0.0 - - // 计算金额 单价不为空,不是数量输入 也不是金额输入 - val finalAmount = - if (finalCount == 0.0) { - 0.0 - } else if (_priceUserInput.value && !_amountUserInput.value) { - finalCount.times(info.goodsUnitPrice).toSafeDouble() - } else 0.0 - Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ") - _selectedItem.value = info.copy( - goodsWeight = weight.toSafeBigDecimal(), - // 数量 - goodsCountTemp = finalCount.toFormattedString(), - goodsCount = finalCount, - // 单价 - goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice, - goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(), - // 金额 - goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount, - goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString() - ) + var consumeValue = selectUnitType.consumeValue?.toDouble() ?: 1.0 + var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0 + if (consumeValue == 0.0) { + consumeValue = 1.0 } - }) - } + if (purchaseValue == 0.0) { + purchaseValue = 1.0 + } + val count = + weight * 1000 / consumeValue / purchaseValue + val finalCount = count.toSafeDouble(currentItem.unitName) + Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") - fun stopSensorScale() { - Timber.d("关闭称重") - SensorScaleUtils.stopContinuousRead() + Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ") + // 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入 + val finalPrice = + if (finalCount == 0.0) { + 0.0 + } else if (_amountUserInput.value && !_priceUserInput.value) { + info.goodsPrice.div(finalCount).toSafeDouble() + } else 0.0 + + // 计算金额 单价不为空,不是数量输入 也不是金额输入 + val finalAmount = + if (finalCount == 0.0) { + 0.0 + } else if (_priceUserInput.value && !_amountUserInput.value) { + finalCount.times(info.goodsUnitPrice).toSafeDouble() + } else 0.0 + Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ") + _selectedItem.value = info.copy( + goodsWeight = weight.toSafeBigDecimal(), + // 数量 + goodsCountTemp = finalCount.toFormattedString(), + goodsCount = finalCount, + // 单价 + goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice, + goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(), + // 金额 + goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount, + goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString() + ) + } } fun updateAddProductDialog(show: Boolean) { @@ -194,6 +163,7 @@ class SelfProcurementViewModel @Inject constructor( } fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) { +// updateLastPhotoUri(null) if (purchaseOrder != null) { if (purchaseOrder.goodsCount != 0.0) { if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入 @@ -277,34 +247,8 @@ class SelfProcurementViewModel @Inject constructor( _purchaseList.value = emptyList() } - /** - * 搜索物品 - */ - fun searchGoodsInfoList( - goodsName: String, - pageNo: Int = 1, - pageSize: Int = 10 - ) { - launch { - if (pageNo > 1) { - _isMoreLoading.value = true - } - val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize) - _isMoreLoading.value = false - if (parseResponse(response)) { - val data = response.result - 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() - } - } + override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) { + updateSelectedItemWithSearch(goodsInfo) } fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) { diff --git a/app/src/main/java/com/sw/inbound/viewmodel/UserViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/UserViewModel.kt index f31b68d..39c6eef 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/UserViewModel.kt @@ -64,4 +64,8 @@ class UserViewModel @Inject constructor( SPUtil.getInstance().remove(GlobalKey.KEY_USER_INFO) SPUtil.getInstance().remove(GlobalKey.KEY_TOKEN) } + + override fun handleSensorScale(weight: Double) { + + } } \ No newline at end of file