添加了注释,完善了参数校验及空值处理

This commit is contained in:
zxj
2025-07-09 15:29:52 +08:00
parent de80a26c2c
commit 6cf7b4fb9b
42 changed files with 584 additions and 334 deletions
@@ -20,26 +20,6 @@ object GlobalData {
var warehouseTypeList: List<DictType> = arrayListOf()
var supplierTypeList: List<DictType> = arrayListOf()
var unitTypeList: List<DictType> = arrayListOf()
fun getStorageType(id: Int): String {
return storageTypeList.find { it.id == id }?.value ?: "默认"
}
fun getGoodsType(id: Int): String {
return goodsTypeList.find { it.id == id }?.value ?: "-"
}
fun getWarehouseType(id: Int): String {
return warehouseTypeList.find { it.id == id }?.value ?: "-"
}
fun getSupplierType(id: Int): String {
return supplierTypeList.find { it.id == id }?.value ?: "-"
}
fun getUnitType(id: Int): String {
return unitTypeList.find { it.id == id }?.value ?: "-"
}
}
/**
@@ -6,6 +6,7 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.ui.AppScreen
import com.sw.inbound.utils.ThreadUtils
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@@ -22,6 +23,7 @@ class MainActivity : ComponentActivity() {
override fun onDestroy() {
SensorScaleUtils.closeScale()
ThreadUtils.release()
super.onDestroy()
}
}
@@ -33,26 +33,35 @@ private fun Double.roundToDouble(decimalPlaces: Int): Double {
return kotlin.math.round(this * factor) / factor
}
fun Double?.toSafeString(unitName: String?): String {
if (this == null || this == 0.0) return ""
val decimalPlaces = getDecimalPlaces(unitName)
return "%.${decimalPlaces}f".format(this)
}
fun Double?.toSafeDouble(unitName: String?): Double {
if (this == null || this == 0.0) return 0.0
val decimalPlaces = when (unitName) {
"", "", "公斤", "" -> 2
else -> 0
}
val decimalPlaces = getDecimalPlaces(unitName)
return roundToDouble(decimalPlaces)
}
fun Double?.toSafeFloat(unitName: String?): Float {
if (this == null || this == 0.0) return 0f
val decimalPlaces = getDecimalPlaces(unitName)
return roundToDouble(decimalPlaces).toFloat()
}
/**
* 通过单位判断小数
*/
private fun getDecimalPlaces(unitName: String?): Int {
val decimalPlaces = when (unitName) {
"", "", "公斤", "" -> 2
else -> 0
}
return roundToDouble(decimalPlaces).toFloat()
return decimalPlaces
}
fun BigDecimal.toFormattedString(): String {
@@ -1,4 +0,0 @@
package com.sw.inbound.model.exception
class ApiException {
}
@@ -1,4 +0,0 @@
package com.sw.inbound.model.exception
class NetException(val code: Int, override val message: String) : Exception(message)
@@ -3,6 +3,7 @@ package com.sw.inbound.model.request
import android.os.Parcelable
import com.sw.inbound.GlobalData
import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeString
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.SearchGoodsInfo.Record.UnitVo
import kotlinx.parcelize.Parcelize
@@ -25,6 +26,9 @@ data class PurchaseWarehouseParam(
* 入库数量
*/
var goodsCount: Double = 0.0,
// 用于数量输入框显示
var goodsCountTemp: String = "",
/**
* 入库单价
*/
@@ -122,7 +126,7 @@ data class PurchaseWarehouseParam(
if (goodsCount == null || goodsCount == 0.0) {
return ""
}
return goodsCount.toFormattedString()
return goodsCount.toSafeString(unitName)
}
val goodsUnitPriceStr: String
@@ -3,6 +3,9 @@ package com.sw.inbound.model.response
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/**
* 字典类型 如仓库列表 物品类型 存储方式等
*/
@Parcelize
data class DictType(
val id: Int,
@@ -75,12 +75,15 @@ data class GoodsInfo(
// 收货数量 收货入参
var receivedNum: Float? = null,
// 收货数量显示
var receivedNumTemp: String = "",
// 重量 收货入参
var goodsWeight: BigDecimal? = null,
// 已调整
var isAdjusted: Boolean = false,
// 选中物品的可选单位
var unitList: List<UnitVo> = emptyList<UnitVo>()
) : Parcelable, BaseBean() {
@@ -173,9 +176,25 @@ data class GoodsInfo(
return warehouseName!!
}
fun hasNull(): Boolean {
return goodName == null || warehouseId == null ||
purchaseUnitId == null || recUnitPriceTaxIn == null
|| receiveCount == null || recPriceExItem == null
fun hasNullField(): String? {
if (warehouseId == null) {
return "请选择仓库"
}
if (receivedNum == null || receivedNum == 0f) {
return "请输入收货数量或进行称重"
}
if (recUnitPriceTaxIn == null || recUnitPriceTaxIn == 0f) {
return "请输入收货单价"
}
if (recPriceExItem == null || recPriceExItem == 0f) {
return "请输入收货金额"
}
if (goodsWeight == null || goodsWeight == BigDecimal(0)) {
return "请放入要称重的物品"
}
return null
// return goodName == null || warehouseId == null ||
// purchaseUnitId == null || recUnitPriceTaxIn == null
// || receiveCount == null || recPriceExItem == null
}
}
@@ -5,6 +5,9 @@ import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
/**
* 物品类型
*/
@Parcelize
data class GoodsType(
@SerializedName("allType")
@@ -1,5 +1,8 @@
package com.sw.inbound.model.response
/**
* 采购详情
*/
data class PurchaseInfo(
/**
* 单据id
@@ -12,21 +15,22 @@ data class PurchaseInfo(
/**
* 供应商名称
*/
var supplierName: String = "",
var supplierName: String? = "",
/**
* 采购单号
*/
var purCode: String = "",
var purCode: String? = "",
/**
* 收货单号
*/
var receiveCode: String = "",
var receiveCode: String? = "",
/**
* 物品信息
*/
var receiveGoodsInfoList: List<GoodsInfo> = emptyList<GoodsInfo>()
) : BaseBean() {
var receiveGoodsInfoList: List<GoodsInfo> = emptyList<GoodsInfo>(),
// 自用
var warehouseName: String = "选择仓库"
) : BaseBean() {
}
@@ -5,6 +5,9 @@ import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
/**
* 搜索商品结果
*/
@Parcelize
data class SearchGoodsInfo(
@SerializedName("current")
@@ -60,7 +63,7 @@ data class SearchGoodsInfo(
* 采购单位列表
*/
@SerializedName("unitVoList")
val unitVoList: List<UnitVo>? = listOf(),
val unitVoList: List<UnitVo>? = null,
@SerializedName("zjmCode")
val zjmCode: String? = ""
) : Parcelable {
@@ -5,6 +5,9 @@ import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
/**
* 采购信息
*/
@Parcelize
data class SupplierInfo(
@SerializedName("createTime")
@@ -1,29 +0,0 @@
package com.sw.inbound.network.interceptor
import com.google.gson.JsonParseException
import com.sw.inbound.model.exception.NetException
import okhttp3.Interceptor
import okhttp3.Response
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
class ErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
try {
val response = chain.proceed(chain.request())
if (!response.isSuccessful) {
throw NetException(response.code, "HTTP Error ${response.code}")
}
return response
} catch (e: Exception) {
Timber.e(e)
throw when (e) {
is IOException -> NetException(-1, "Network error: ${e.message}")
is JsonParseException -> NetException(-2, "Data parse error")
is HttpException -> NetException(-3, e.message ?: "未知错误")
else -> NetException(-100, e.message ?: "未知错误")
}
}
}
}
@@ -6,6 +6,9 @@ import com.sw.inbound.utils.SPUtil
import okhttp3.Interceptor
import okhttp3.Response
/**
* 请求拦截器
*/
class RequestInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
@@ -1,6 +1,7 @@
package com.sw.inbound.sdk
import com.sw.inbound.utils.ThreadUtils
import com.sw.inbound.utils.ToastUtils
import com.wabon.wbintelligenthardwaresdk.api.SensorScale
import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult
import kotlinx.coroutines.delay
@@ -48,6 +49,10 @@ object SensorScaleUtils {
})
}
/**
* 开启称重
* @param autoScale 是否开启自动读取
*/
fun startScale(autoScale: Boolean = true, callback: Callback?) {
if (isOpened) {
startContinuousRead(callback = callback)
@@ -70,15 +75,21 @@ object SensorScaleUtils {
}
}
/**
* 开启自动读取重量
*/
fun startContinuousRead(callback: Callback?) {
this.callback = callback
Timber.d("isOpened = $isOpened")
Timber.d("开启自动读取 = $isOpened")
if (!isOpened) {
return
}
mSensorScale?.startContinuousRead()
}
/**
* 手动读取重量
*/
fun readWeight(callback: Callback?) {
this.callback = callback
Timber.d("isOpened = $isOpened")
@@ -88,6 +99,30 @@ object SensorScaleUtils {
mSensorScale?.readWeight()
}
/**
* 零位标定
*/
fun zero() {
if (!isOpened) return
mSensorScale?.zero {
Timber.d("零位标定操作成功")
}
}
/**
* 去皮置零
*/
fun tare() {
if (!isOpened) return
mSensorScale?.tare {
Timber.d("去皮置零操作成功")
ToastUtils.showToast("去皮置零操作成功")
}
}
/**
* 停止自动读取重量
*/
fun stopContinuousRead() {
Timber.d("isOpened = $isOpened")
if (!isOpened) {
@@ -96,6 +131,9 @@ object SensorScaleUtils {
mSensorScale?.stopContinuousRead()
}
/**
* 关闭称重
*/
fun closeScale() {
isOpened = false
mSensorScale?.closeScale()
@@ -91,6 +91,9 @@ fun AppScreen(
}
/**
* 导航
*/
@Composable
private fun NavHost(
padding: PaddingValues,
@@ -30,6 +30,9 @@ import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.viewmodel.UserViewModel
import timber.log.Timber
/**
* 首页
*/
@Composable
fun HomeScreen(
modifier: Modifier = Modifier,
@@ -49,18 +49,21 @@ import com.sw.inbound.ui.theme.AppTypography.blackTextStyle
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.ProductViewModel
import com.sw.inbound.viewmodel.PurchaseOrderViewModel
@Preview(
widthDp = 1920,
heightDp = 1080,
showBackground = true
)
/**
* 采购订单-供应商列表
*/
@Composable
fun PurchaseOrderScreen(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
viewModel: ProductViewModel = hiltViewModel<ProductViewModel>()
viewModel: PurchaseOrderViewModel = hiltViewModel<PurchaseOrderViewModel>()
) {
val products by viewModel.supplierList.collectAsState()
@@ -97,12 +100,6 @@ fun PurchaseOrderScreen(
} else {
LazyRow(
modifier = modifier
// .paint(painterResource(R.mipmap.bg_listview))
// .fillMaxSize()
// .background(
// color = Color(0x80FFFFFF),
// shape = RoundedCornerShape(12.dp) // 圆角背景
// )
.padding(10.dp),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(30.dp)
@@ -131,6 +128,9 @@ fun PurchaseOrderScreen(
}
}
/**
* 采购单缺省
*/
@Composable
fun PurchaseEmptyItem() {
Column(
@@ -149,6 +149,9 @@ fun PurchaseEmptyItem() {
}
}
/**
* 列表item
*/
@Composable
fun PurchaseOrderItem(product: SupplierInfo, onItemClick: (SupplierInfo) -> Unit) {
@@ -235,7 +238,7 @@ fun PurchaseOrderItem(product: SupplierInfo, onItemClick: (SupplierInfo) -> Unit
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "采购日期", style = grayTextStyle)
Spacer(modifier = Modifier.height(8.dp))
Text(text = product.purchaseDate ?: "", style = blackTextStyle)
Text(text = product.purchaseDate ?: "-", style = blackTextStyle)
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "到货日期", style = grayTextStyle)
@@ -48,6 +48,7 @@ import com.sw.inbound.ext.withSize
import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.AppTypography.black141428TextStyle
import com.sw.inbound.ui.theme.AppTypography.gray96a0aaTextStyle
@@ -57,13 +58,18 @@ import com.sw.inbound.ui.weight.CustomSpinner
import com.sw.inbound.ui.weight.CustomTextField
import com.sw.inbound.ui.weight.IdentityView
import com.sw.inbound.ui.weight.InputType
import com.sw.inbound.ui.weight.ProductListView
import com.sw.inbound.ui.weight.ReceiptUnadjustedListView
import com.sw.inbound.ui.weight.RowInputLayout
import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.ui.weight.dialog.ReceiptTipDialog
import com.sw.inbound.utils.InteractionUtils
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.viewmodel.ReceiptViewModel
import timber.log.Timber
/**
* 收货界面
*/
@Composable
fun ReceiptProductScreen(
modifier: Modifier = Modifier,
@@ -79,6 +85,7 @@ fun ReceiptProductScreen(
LaunchedEffect(receiptResult) {
if (receiptResult) {
ToastUtils.showToast("收货成功")
controller.popBackStack()
}
}
@@ -94,7 +101,7 @@ fun ReceiptProductScreen(
modifier = modifier
.background(
color = Color(0x80FFFFFF),
shape = RoundedCornerShape(12.dp)
shape = RoundedCornerShape(10.dp)
)
.fillMaxWidth()
.padding(30.dp)
@@ -140,6 +147,9 @@ fun ReceiptProductScreen(
}
}
/**
* 左侧列表
*/
@Composable
fun ReceiptLeftView(
modifier: Modifier,
@@ -161,18 +171,18 @@ fun ReceiptLeftView(
) {
Column {
Text(
"供应商:${currentPurchaseInfo?.supplierName}",
"供应商:${currentPurchaseInfo?.supplierName ?: "-"}",
style = black141428TextStyle.bold()
)
Spacer(modifier = Modifier.height(18.dp))
Row {
Text(
"采购单号:${currentPurchaseInfo?.purCode}",
"采购单号:${currentPurchaseInfo?.purCode ?: "-"}",
style = gray96a0aaTextStyle.copy(fontSize = 20.sp)
)
Spacer(modifier = Modifier.width(120.dp))
Text(
"收货单号:${currentPurchaseInfo?.receiveCode}",
"收货单号:${currentPurchaseInfo?.receiveCode ?: "-"}",
style = gray96a0aaTextStyle.copy(fontSize = 20.sp)
)
}
@@ -181,22 +191,15 @@ fun ReceiptLeftView(
items = warehouseTypeList,
selectedItem = currentPurchaseInfo!!.warehouseName,
onItemSelected = { value ->
val currentPurchaseInfo1 = currentPurchaseInfo!!.copy()
currentPurchaseInfo1.warehouseName = value.value
val currentPurchaseInfo1 =
currentPurchaseInfo!!.copy(warehouseName = value.value)
viewModel.updateCurrentPurchaseInfo(currentPurchaseInfo1)
viewModel.updateAllPurchaseStore(store = value)
viewModel.updateAllPurchaseStore(warehouse = value)
})
}
Spacer(modifier = Modifier.height(30.dp))
TabScreen(viewModel)
// LazyColumn(
// verticalArrangement = Arrangement.spacedBy(30.dp)
// ) {
// items(items = purchaseOrderList, key = { it.id }) {
// ReceiptItem(it, modifier)
// }
// }
}
}
}
@@ -275,7 +278,7 @@ fun TabScreen(viewModel: ReceiptViewModel) {
fun UnadjustedView(purchaseOrderList: List<GoodsInfo>, viewModel: ReceiptViewModel) {
val checkedItem by viewModel.selectedItem.collectAsState()
// 未调整view
ProductListView(
ReceiptUnadjustedListView(
modifier = Modifier.padding(horizontal = 30.dp),
productList = purchaseOrderList,
checkedItem = checkedItem,
@@ -343,10 +346,11 @@ private fun AdjustedViewItem(purchaseOrder: GoodsInfo, viewModel: ReceiptViewMod
Text(text = "x", style = AppTypography.black141428TextStyle.bold())
Spacer(modifier = Modifier.width(50.dp))
AdjustedRowInputLayout(
label = "实收", value = purchaseOrder.receivedNumStr,
label = "实收", value = purchaseOrder.receivedNumTemp,
onValueChange = {
viewModel.updatePurchaseItem(
purchaseOrder = purchaseOrder.copy(
receivedNumTemp = it,
receivedNum = it.toSafeFloat()
)
)
@@ -532,11 +536,16 @@ private fun ReceiptProductEditView(
RowInputLayout(
label = "收货数量",
value = selectedItem!!.receivedNumStr,
value = selectedItem!!.receivedNumTemp,
onValueChange = { value ->
viewModel.updateCountInputState(value.isNotEmpty())
selectedItem?.let {
viewModel.updateSelectedItem(selectedItem!!.copy(receivedNum = value.toSafeFloat()))
viewModel.updateSelectedItem(
selectedItem!!.copy(
receivedNumTemp = value,
receivedNum = value.toSafeFloat()
)
)
}
},
trailingLabel = selectedItem?.unitName,
@@ -582,7 +591,11 @@ private fun ReceiptProductEditView(
isInitUpdate = true,
textAlign = TextAlign.End,
trailingLabel = selectedItem!!.goodsWeightUnitStr,
inputType = InputType.Decimal
inputType = InputType.Decimal,
onClick = InteractionUtils.rememberDoubleClickDetector {
Timber.d("物品重量 双击")
SensorScaleUtils.tare()
}
)
}
@@ -593,7 +606,7 @@ private fun ReceiptProductEditView(
thickness = 1.dp,
color = colorResource(R.color.divider)
)
Spacer(modifier = Modifier.height(30.dp))
Spacer(modifier = Modifier.height(20.dp))
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
@@ -604,6 +617,11 @@ private fun ReceiptProductEditView(
viewModel.updateSelectedItem(null)
}, painter = painterResource(R.mipmap.ic_btn_back), contentDescription = "返回")
Image(modifier = Modifier.clickable {
val errorInfo = selectedItem!!.hasNullField()
if (errorInfo != null) {
ToastUtils.showToast(errorInfo)
return@clickable
}
viewModel.updatePurchaseItem(purchaseOrder = selectedItem!!.copy(isAdjusted = true))
viewModel.updateSelectedItem(null)
}, painter = painterResource(R.mipmap.ic_btn_confirm), contentDescription = "确定")
@@ -1,6 +1,5 @@
package com.sw.inbound.ui.page
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -19,8 +18,6 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@@ -60,6 +57,7 @@ import com.sw.inbound.ext.withColor
import com.sw.inbound.ext.withSize
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.DictType
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Black_141428
import com.sw.inbound.ui.weight.BottomActionBar
@@ -74,6 +72,7 @@ import com.sw.inbound.ui.weight.InputType
import com.sw.inbound.ui.weight.RowInputLayout
import com.sw.inbound.ui.weight.SelfProcurementListItem
import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.utils.InteractionUtils
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.viewmodel.SelfProcurementViewModel
import timber.log.Timber
@@ -83,6 +82,9 @@ import timber.log.Timber
heightDp = 1080,
showBackground = true
)
/**
* 自采购
*/
@Composable
fun SelfProcurementScreen(
modifier: Modifier = Modifier,
@@ -94,6 +96,7 @@ fun SelfProcurementScreen(
LaunchedEffect(addToWarehouseResult) {
if (addToWarehouseResult) {
ToastUtils.showToast("提交入库成功")
controller.popBackStack()
}
}
@@ -120,6 +123,7 @@ fun SelfProcurementScreen(
controller.popBackStack()
}, showRight1Button = true, right1ButtonText = "清空物品", onRight1ButtonClick = {
viewModel.clearPurchaseOrders()
ToastUtils.showToast("物品清空成功")
}, right2ButtonText = "提交入库", onRight2ButtonClick = {
viewModel.addToWarehouse()
})
@@ -288,11 +292,7 @@ private fun DialogContentView(
Spacer(modifier = Modifier.height(58.dp))
Row(modifier = Modifier.fillMaxWidth()) {
// 采集窗口
CameraCaptureLayout(modifier = Modifier.width(428.dp), onCancelClick = {
}, onConfirmClick = {
})
CameraCaptureLayout(modifier = Modifier.width(428.dp))
Spacer(modifier = Modifier.width(60.dp))
// 右侧输入窗口
@@ -331,8 +331,9 @@ private fun DialogRightEditView(viewModel: SelfProcurementViewModel) {
})
ColumnInputText(
modifier = Modifier.width(474.dp),
label = "物品编码(服务生成)",
label = "物品编码(系统生成)",
value = "",
enabled = false,
onValueChange = {
// viewModel.updateFormState(formState.copy(goodCode = it))
})
@@ -470,7 +471,8 @@ fun ColumnInputText(
value: String,
onValueChange: (String) -> Unit = {},
dropdownItems: List<DictType> = emptyList(),
trailingLabel: String? = null, inputType: InputType = InputType.Text
trailingLabel: String? = null, inputType: InputType = InputType.Text,
enabled: Boolean = true
) {
val placeholder = if (dropdownItems.isEmpty()) "请录入" else "请选择"
Column(modifier = modifier) {
@@ -482,7 +484,8 @@ fun ColumnInputText(
onValueChange = onValueChange,
placeholderValue = placeholder,
trailingLabel = trailingLabel,
inputType = inputType
inputType = inputType,
enabled = enabled
)
} else {
CustomDropdownTextField(
@@ -647,14 +650,19 @@ private fun SelfProductEditView(
RowInputLayout(
label = "采购数量",
value = selectedItem!!.goodsCountStr,
value = selectedItem!!.goodsCountTemp,
inputType = InputType.Decimal,
isInitUpdate = true,
onValueChange = { value ->
Timber.d("采购数量 onValueChange value = $value")
viewModel.updateCountInputState(value.isNotEmpty())
selectedItem.let {
viewModel.updateSelectedItem(selectedItem!!.copy(goodsCount = value.toSafeDouble()))
viewModel.updateSelectedItem(
selectedItem!!.copy(
goodsCountTemp = value,
goodsCount = value.toSafeDouble()
)
)
}
},
trailingLabel = selectedItem!!.unitName,
@@ -699,19 +707,23 @@ private fun SelfProductEditView(
isInitUpdate = true,
textAlign = TextAlign.End,
trailingLabel = selectedItem!!.goodsWeightUnitStr,
onClick = InteractionUtils.rememberDoubleClickDetector {
Timber.d("物品重量 双击")
SensorScaleUtils.tare()
},
leadingIcon = {
Button(
onClick = {},
modifier = Modifier
.padding(0.dp)
.fillMaxHeight(),
shape = RoundedCornerShape(10.dp),
border = BorderStroke(2.dp, color = Color.White),
colors = ButtonDefaults.buttonColors(
containerColor = Color.White,
contentColor = Black_141428
),
) { Text(text = "累计", style = AppTypography.black141428TextStyle) }
// Button(
// onClick = {},
// modifier = Modifier
// .padding(0.dp)
// .fillMaxHeight(),
// shape = RoundedCornerShape(10.dp),
// border = BorderStroke(2.dp, color = Color.White),
// colors = ButtonDefaults.buttonColors(
// containerColor = Color.White,
// contentColor = Black_141428
// ),
// ) { Text(text = "累计", style = AppTypography.black141428TextStyle) }
}
)
}
@@ -748,6 +760,7 @@ private fun SelfProductEditView(
ToastUtils.showToast(errInfo)
return@CustomButton
}
viewModel.addPurchaseItem(selectedItem!!)
})
}
@@ -50,11 +50,12 @@ import com.sw.inbound.utils.ToastUtils
import timber.log.Timber
import java.io.File
/**
* 相机预览 -默认不预览,支持拍照
*/
@Composable
fun CameraCaptureLayout(
modifier: Modifier = Modifier,
onCancelClick: () -> Unit = {},
onConfirmClick: () -> Unit = {}
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var showCamera by remember { mutableStateOf(false) }
@@ -79,7 +80,6 @@ fun CameraCaptureLayout(
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
if (showCamera) {
// CameraPreview()
// 摄像头预览
CameraPreview(
modifier = Modifier
@@ -183,7 +183,7 @@ fun CameraCaptureLayout(
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile)
photoUri = savedUri
Timber.d("photoUri = $photoUri")
Toast.makeText(context, "片已保存", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "片已保存", Toast.LENGTH_SHORT).show()
showCamera = false
GlobalData.imageUri = photoUri
}
@@ -208,7 +208,7 @@ fun CameraCaptureLayout(
// 生命周期管理
DisposableEffect(lifecycleOwner) {
Timber.d("cameraController 释放")
Timber.d("cameraController")
cameraController.bindToLifecycle(lifecycleOwner)
onDispose { }
}
@@ -13,6 +13,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.sw.inbound.R
/**
* 相机预览
*/
@Composable
fun CameraPreview(
controller: LifecycleCameraController,
@@ -1,60 +0,0 @@
package com.sw.inbound.ui.weight
import android.Manifest
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
@OptIn(ExperimentalPermissionsApi::class)
@Preview
@Composable
fun CameraScreen() {
val cameraPermissionState =
rememberPermissionState(permission = Manifest.permission.CAMERA)
LaunchedEffect(key1 = Unit) {
if (!cameraPermissionState.status.isGranted && !cameraPermissionState.status.shouldShowRationale) {
cameraPermissionState.launchPermissionRequest()
}
}
if (cameraPermissionState.status.isGranted) {
//接受拍照的授权
// CameraContent()
} else {
//未授权,显示未授权的界面
NoPermissionScreen(cameraPermissionState)
}
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun NoPermissionScreen(cameraPermissionState: PermissionState) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
val message = if (cameraPermissionState.status.shouldShowRationale) {
"未获取照相机权限导致无法使用照相机功能"
} else {
"请授权照相机的权限"
}
Text(message)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = {
cameraPermissionState.launchPermissionRequest()
}) {
Text("请求授权")
}
}
}
@@ -30,6 +30,9 @@ import com.sw.inbound.model.response.DictType
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Black_141428
/**
* 表单中的下拉菜单
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomDropdownTextField(
@@ -30,6 +30,9 @@ import com.sw.inbound.R
import com.sw.inbound.ui.theme.AppTypography
import timber.log.Timber
/**
* 搜索框
*/
@Composable
fun CustomSearchView(onValueChange: (String) -> Unit = {}, onSearchClick: (String) -> Unit) {
var searchText by remember { mutableStateOf("") }
@@ -0,0 +1,29 @@
package com.sw.inbound.ui.weight
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import com.sw.inbound.ui.theme.AppTypography
/**
* 自定义单行文本
*/
@Composable
fun CustomSingleRightText(
modifier: Modifier,
text: String,
style: TextStyle = AppTypography.blackTextStyle,
textAlign: TextAlign = TextAlign.End
) {
Text(
modifier = modifier,
text = text,
textAlign = textAlign,
style = style,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
@@ -24,6 +24,9 @@ import androidx.compose.ui.unit.sp
import com.sw.inbound.R
import com.sw.inbound.model.response.DictType
/**
* 自定义顶部仓库下拉
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomSpinner(
@@ -2,10 +2,12 @@ package com.sw.inbound.ui.weight
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
@@ -84,22 +86,26 @@ enum class InputType {
Decimal // 浮点
}
/**
* 自定义输入框
*/
@Composable
fun CustomTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier.height(60.dp),
placeholderValue: String = "请录入",
trailingLabel: String? = null,
placeholderValue: String = "请录入", // 占位文本
trailingLabel: String? = null, // 右侧文字
textAlign: TextAlign = TextAlign.Start,
textStyle: TextStyle? = null,
leadingIcon: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null, // 左侧布局
enabled: Boolean = true,
inputType: InputType = InputType.Text,
hasNext: Boolean = true,
isInitUpdate: Boolean = false,
inputType: InputType = InputType.Text, // 输入类型
hasNext: Boolean = true, // 键盘显示下一个
isInitUpdate: Boolean = false, // 是否需要根据原始数据变动
keyboardOptions: KeyboardOptions? = null,
keyboardActions: KeyboardActions? = null
keyboardActions: KeyboardActions? = null,
onClick: () -> Unit = {}, // 点击
) {
val containerColor = if (enabled) Color.Transparent else Gray_DCDCF0
// var inputValue by remember { mutableStateOf(value) }
@@ -109,8 +115,8 @@ fun CustomTextField(
}
val focusManager = LocalFocusManager.current
fun onEditingComplete() {
Timber.d("onEditingComplete inputValue = $inputValue")
fun onEditingComplete(isFocus: Boolean) {
Timber.d("onEditingComplete inputValue = $inputValue, isFocus = $isFocus")
onValueChange(inputValue)
}
@@ -133,20 +139,20 @@ fun CustomTextField(
InputType.Number -> {
if (newValue.isEmpty() || newValue.isValidNumber()) {
inputValue = newValue
onEditingComplete()
onEditingComplete(true)
}
}
InputType.Decimal -> {
if (newValue.isEmpty() || newValue.isValidFloat()) {
inputValue = newValue
onEditingComplete()
onEditingComplete(true)
}
}
else -> {
inputValue = newValue
onEditingComplete()
onEditingComplete(true)
}
}
},
@@ -159,9 +165,11 @@ fun CustomTextField(
color = Gray_DCDCF0,
shape = RoundedCornerShape(10.dp)
)
.clickable(onClick = onClick)
// .focusable()
.onFocusChanged(onFocusChanged = { focusState ->
{
onEditingComplete()
onEditingComplete(focusState.isFocused)
}
}),
colors = TextFieldDefaults.colors(
@@ -187,23 +195,25 @@ fun CustomTextField(
leadingIcon = leadingIcon,
trailingIcon = trailingLabel?.let { label ->
{
Text(
text = trailingLabel,
modifier = Modifier
.fillMaxHeight()
.wrapContentHeight(Alignment.CenterVertically),
style = AppTypography.gray96a0aaTextStyle
)
Box(modifier = Modifier.padding(start = 10.dp, end = 20.dp)) {
Text(
text = trailingLabel,
modifier = Modifier
.fillMaxHeight()
.wrapContentHeight(Alignment.CenterVertically),
style = AppTypography.gray96a0aaTextStyle
)
}
}
},
keyboardOptions = keyboardOptions
?: KeyboardOptions.Default.copy(imeAction = if (hasNext) ImeAction.Next else ImeAction.Done),
keyboardActions = keyboardActions ?: KeyboardActions(onNext = {
focusManager.moveFocus(focusDirection = FocusDirection.Next)
onEditingComplete()
onEditingComplete(false)
}, onDone = {
focusManager.clearFocus()
onEditingComplete()
onEditingComplete(false)
})
)
}
@@ -1,16 +1,21 @@
package com.sw.inbound.ui.weight
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.sw.inbound.ext.withColor
import com.sw.inbound.network.LoadingState
import com.sw.inbound.ui.theme.AppTypography
@Composable
fun GlobalLoading() {
@@ -22,10 +27,16 @@ fun GlobalLoading() {
dismissOnClickOutside = false
)
) {
Column {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
CircularProgressIndicator(modifier = Modifier)
Spacer(modifier = Modifier.height(20.dp))
Text(text = "请稍等...")
Text(
text = "请稍等...",
style = AppTypography.grayTextStyle.withColor(color = Color.White)
)
}
}
}
@@ -13,16 +13,13 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.unit.dp
import com.sw.inbound.R
import com.sw.inbound.ext.bold
@@ -30,9 +27,11 @@ import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Gray_DCDCF0
/**
* 收货-未调整列表
*/
@Composable
fun ProductListView(
fun ReceiptUnadjustedListView(
modifier: Modifier = Modifier,
productList: List<GoodsInfo>,
checkedItem: GoodsInfo? = null,
@@ -141,21 +140,4 @@ fun ProductListView(
}
}
}
}
@Composable
private fun CustomSingleRightText(
modifier: Modifier,
text: String,
style: TextStyle = AppTypography.blackTextStyle,
textAlign: TextAlign = TextAlign.End
) {
Text(
modifier = modifier,
text = text,
textAlign = textAlign,
style = style,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
@@ -23,16 +23,16 @@ import com.sw.inbound.ui.theme.AppTypography
*/
@Composable
fun RowInputLayout(
label: String,
label: String, // 左侧文字
value: String,
onValueChange: (String) -> Unit,
dropdownItems: List<DictType>? = null,
hasNext: Boolean = true,
dropdownItems: List<DictType>? = null, // 下拉列表
hasNext: Boolean = true, // 键盘显示下一步
inputType: InputType = InputType.Text,
trailingLabel: String? = null,
trailingLabel: String? = null, // 尾部文字
keyboardOptions: KeyboardOptions? = null,
keyboardActions: KeyboardActions? = null,
isInitUpdate: Boolean = false
isInitUpdate: Boolean = false // 是否根据原始数据更新
) {
Row(
modifier = Modifier
@@ -13,16 +13,13 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.unit.dp
import com.sw.inbound.R
import com.sw.inbound.ext.bold
@@ -30,7 +27,9 @@ import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Gray_DCDCF0
/**
* 自采购 左侧列表
*/
@Composable
fun SelfProcurementListItem(
modifier: Modifier = Modifier,
@@ -141,21 +140,4 @@ fun SelfProcurementListItem(
}
}
}
}
@Composable
private fun CustomSingleRightText(
modifier: Modifier,
text: String,
style: TextStyle = AppTypography.blackTextStyle,
textAlign: TextAlign = TextAlign.End
) {
Text(
modifier = modifier,
text = text,
textAlign = textAlign,
style = style,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
@@ -52,6 +52,9 @@ fun testSingleGroup() {
// SingleSelectButtonGroup(list)
}
/**
* 搜索结果列表,可选中
*/
@Composable
fun SingleSelectButtonGroup(
options: List<SearchGoodsInfo.Record>,
@@ -65,15 +68,15 @@ fun SingleSelectButtonGroup(
var selectedOption by remember { mutableStateOf(options.firstOrNull() ?: "") }
// 定义颜色
val selectedColor = Color(0xFFD9E3F9) // 选中颜色 #D9E3F9
val unselectedColor = Color(0xFFDCDCF0) // 未选中颜色 #DCDCF0
val selectedColor = Color(0xFFD9E3F9)
val unselectedColor = Color(0xFFDCDCF0)
LazyVerticalGrid(
columns = GridCells.Fixed(2), // 每行2列
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), // 水平间距13dp
verticalArrangement = Arrangement.spacedBy(verticalSpacing) // 垂直间距13dp
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing),
verticalArrangement = Arrangement.spacedBy(verticalSpacing)
) {
items(items = options) { option ->
Box(
@@ -90,7 +93,7 @@ fun SingleSelectButtonGroup(
onOptionSelected(option)
},
contentAlignment = Alignment.Center
// .padding(vertical = 20.dp) // 垂直内边距
// .padding(vertical = 20.dp)
) {
Text(
text = option.goodsNameStr,
@@ -42,6 +42,9 @@ import kotlinx.coroutines.delay
heightDp = 1080,
showBackground = true
)
/**
* 标题
*/
@Composable
fun TopTitleBar(
modifier: Modifier = Modifier,
@@ -33,6 +33,9 @@ import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.weight.CustomButton
import com.sw.inbound.ui.weight.CustomOutlinedButton
/**
* 收货确认弹窗
*/
@Composable
fun ReceiptTipDialog(
modifier: Modifier = Modifier,
@@ -2,6 +2,8 @@ package com.sw.inbound.utils
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -126,12 +128,12 @@ object InteractionUtils {
* 双击检测器
*/
class DoubleClickDetector(
private val timeout: Long = 300L,
private val timeout: Long = 500L,
private val onSingleClick: () -> Unit = {},
private val onDoubleClick: () -> Unit
) {
private var clickCount by mutableStateOf(0)
private var lastClickTime by mutableStateOf(0L)
private var clickCount by mutableIntStateOf(0)
private var lastClickTime by mutableLongStateOf(0L)
/**
* 处理点击事件
@@ -121,31 +121,4 @@ abstract class BaseViewModel(
}
}
}
fun getStoreList(): ArrayList<String> {
return arrayListOf(
"默认仓库",
"仓库1",
"仓库2",
"仓库3",
)
}
fun getPurchasingUnit(): ArrayList<String> {
return arrayListOf(
"",
"",
""
)
}
fun getProductList(): ArrayList<String> {
return arrayListOf<String>(
"胶东大白菜",
"玉田尖白菜1",
"玉田尖白菜2",
"玉田尖白菜3",
"玉田尖白菜4"
)
}
}
@@ -7,11 +7,17 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
/**
* 采购订单
*/
@HiltViewModel
class ProductViewModel @Inject constructor(
class PurchaseOrderViewModel @Inject constructor(
private val repository: RemoteRepository
) : BaseViewModel(repository) {
/**
* 采购订单-供应商列表
*/
private val _supplierList = MutableStateFlow<List<SupplierInfo?>>(emptyList())
val supplierList: StateFlow<List<SupplierInfo?>> = _supplierList
@@ -3,6 +3,7 @@ package com.sw.inbound.viewmodel
import androidx.lifecycle.viewModelScope
import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeFloat
import com.sw.inbound.ext.toSafeString
import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo
@@ -22,6 +23,9 @@ import kotlinx.coroutines.flow.update
import timber.log.Timber
import javax.inject.Inject
/**
* 收货
*/
@HiltViewModel
class ReceiptViewModel @Inject constructor(
private val repository: RemoteRepository
@@ -37,16 +41,6 @@ class ReceiptViewModel @Inject constructor(
private val _currentPurchaseInfo = MutableStateFlow<PurchaseInfo?>(null)
val currentPurchaseInfo: StateFlow<PurchaseInfo?> = _currentPurchaseInfo
// 自动从 currentPurchaseInfo 派生 orders
// private val _orders: StateFlow<List<GoodsInfo>> = currentPurchaseInfo
// .map { purchaseInfo ->
// purchaseInfo?.receiveGoodsInfoList ?: emptyList()
// }
// .stateIn(
// viewModelScope,
// SharingStarted.WhileSubscribed(5000), // 或者使用 Lazily/Eagerly 根据需求
// emptyList()
// )
private val _orders = MutableStateFlow<List<GoodsInfo>>(emptyList())
val orders: StateFlow<List<GoodsInfo>> = _orders.asStateFlow()
@@ -64,9 +58,7 @@ class ReceiptViewModel @Inject constructor(
.map { orders -> orders.filter { !it.isAdjusted && it.goodId != null } }
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
val mergedOrders: StateFlow<List<GoodsInfo>> = _orders
//
// 选中的商品
private val _selectedItem = MutableStateFlow<GoodsInfo?>(null)
val selectedItem: StateFlow<GoodsInfo?> = _selectedItem
@@ -74,9 +66,11 @@ class ReceiptViewModel @Inject constructor(
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
// 物品数量 是否由用户输入
private val _countUserInput = MutableStateFlow<Boolean>(false)
/**
@@ -87,10 +81,21 @@ class ReceiptViewModel @Inject constructor(
_adjustState.value = isAdjustState
}
fun StateFlow<List<GoodsInfo>>.getValidOrders(): List<GoodsInfo> {
return this.value.filter { it.goodId != null }
}
/**
* 更新收货提示弹窗
*/
fun updateReceiptDialog(showDialog: Boolean) {
if (_orders.getValidOrders().isEmpty()) {
ToastUtils.showToast("订单为空或包含异常数据")
return
}
if (!unadjustedOrders.value.isEmpty()) {
ToastUtils.showToast("请先调整物品信息")
return
}
_showReceiptDialog.value = showDialog
}
@@ -151,12 +156,12 @@ class ReceiptViewModel @Inject constructor(
/**
* 更新所有商品仓库
*/
fun updateAllPurchaseStore(store: DictType, predicate: (GoodsInfo) -> Boolean = { true }) {
fun updateAllPurchaseStore(warehouse: DictType, predicate: (GoodsInfo) -> Boolean = { true }) {
_orders.update { currentList ->
currentList.map { order ->
if (predicate(order)) order.copy(
warehouseId = store.id,
warehouseName = store.value
warehouseId = warehouse.id,
warehouseName = warehouse.value
) else order
}
}
@@ -192,6 +197,9 @@ class ReceiptViewModel @Inject constructor(
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
receivedNumTemp = if (_countUserInput.value) info.receivedNumTemp else count.toSafeString(
currentItem.unitName
),
receivedNum = if (_countUserInput.value) info.receivedNum else finalCount
)
}
@@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope
import com.sw.inbound.GlobalData
import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.ext.toSafeString
import com.sw.inbound.model.request.GoodsAddParam
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.DictType
@@ -15,12 +16,14 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
/**
* 自采购
*/
@HiltViewModel
class SelfProcurementViewModel @Inject constructor(
private val repository: RemoteRepository
@@ -39,6 +42,7 @@ class SelfProcurementViewModel @Inject constructor(
private val _globalWarehouse = MutableStateFlow<DictType>(DictType(-1, "选择仓库"))
val globalWarehouse: StateFlow<DictType> = _globalWarehouse
// 采购列表
private val _purchaseList = MutableStateFlow<List<PurchaseWarehouseParam>>(emptyList())
val purchaseList: StateFlow<List<PurchaseWarehouseParam>> = _purchaseList
@@ -58,14 +62,6 @@ class SelfProcurementViewModel @Inject constructor(
private val _weightInfo = MutableStateFlow<Double?>(0.0)
val weightInfo: StateFlow<Double?> = _weightInfo
private val _showCameraPreview = MutableStateFlow(true)
val showCameraPreview = _showCameraPreview.asStateFlow()
fun updateCameraPreviewShow(show: Boolean) {
_showCameraPreview.value = show
}
/**
* 数量是否是用户输入的值
*/
@@ -95,6 +91,9 @@ class SelfProcurementViewModel @Inject constructor(
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
goodsCountTemp = if (_countUserInput.value) info.goodsCountTemp else count.toSafeString(
currentItem.unitName
),
goodsCount = if (_countUserInput.value) info.goodsCount else finalCount
)
}
@@ -124,6 +123,10 @@ class SelfProcurementViewModel @Inject constructor(
// 添加订单
fun addPurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
if (_purchaseList.value.any { it.goodsId == purchaseOrder.goodsId }) {
ToastUtils.showToast("添加失败,当前物品已添加")
return
}
_purchaseList.update { currentList ->
// 当已经添加过则忽略
if (currentList.any { it.goodsId == purchaseOrder.goodsId }) {
@@ -181,9 +184,9 @@ class SelfProcurementViewModel @Inject constructor(
delay(50)
_selectedItem.value = PurchaseWarehouseParam(
warehouseId = warehouse.id,
goodsId = searchFirst.goodsId!!,
goodsId = searchFirst.goodsId ?: 0,
goodsName = searchFirst.goodsName,
kcUnitId = searchFirst.kcUnitId!!,
kcUnitId = searchFirst.kcUnitId ?: 0,
unitList = searchFirst.unitVoList,
)
}
@@ -220,6 +223,7 @@ class SelfProcurementViewModel @Inject constructor(
return@launchWithLoading
}
_showAddProductDialog.value = false
_goodsAddParam.value = GoodsAddParam()
val searchFirst = response.data!!.records?.get(0)
searchFirst?.let {
updateSelectedItemWithSearch(searchFirst)
@@ -229,7 +233,10 @@ class SelfProcurementViewModel @Inject constructor(
}
fun addToWarehouse() {
if (_purchaseList.value.isEmpty()) return
if (_purchaseList.value.isEmpty()) {
ToastUtils.showToast("采购列表为空")
return
}
launchWithLoading {
val response = repository.selfPurchaseWarehousing(_purchaseList.value)
if (parseResponse(response)) {