添加了图片拍照及识别逻辑
This commit is contained in:
@@ -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/"
|
||||
|
||||
@@ -116,6 +116,7 @@ object SensorScaleUtils {
|
||||
* 去皮置零
|
||||
*/
|
||||
fun tare() {
|
||||
Timber.d("tare isOpened = $isOpened")
|
||||
if (!isOpened) return
|
||||
mSensorScale?.tare {
|
||||
Timber.d("去皮置零操作成功")
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
@@ -213,52 +191,3 @@ fun CameraCaptureLayout(
|
||||
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 = "扫描"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<SearchGoodsInfo.Record>,
|
||||
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<Double?>(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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 <T> 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) }
|
||||
}
|
||||
|
||||
// ======================== 双击检测 ========================
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<PhotoCaptureHelper, () -> Unit> 返回工具类实例和拍照函数
|
||||
*/
|
||||
@Composable
|
||||
fun rememberPhotoCapture(
|
||||
cameraController: CameraController,
|
||||
onSuccess: (Uri) -> Unit = {},
|
||||
onError: (String) -> Unit = {}
|
||||
): Pair<PhotoCaptureHelper, () -> Unit> {
|
||||
val context = LocalContext.current
|
||||
val photoCaptureHelper = remember {
|
||||
PhotoCaptureHelper(
|
||||
context = context,
|
||||
cameraController = cameraController,
|
||||
onSuccess = onSuccess,
|
||||
onError = onError
|
||||
)
|
||||
}
|
||||
|
||||
return Pair(photoCaptureHelper) { photoCaptureHelper.takePhoto() }
|
||||
}
|
||||
@@ -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<Boolean> = _takePhotoState
|
||||
|
||||
// 称重结果
|
||||
private val _weightInfo = MutableStateFlow<Double>(0.0)
|
||||
val weightInfo: StateFlow<Double> = _weightInfo
|
||||
|
||||
// 搜索物品列表
|
||||
private val _searchListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
|
||||
val searchListItems: StateFlow<List<SearchGoodsInfo.Record>> = _searchListItems
|
||||
|
||||
// 识别列表
|
||||
private val _identityListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
|
||||
val identityListItems: StateFlow<List<SearchGoodsInfo.Record>> = _identityListItems
|
||||
|
||||
// 待收货的列表 用于识别时从中获取
|
||||
private val _receiptList = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
|
||||
|
||||
// 拍照uri
|
||||
private val _lastPhotoUri = MutableStateFlow<Uri?>(null)
|
||||
val lastPhotoUri: StateFlow<Uri?> = _lastPhotoUri
|
||||
|
||||
/**
|
||||
* 是否可以加载更多
|
||||
*/
|
||||
private val _canLoadMore = MutableStateFlow(true)
|
||||
val canLoadMore: StateFlow<Boolean> = _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<GoodsInfo>) {
|
||||
_receiptList.value = list.map { goods ->
|
||||
SearchGoodsInfo.Record(
|
||||
goodsId = goods.goodId,
|
||||
goodsName = goods.goodName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateIdentityList(list: List<SearchGoodsInfo.Record>) {
|
||||
_identityListItems.value = list
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取识别列表
|
||||
*/
|
||||
fun getIdentityList(photoUri: Uri) {
|
||||
Timber.d("getIdentityList")
|
||||
launchWithLoading {
|
||||
_searchListItems.value = emptyList<SearchGoodsInfo.Record>()
|
||||
// 有收货列表,则返回收货列表
|
||||
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<SearchGoodsInfo.Record>()
|
||||
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<SearchGoodsInfo.Record>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDictType() {
|
||||
Timber.d("获取所有字典列表")
|
||||
launchWithLoading {
|
||||
|
||||
@@ -21,32 +21,18 @@ 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
|
||||
|
||||
/**
|
||||
* 是否显示进度条
|
||||
*/
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<GoodsInfo?>(null)
|
||||
val selectedItem: StateFlow<GoodsInfo?> = _selectedItem
|
||||
|
||||
// 搜索物品列表
|
||||
private val _searchListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
|
||||
val searchListItems: StateFlow<List<SearchGoodsInfo.Record>> = _searchListItems
|
||||
|
||||
// 收货请求结果
|
||||
private val _receiptResult = MutableStateFlow<Boolean>(false)
|
||||
val receiptResult: StateFlow<Boolean> = _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,9 +242,7 @@ class ReceiptViewModel @Inject constructor(
|
||||
_amountUserInput.value = boolean
|
||||
}
|
||||
|
||||
fun startSensorScale() {
|
||||
Timber.d("开始称重")
|
||||
SensorScaleUtils.startScale(callback = { weight ->
|
||||
override fun handleSensorScale(weight: Double) {
|
||||
val currentItem = _selectedItem.value
|
||||
|
||||
currentItem?.let { info ->
|
||||
@@ -248,7 +251,7 @@ class ReceiptViewModel @Inject constructor(
|
||||
_selectedItem.value = info.copy(
|
||||
goodsWeight = weight.toSafeBigDecimal(),
|
||||
)
|
||||
return@startScale
|
||||
return
|
||||
}
|
||||
var consumeValue = currentItem.consumeValue?.toDouble() ?: 1.0
|
||||
var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0
|
||||
@@ -300,12 +303,6 @@ class ReceiptViewModel @Inject constructor(
|
||||
recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun stopSensorScale() {
|
||||
Timber.d("关闭称重")
|
||||
SensorScaleUtils.stopContinuousRead()
|
||||
}
|
||||
|
||||
fun partialReceipt(uploadInfo: UploadInfo) {
|
||||
|
||||
@@ -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<Boolean>(false)
|
||||
val showAddPurchaseUnitDialog: StateFlow<Boolean> = _showAddPurchaseUnitDialog
|
||||
|
||||
// 搜索物品列表
|
||||
private val _searchListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
|
||||
val searchListItems: StateFlow<List<SearchGoodsInfo.Record>> = _searchListItems
|
||||
|
||||
// 称重结果
|
||||
private val _weightInfo = MutableStateFlow<Double?>(0.0)
|
||||
val weightInfo: StateFlow<Double?> = _weightInfo
|
||||
|
||||
// 是否可以下拉
|
||||
private val _dropdownTextChange = MutableStateFlow<Boolean>(false)
|
||||
@@ -95,18 +87,6 @@ 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
|
||||
|
||||
/**
|
||||
* 更新全局仓库
|
||||
*/
|
||||
@@ -114,12 +94,7 @@ class SelfProcurementViewModel @Inject constructor(
|
||||
_globalWarehouse.value = dictType
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始称重
|
||||
*/
|
||||
fun startSensorScale() {
|
||||
Timber.d("开始称重")
|
||||
SensorScaleUtils.startScale(callback = { weight ->
|
||||
override fun handleSensorScale(weight: Double) {
|
||||
val currentItem = _selectedItem.value
|
||||
|
||||
currentItem?.let { info ->
|
||||
@@ -129,7 +104,7 @@ class SelfProcurementViewModel @Inject constructor(
|
||||
_selectedItem.value = info.copy(
|
||||
goodsWeight = weight.toSafeBigDecimal(),
|
||||
)
|
||||
return@startScale
|
||||
return
|
||||
}
|
||||
|
||||
// val selectUnitType = currentItem.selectUnitType
|
||||
@@ -178,12 +153,6 @@ class SelfProcurementViewModel @Inject constructor(
|
||||
goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString()
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun stopSensorScale() {
|
||||
Timber.d("关闭称重")
|
||||
SensorScaleUtils.stopContinuousRead()
|
||||
}
|
||||
|
||||
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<SearchGoodsInfo.Record>()
|
||||
}
|
||||
}
|
||||
override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
|
||||
updateSelectedItemWithSearch(goodsInfo)
|
||||
}
|
||||
|
||||
fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user