自采入库、新增物品、上传图片、全部收货接口调试,其它逻辑优化

This commit is contained in:
2025-10-29 20:08:12 +08:00
parent 0611005d04
commit 7930ba0cd1
24 changed files with 651 additions and 306 deletions
@@ -5,15 +5,22 @@ import android.view.WindowManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import com.sw.inbound.objbox.FoodModule
import com.sw.inbound.sdk.SensorScaleUtils import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.ui.AppScreen import com.sw.inbound.ui.AppScreen
import com.sw.inbound.utils.ContextUtils import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.SPUtil import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ThreadUtils import com.sw.inbound.utils.ThreadUtils
import com.sw.inbound.viewmodel.ReceiptViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlin.getValue
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
val viewModel: ReceiptViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
@@ -27,6 +34,8 @@ class MainActivity : ComponentActivity() {
finish() finish()
}) })
} }
SensorScaleUtils.startScale(autoScale = true){}
FoodModule.init(this)
} }
override fun onDestroy() { override fun onDestroy() {
@@ -8,26 +8,32 @@ import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.camera.core.CameraSelector import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.view.CameraController import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController import androidx.camera.view.LifecycleCameraController
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams
import com.shuwei.intelligent.shelves.utils.ext.appendText import com.shuwei.intelligent.shelves.utils.ext.appendText
import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString
import com.sw.inbound.GlobalData import com.sw.inbound.GlobalData
import com.sw.inbound.databinding.ActivityGoodsListBinding import com.sw.inbound.databinding.ActivityGoodsListBinding
import com.sw.inbound.databinding.LayoutCameraPreviewBinding
import com.sw.inbound.databinding.ListItemReceiptGoodsBinding import com.sw.inbound.databinding.ListItemReceiptGoodsBinding
import com.sw.inbound.databinding.ListItemSelfProcurementBinding import com.sw.inbound.databinding.ListItemSelfProcurementBinding
import com.sw.inbound.dialog.DropdownPopup import com.sw.inbound.dialog.DropdownPopup
import com.sw.inbound.dialog.GoodsRecognizeDialog import com.sw.inbound.dialog.GoodsRecognizeDialog
import com.sw.inbound.dialog.GoodsSearchDialog import com.sw.inbound.dialog.GoodsSearchDialog
import com.sw.inbound.dialog.NotReceiptWarnDialog import com.sw.inbound.dialog.NotReceiptWarnDialog
import com.sw.inbound.model.request.GoodsAddParam
import com.sw.inbound.model.request.PurchaseWarehouseParam import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.request.UploadInfo import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.objbox.FoodModule import com.sw.inbound.objbox.FoodModule
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.utils.BitmapCropper import com.sw.inbound.utils.BitmapCropper
import com.sw.inbound.utils.BitmapSaver import com.sw.inbound.utils.BitmapSaver
import com.sw.inbound.utils.ImageUtil import com.sw.inbound.utils.ImageUtil
@@ -67,6 +73,8 @@ abstract class GoodsListActivity : ComponentActivity() {
abstract fun initView() abstract fun initView()
abstract fun getWarehouseList(): List<DictType> abstract fun getWarehouseList(): List<DictType>
private lateinit var backPressedCallback: OnBackPressedCallback private lateinit var backPressedCallback: OnBackPressedCallback
private lateinit var previewView: PreviewView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityGoodsListBinding.inflate(layoutInflater) binding = ActivityGoodsListBinding.inflate(layoutInflater)
@@ -76,7 +84,6 @@ abstract class GoodsListActivity : ComponentActivity() {
isNewReceipt = intent.getBooleanExtra(IS_NEW_RECEIPT, false) isNewReceipt = intent.getBooleanExtra(IS_NEW_RECEIPT, false)
id = intent.getStringExtra(ID) ?: "" id = intent.getStringExtra(ID) ?: ""
supplierId = intent.getStringExtra(SUPPLIER_ID) ?: "" supplierId = intent.getStringExtra(SUPPLIER_ID) ?: ""
FoodModule.init(this)
initCamera() initCamera()
replaceIncludeContent() replaceIncludeContent()
initRecyclerView() initRecyclerView()
@@ -105,18 +112,34 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
dropdownPopup?.showAsDropDown(v) dropdownPopup?.showAsDropDown(v)
} }
binding.tvPurchaseNo.setOnClickListener {
GoodsRecognizeDialog(
context = this,
list = mutableListOf()
) {
GoodsSearchDialog(this).show()
}.show()
}
binding.tvUserName.text = GlobalData.deviceId binding.tvUserName.text = GlobalData.deviceId
binding.tvUserName.gone()
binding.ivLogout.gone() binding.ivLogout.gone()
val previewBinding =
LayoutCameraPreviewBinding.inflate(layoutInflater, binding.flCameraPreview)
previewView = previewBinding.previewView.also {
it.updateLayoutParams {
width = 1
height = 1
}
}
setPreviewController(previewView)
setPreviewController(binding.previewView) //viewModel.startSensorScale()
viewModel.startSensorScale()
binding.root.postDelayed({ binding.root.postDelayed({
viewModel.readWeight { SensorScaleUtils.addWeightListener {
weightCallback?.invoke(it) weightCallback?.invoke(it)
recognizeWeight(weight = it) recognizeWeight(weight = it)
} }
}, 5 * 1000) }, 3 * 1000)
} }
private var weightCallback: ((weight: Int) -> Unit)? = null private var weightCallback: ((weight: Int) -> Unit)? = null
@@ -128,21 +151,23 @@ abstract class GoodsListActivity : ComponentActivity() {
if (weight < 200) { if (weight < 200) {
return return
} }
if (searchFoodEnable.not()) { if (isShowRecognizeDialog.not()) {
return return
} }
isShowRecognizeDialog = false
runOnUiThread { runOnUiThread {
recognizeFood() recognizeFood()
} }
} }
fun recognizeFood() { private val takePhotoSuccessCallback: (Uri) -> Unit = { uri ->
searchFoodEnable = false
takePhoto { uri ->
Thread { Thread {
searchFood(uri) searchFood(uri)
}.start() }.start()
} }
fun recognizeFood() {
takePhoto(takePhotoSuccessCallback)
} }
private var dropdownPopup: DropdownPopup? = null private var dropdownPopup: DropdownPopup? = null
@@ -156,7 +181,7 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
} }
private var searchFoodEnable = true private var isShowRecognizeDialog = true
private fun searchFood(uri: Uri) { private fun searchFood(uri: Uri) {
ImageUtil.uriToBitmap(this, uri)?.let { bitmap -> ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
val newBmp = BitmapCropper.cropCenter( val newBmp = BitmapCropper.cropCenter(
@@ -174,7 +199,6 @@ abstract class GoodsListActivity : ComponentActivity() {
searchMultipleGoods(foodNameList) { goodsList -> searchMultipleGoods(foodNameList) { goodsList ->
//if (goodsList.size != foodNameList.size) { //if (goodsList.size != foodNameList.size) {
// toast("系统异常,请稍后重试!!!") // toast("系统异常,请稍后重试!!!")
// searchFoodEnable = true
// return@searchMultipleGoods // return@searchMultipleGoods
//} //}
handleGoodsResult( handleGoodsResult(
@@ -188,43 +212,56 @@ abstract class GoodsListActivity : ComponentActivity() {
private fun handleGoodsResult(goodsList: MutableList<SearchGoodsInfo.Record>) { private fun handleGoodsResult(goodsList: MutableList<SearchGoodsInfo.Record>) {
runOnUiThread { runOnUiThread {
if (goodsRecognizeDialog?.isShowing == true) { if (goodsRecognizeDialog?.isShowing == true) {
searchFoodEnable = true isShowRecognizeDialog = false
return@runOnUiThread return@runOnUiThread
} }
goodsRecognizeDialog = GoodsRecognizeDialog(this, goodsList, { goodsRecognizeDialog = GoodsRecognizeDialog(
goodsRecognizeDialog = null context = this,
searchFoodEnable = true list = goodsList
}) { ) {
GoodsSearchDialog(this).show() GoodsSearchDialog(this).show()
}.apply { }.apply {
if (isFinishing || isDestroyed) { setOnDismissListener {
return@apply goodsRecognizeDialog = null
isShowRecognizeDialog = true
} }
setOnShowListener {
isShowRecognizeDialog = false
}
if (isFinishing.not() && isDestroyed.not()) {
show() show()
} }
} }
} }
}
private var goodsRecognizeDialog: GoodsRecognizeDialog? = null private var goodsRecognizeDialog: GoodsRecognizeDialog? = null
private var cameraController: LifecycleCameraController? = null private var cameraController: LifecycleCameraController? = null
private var photoCaptureHelper: PhotoCaptureHelper? = null private var photoCaptureHelper: PhotoCaptureHelper? = null
private var isCameraReady = false private var isCameraReady = false
fun takePhoto(cameraCallback: (Uri) -> Unit) { fun takePhoto(callback: (Uri) -> Unit) {
cameraController?.let { cameraController?.let {
if (photoCaptureHelper == null) { if (photoCaptureHelper == null) {
initCaptureHelper()
}
}
photoCaptureHelper?.let {
it.addSuccessCallback(callback)
it.takePhoto()
}
}
fun initCaptureHelper() {
photoCaptureHelper = PhotoCaptureHelper( photoCaptureHelper = PhotoCaptureHelper(
context = this, context = this,
cameraController = cameraController!!, cameraController = cameraController!!,
onSuccess = cameraCallback, onSuccess = {},
onError = { msg -> onError = { msg ->
//toast(msg) //toast(msg)
} }
) )
} }
}
photoCaptureHelper?.takePhoto()
}
fun setPreviewController(previewView: PreviewView?) { fun setPreviewController(previewView: PreviewView?) {
previewView?.controller = cameraController previewView?.controller = cameraController
@@ -271,7 +308,6 @@ abstract class GoodsListActivity : ComponentActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
cameraController?.unbind() cameraController?.unbind()
viewModel.stopSensorScale()
isCameraReady = false isCameraReady = false
} }
@@ -407,4 +443,27 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
} }
fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) {
viewModel.uploadImage(imageUri) { imgUrl ->
if (imgUrl.isNullOrBlank()) {
callback(null)
return@uploadImage
}
callback(imgUrl)
}
}
fun createNewGoods(imageUri: Uri, param: GoodsAddParam, callback: (Boolean) -> Unit) {
viewModel.uploadImage(imageUri) { imgUrl ->
if (imgUrl.isNullOrBlank()) {
toast("图片上传失败")
return@uploadImage
}
param.relativeUrl = imgUrl
viewModel.createNewGoods(param = param, callback = callback)
}
}
private var preview: Preview? = null
} }
@@ -34,14 +34,15 @@ class RecognizeAdapter(var list: MutableList<SearchGoodsInfo.Record>) :
) )
} }
it.ivRecImage.load(item!!.relativeUrl) it.ivRecImage.load(item!!.relativeUrl)
it.root.run { //it.root.run {
setShapeDrawable( // setShapeDrawable(
strokeColor = if (item.isSelected) "#FF0033CC" else "#FFDCDCF0", // //strokeColor = if (item.isSelected) "#FF0033CC" else "#FFDCDCF0",
strokeWidth = 2.dp, // strokeColor = "#FFDCDCF0",
radius = 12.dp // strokeWidth = 2.dp,
) // radius = 12.dp
//setPadding(if (item.isSelected) 2.dp else 0) // )
} // //setPadding(if (item.isSelected) 2.dp else 0)
//}
} }
} }
@@ -1,146 +1,249 @@
//package com.sw.inbound.dialog package com.sw.inbound.dialog
//
//import android.content.Context import android.content.Context
//import android.graphics.SurfaceTexture import android.net.Uri
//import android.view.LayoutInflater import android.view.LayoutInflater
//import android.view.TextureView import android.view.View
//import android.view.View import android.widget.FrameLayout
//import android.widget.FrameLayout import android.widget.TextView
//import android.widget.TextView import androidx.camera.view.PreviewView
//import androidx.compose.ui.text.style.LineHeightStyle import androidx.core.view.updateLayoutParams
//import com.sw.inbound.GlobalData import coil.load
//import com.sw.inbound.activity.GoodsListActivity import com.sw.inbound.GlobalData
//import com.sw.inbound.databinding.DialogAddGoodsBinding import com.sw.inbound.activity.GoodsListActivity
//import com.sw.inbound.model.response.DictType import com.sw.inbound.databinding.DialogAddGoodsBinding
//import com.sw.inbound.utils.ext.dp import com.sw.inbound.databinding.LayoutCameraPreviewBinding
//import com.sw.inbound.utils.ext.gone import com.sw.inbound.ext.toSafeBigDecimal
//import com.sw.inbound.utils.ext.toast import com.sw.inbound.ext.toSafeFloat
//import com.sw.inbound.utils.ext.visible import com.sw.inbound.model.request.GoodsAddParam
//import kotlin.math.min import com.sw.inbound.model.response.DictType
// import com.sw.inbound.utils.ext.dp
//class AddGoodsDialog( import com.sw.inbound.utils.ext.gone
// context: Context, import com.sw.inbound.utils.ext.toast
// var cancelBlock: () -> Unit = {}, import com.sw.inbound.utils.ext.visible
// var confirmBlock: () -> Unit = {}, import kotlin.math.min
//) : BaseDialog(context) {
// class AddGoodsDialog(
// private lateinit var binding: DialogAddGoodsBinding context: Context,
// override fun getRootView(): View { var cancelBlock: () -> Unit = {},
// val inflater = LayoutInflater.from(context) var confirmBlock: (String) -> Unit = {},
// binding = DialogAddGoodsBinding.inflate(inflater) ) : BaseDialog(context) {
// return binding.root
// } private lateinit var binding: DialogAddGoodsBinding
// override fun getRootView(): View {
// private var dropdownPopup: DropdownPopup? = null val inflater = LayoutInflater.from(context)
// binding = DialogAddGoodsBinding.inflate(inflater)
// private val dropdownList: MutableList<DictType> = mutableListOf() return binding.root
// private var activity: GoodsListActivity? = null }
// override fun initView() {
// activity = getReceiptActivity() private var dropdownPopup: DropdownPopup? = null
// binding.previewView.let {
// it.visible() private val dropdownList: MutableList<DictType> = mutableListOf()
// activity?.setPreviewController(it) private var activity: GoodsListActivity? = null
// activity?.setPreviewController(it)
//// val textureView = it.getChildAt(0) as? TextureView override fun show() {
//// textureView?.surfaceTextureListener = object : TextureView.SurfaceTextureListener { super.show()
//// override fun onSurfaceTextureAvailable(
//// surface: SurfaceTexture, window?.decorView?.postDelayed({
//// width: Int, activity?.setPreviewController(previewView)
//// height: Int }, 600)
//// ) { }
//// it.visible()
//// activity?.setPreviewController(it) private val takePhotoCallback: (Uri) -> Unit = { uri ->
//// } binding.flCameraPreview.gone()
//// imageUri = uri
//// override fun onSurfaceTextureSizeChanged( binding.cvImageBg.visible()
//// surface: SurfaceTexture, binding.ivGoodsImage.load(uri)
//// width: Int, }
//// height: Int
//// ) { private lateinit var previewView: PreviewView
//// } override fun initView() {
//// activity = getReceiptActivity()
//// override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { val previewBinding =
//// return true LayoutCameraPreviewBinding.inflate(LayoutInflater.from(context), binding.flCameraPreview)
//// } previewBinding.previewView.let {
//// it.updateLayoutParams {
//// override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { width = 428.dp
//// } height = 320.dp
//// } }
// } previewView = it
// binding.ivGoodsImage.gone() }
// binding.btnClose.setOnClickListener { // binding.flCameraPreview.removeAllViews()
// cancelBlock() // binding.flCameraPreview.addView(previewView)
// dismiss() binding.flCameraPreview.visible()
// } binding.cvImageBg.gone()
// binding.btnConfirm.setOnClickListener { binding.btnClose.setOnClickListener {
// confirmBlock() cancelBlock()
// dismiss() dismiss()
// } }
// binding.btnStartPreview.setOnClickListener { binding.btnConfirm.setOnClickListener {
// binding.ivGoodsImage.gone() submit()
// } }
// binding.btnTakePhoto.setOnClickListener { binding.btnStartPreview.setOnClickListener {
// activity?.takePhoto { uri -> binding.cvImageBg.gone()
// binding.ivGoodsImage.setImageURI(uri) binding.flCameraPreview.visible()
// binding.ivGoodsImage.visible() }
// } binding.btnTakePhoto.setOnClickListener {
// } activity?.takePhoto(takePhotoCallback)
// showDropDownList( }
// binding.flProcurementUnit, binding.btnUploadImg.gone()
// textView = binding.tvProcurementUnit, binding.btnUploadImg.setOnClickListener {
// list = GlobalData.unitTypeList, uploadImage()
// height = 213.dp }
// ) binding.tvGoodsType.let { tv ->
tv.text = "原材料"
tv.tag = GlobalData.goodsTypeList.firstOrNull { it.value == "原材料" }?.id
?: "1980098911276191746"
}
showDropDownList(
binding.flProcurementUnit,
textView = binding.tvProcurementUnit,
list = GlobalData.unitTypeList,
height = 213.dp
)
// showDropDownList( // showDropDownList(
// binding.flGoodsType, // binding.flGoodsType,
// textView = binding.tvGoodsType, // textView = binding.tvGoodsType,
// list = GlobalData.goodsTypeList, // list = GlobalData.goodsTypeList,
// ) // )
// showDropDownList( showDropDownList(
// binding.flStorageType, binding.flStorageType,
// textView = binding.tvStorageType, textView = binding.tvStorageType,
// list = GlobalData.storageTypeList, list = GlobalData.storageTypeList,
// ) )
// showDropDownList( showDropDownList(
// dropdownView = binding.flWarehouseUnit, dropdownView = binding.flWarehouseUnit,
// textView = binding.tvWarehouseUnit, textView = binding.tvWarehouseUnit,
// list = GlobalData.unitTypeList list = GlobalData.unitTypeList
// ) { ) {
// binding.tvSelectUseUnit.text = it.value binding.tvSelectUseUnit.text = it.value
// } binding.tvSelectProcurementUnit.text = it.value
// } }
// }
// private fun showDropDownList(
// dropdownView: FrameLayout, private fun showDropDownList(
// textView: TextView, dropdownView: FrameLayout,
// list: List<DictType>, textView: TextView,
// height: Int = 355.dp, list: List<DictType>,
// block:(DictType)-> Unit= {} height: Int = 355.dp,
// ) { block: (DictType) -> Unit = {}
// dropdownView.setOnClickListener { ) {
// dropdownList.clear() dropdownView.setOnClickListener {
// val tempList = dropdownList.clear()
// list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() } val tempList =
// if (tempList.isEmpty()) { list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
// context.toast("暂无下拉数据") if (tempList.isEmpty()) {
// return@setOnClickListener context.toast("暂无下拉数据")
// } return@setOnClickListener
// dropdownList.addAll(tempList) }
// val realHeight = min(height, dropdownList.size * 71.dp) dropdownList.addAll(tempList)
// dropdownPopup = DropdownPopup( val realHeight = min(height, dropdownList.size * 71.dp)
// context = context, dropdownPopup = DropdownPopup(
// list = dropdownList, context = context,
// popWidth = dropdownView.width, list = dropdownList,
// popHeight = realHeight popWidth = dropdownView.width,
// ) { popHeight = realHeight
// textView.text = it.value ) {
// block(it) textView.run {
// } text = it.value
// dropdownPopup?.showAsDropDown(dropdownView) tag = it.id
// dropdownPopup?.setOnDismissListener { }
// dropdownPopup = null block(it)
// } }
// } dropdownPopup?.showAsDropDown(dropdownView)
// } dropdownPopup?.setOnDismissListener {
// dropdownPopup = null
//} }
}
}
private fun submit() {
if (imageUri == null) {
context.toast("请采集图片")
return
}
val goodsName = binding.etGoodsName.text.trim().toString()
if (goodsName.isBlank()) {
context.toast("请输入物品名称")
return
}
val netRateText = binding.etNetMaterialRate.text.trim().toString()
if (netRateText.isBlank()) {
context.toast("请输入净材率")
return
}
val netRate = (netRateText.toFloatOrNull() ?: 0f) / 100f
val goodsType = binding.tvGoodsType.tag.toString()
if (goodsType.isBlank()) {
context.toast("请录入物品类型")
return
}
val storageType = binding.tvStorageType.tag.toString()
if (storageType.isBlank()) {
context.toast("请录入存储方式")
return
}
val warehouseUnit = binding.tvWarehouseUnit.tag.toString()
if (warehouseUnit.isBlank()) {
context.toast("请录入库存单位")
return
}
val purchaseUnit = binding.tvProcurementUnit.tag.toString()
if (purchaseUnit.isBlank()) {
context.toast("请录采购单位")
return
}
val costValue = binding.etUseUnit.text.trim().toString()
if (costValue.isBlank()) {
context.toast("请输入物品名称")
return
}
val goodsCount = binding.etGoodsCount.text.trim().toString()
if (costValue.isBlank()) {
context.toast("请输入采购数量")
return
}
val goodsPrice = binding.etGoodsPrice.text.trim().toString()
if (goodsPrice.isBlank()) {
context.toast("请输入采购单价")
return
}
val param = GoodsAddParam(
goodName = goodsName,
netRate = netRate,
goodType = goodsType,
storageType = storageType,
unitId = warehouseUnit,
consumeValue = costValue,
purchaseUnit = purchaseUnit,
purchaseValue = goodsCount.toSafeFloat(),
purchasePrice = goodsPrice.toSafeBigDecimal(),
)
activity?.createNewGoods(imageUri!!, param) {
if (it.not()) {
context.toast("新增物品失败")
return@createNewGoods
}
context.toast("新增物品成功")
confirmBlock(goodsName)
dismiss()
}
}
private var imageUri: Uri? = null
private fun uploadImage() {
if (imageUri == null) {
context.toast("请采集图片")
return
}
activity?.uploadImage(imageUri!!) { imgUrl ->
if (imgUrl.isNullOrBlank()) {
context.toast("图片上传失败")
return@uploadImage
}
context.toast(imgUrl)
}
}
}
@@ -15,7 +15,6 @@ import com.sw.inbound.model.response.SearchGoodsInfo
class GoodsRecognizeDialog( class GoodsRecognizeDialog(
context: Context, context: Context,
var list: MutableList<SearchGoodsInfo.Record>, var list: MutableList<SearchGoodsInfo.Record>,
var dismissDialog: () -> Unit,
var findGoods: () -> Unit var findGoods: () -> Unit
) : BaseDialog(context) { ) : BaseDialog(context) {
@@ -27,11 +26,6 @@ class GoodsRecognizeDialog(
return binding.root return binding.root
} }
override fun dismiss() {
dismissDialog()
super.dismiss()
}
private val recognizeAdapter by lazy { private val recognizeAdapter by lazy {
RecognizeAdapter(list).apply { RecognizeAdapter(list).apply {
isStateViewEnable = true isStateViewEnable = true
@@ -38,9 +38,17 @@ class GoodsSearchDialog(
searchGoods() searchGoods()
} }
} }
// binding.btnAddGoods.setOnClickListener { binding.btnAddGoods.setOnClickListener {
// AddGoodsDialog(context).show() AddGoodsDialog(
// } context = context,
cancelBlock = {},
confirmBlock = { goodsName->
pageNo = 1
binding.etInputGoods.setText(goodsName)
searchGoods()
}
).show()
}
binding.btnConfirm.setOnClickListener { binding.btnConfirm.setOnClickListener {
if (list.isEmpty()) { if (list.isEmpty()) {
context.toast("请搜索物品") context.toast("请搜索物品")
@@ -80,6 +80,7 @@ class GoodsStoreDialog(
text = it.value text = it.value
tag = it.id tag = it.id
} }
binding.tvCountUnit.text = it.value
} }
} }
dropdownPopup?.showAsDropDown(v) dropdownPopup?.showAsDropDown(v)
@@ -166,22 +167,22 @@ class GoodsStoreDialog(
private fun confirmInputData() { private fun confirmInputData() {
val unit = binding.tvProcurementUnit.text.trim().toString() val unit = binding.tvProcurementUnit.text.trim().toString()
if (unit.isBlank()) { if (unit.isBlank()) {
context.toast("请选择单位") context.toast("请选择入库单位")
return return
} }
val countText = binding.etProcurementCount.text.trim().toString() val countText = binding.etProcurementCount.text.trim().toString()
if (countText.isBlank()) { if (countText.isBlank()) {
context.toast("请录入数量") context.toast("请录入入库数量")
return
}
val priceText = binding.tvProcurementPrice.text.trim().toString()
if (priceText.isBlank()) {
context.toast("请录入单价")
return return
} }
val amountText = binding.etProcurementAmount.text.trim().toString() val amountText = binding.etProcurementAmount.text.trim().toString()
if (amountText.isBlank()) { if (amountText.isBlank()) {
context.toast("请录入金额") context.toast("请录入入库金额")
return
}
val priceText = binding.tvProcurementPrice.text.trim().toString()
if (priceText.isBlank()) {
context.toast("请录入入库单价")
return return
} }
confirmBlock( confirmBlock(
@@ -27,7 +27,7 @@ data class GoodsAddParam(
/** /**
* 存储方式 * 存储方式
*/ */
var storageType: Int? = null, var storageType: String? = null,
/** /**
* 净材率 * 净材率
@@ -37,18 +37,18 @@ data class GoodsAddParam(
/** /**
* 库存单位id * 库存单位id
*/ */
var unitId: Int? = null, var unitId: String? = null,
/** /**
* 采购单位 * 采购单位
*/ */
var purchaseUnit: Int = 0, var purchaseUnit: String? = null,
/** /**
* 单位转换值 * 单位转换值
*/ */
var purchaseValue: Float = 0F, var purchaseValue: Float = 0F,
var purchaseValueStr: String = "", //var purchaseValueStr: String = "",
/** /**
* 采购单价 * 采购单价
@@ -119,7 +119,7 @@ data class GoodsAddParam(
val purchaseUnitStr: String val purchaseUnitStr: String
get() { get() {
if (purchaseUnit == 0) { if (purchaseUnit == null) {
return "" return ""
} }
return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: "" return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: ""
@@ -131,16 +131,16 @@ data class GoodsAddParam(
if (goodType.isNullOrBlank() || goodType == "0") { if (goodType.isNullOrBlank() || goodType == "0") {
return "请选择物品类型" return "请选择物品类型"
} }
if (storageType == null || storageType == 0) { if (storageType.isNullOrBlank()) {
return "请选择存储方式" return "请选择存储方式"
} }
if (netRate == null || netRate == 0f) { if (netRate == null || netRate == 0f) {
return "请录入净材率" return "请录入净材率"
} }
if (unitId == null || unitId == 0) { if (unitId.isNullOrBlank()) {
return "请选择库存单位" return "请选择库存单位"
} }
if (purchaseUnit == null || purchaseUnit == 0) { if (purchaseUnit.isNullOrBlank()) {
return "请选择采购单位" return "请选择采购单位"
} }
if (purchaseValue == null || purchaseValue == 0f) { if (purchaseValue == null || purchaseValue == 0f) {
@@ -15,7 +15,7 @@ data class ApiResponse<T>(
val msg: String? = "", val msg: String? = "",
val data: T? = null val data: T? = null
) { ) {
fun isSuccess(): Boolean = code == "00000" fun isSuccess(): Boolean = ("00000" == code)
val result: T? val result: T?
get() = data get() = data
@@ -139,11 +139,19 @@ interface ApiService {
/** /**
* 上传图片 * 上传图片
*/ */
// @Multipart
// @POST//("sys/common/upload")
// suspend fun uploadImage(
// @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/sys/common/upload",
// @Part("code") code: RequestBody,
// @Part file: MultipartBody.Part,
// ): ApiResponse<String>
@Multipart @Multipart
@POST//("sys/common/upload") @POST//("sys/common/upload")
suspend fun uploadImage( suspend fun uploadImage(
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/sys/common/upload", @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/upload",
@Part("code") code: RequestBody, //@Part("code") code: RequestBody,
@Part file: MultipartBody.Part, @Part file: MultipartBody.Part,
): ApiResponse<String> ): ApiResponse<String>
@@ -166,7 +174,7 @@ interface ApiService {
suspend fun selfPurchaseGoodsAdd( suspend fun selfPurchaseGoodsAdd(
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAdd", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAdd",
@Body goodsAddParam: GoodsAddParam, @Body goodsAddParam: GoodsAddParam,
): ApiResponse<SearchGoodsInfo> ): ApiResponse<String>
/** /**
* 添加物品采购单位 * 添加物品采购单位
@@ -65,19 +65,25 @@ object FoodModule {
queryFood(it, queryCount) queryFood(it, queryCount)
} }
} }
fun queryFood(bitmap: Bitmap, queryCount: Int = 15): List<String> { fun queryFood(bitmap: Bitmap, queryCount: Int = 15): List<String> {
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor( val inputTensor =
TensorImageUtils.bitmapToFloat32Tensor(
bitmap, bitmap,
NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
) )
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor() val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
val floatArray = outputTensor.dataAsFloatArray val floatArray = outputTensor.dataAsFloatArray
if (bitmap.isRecycled.not()) {
bitmap.recycle()
}
return queryFood(floatArray, queryCount) return queryFood(floatArray, queryCount)
} }
fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> { fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> {
val query: Query<Food> = box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build() val query: Query<Food> =
box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
//查询比较分数 //查询比较分数
// val tempList = query.findWithScores().sortedBy { it.score }.map { "${it.get().name}|${it.get().foodIdx}|${it.score}" } // val tempList = query.findWithScores().sortedBy { it.score }.map { "${it.get().name}|${it.get().foodIdx}|${it.score}" }
val map = mutableMapOf<String, Int>() val map = mutableMapOf<String, Int>()
@@ -113,17 +113,18 @@ class RemoteRepository @Inject constructor(
suspend fun uploadImage(uri: Uri): ApiResponse<String> { suspend fun uploadImage(uri: Uri): ApiResponse<String> {
Timber.d("uploadImage uri = $uri") Timber.d("uploadImage uri = $uri")
return safeApiCall { return safeApiCall {
val codeRequestBody = RequestBody.create( //val codeRequestBody = RequestBody.create(
MultipartBody.FORM, // MultipartBody.FORM,
"4" // "4"
) //)
val part = val part =
FileUtils.genRequestPart(context = ContextUtils.getAppContext(), imageUri = uri) FileUtils.genRequestPart(context = ContextUtils.getAppContext(), imageUri = uri)
if (part == null) { if (part == null) {
ApiResponse(code = "-1", msg = "解析图片失败") ApiResponse(code = "-1", msg = "解析图片失败")
} else { } else {
apiService.uploadImage(code = codeRequestBody, file = part) //apiService.uploadImage(code = codeRequestBody, file = part)
apiService.uploadImage(file = part)
} }
} }
} }
@@ -164,7 +165,7 @@ class RemoteRepository @Inject constructor(
/** /**
* 自采购-添加商品 * 自采购-添加商品
*/ */
suspend fun selfPurchaseGoodsAdd(goodsAddParam: GoodsAddParam): ApiResponse<SearchGoodsInfo> { suspend fun selfPurchaseGoodsAdd(goodsAddParam: GoodsAddParam): ApiResponse<String> {
return safeApiCall { return safeApiCall {
apiService.selfPurchaseGoodsAdd(goodsAddParam = goodsAddParam) apiService.selfPurchaseGoodsAdd(goodsAddParam = goodsAddParam)
} }
@@ -32,6 +32,8 @@ object SensorScaleUtils {
SensorScale.STATE_OVER_WEIGHT -> "量程溢出" SensorScale.STATE_OVER_WEIGHT -> "量程溢出"
else -> "未知" else -> "未知"
} }
weightCallback?.invoke((value * 1000).toInt())
//Timber.d("readWeight state = ${stateStr}, weight = $value") //Timber.d("readWeight state = ${stateStr}, weight = $value")
// 只使用稳定值 // 只使用稳定值
// if (state == SensorScale.STATE_STABLE) { // if (state == SensorScale.STATE_STABLE) {
@@ -52,6 +54,11 @@ object SensorScaleUtils {
}) })
} }
private var weightCallback: ((Int) -> Unit)? = null
fun addWeightListener(callback: (Int) -> Unit) {
weightCallback = callback
}
/** /**
* 开启称重 * 开启称重
* @param autoScale 是否开启自动读取 * @param autoScale 是否开启自动读取
@@ -0,0 +1,49 @@
package com.sw.inbound.utils
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.view.View
import java.util.Arrays
class MultiClickDetector(private val targetCount: Int = 10,
private val intervalMs: Long = 50) {
private var clickCount = 0
private val clickTimestamps = LongArray(targetCount)
private val handler = Handler(Looper.getMainLooper())
private lateinit var callback: () -> Unit
fun setOnMultiClickListener(view: View, action: () -> Unit) {
callback = action
view.setOnClickListener {
System.arraycopy(clickTimestamps, 1, clickTimestamps, 0, targetCount - 1)
clickTimestamps[targetCount - 1] = SystemClock.uptimeMillis()
if (clickTimestamps[0] >= SystemClock.uptimeMillis() - intervalMs) {
callback.invoke()
resetCount()
}
}
}
// 使用Handler的延迟检测方案
fun setOnDelayedMultiClickListener(view: View, action: () -> Unit) {
callback = action
view.setOnClickListener {
clickCount++
handler.removeCallbacks(resetTask)
handler.postDelayed(resetTask, intervalMs)
if (clickCount >= targetCount) {
callback.invoke()
resetCount()
}
}
}
private val resetTask = Runnable { resetCount() }
private fun resetCount() {
clickCount = 0
Arrays.fill(clickTimestamps, 0L)
}
}
@@ -25,6 +25,12 @@ class PhotoCaptureHelper(
private val onSuccess: (Uri) -> Unit = {}, private val onSuccess: (Uri) -> Unit = {},
private val onError: (String) -> Unit = {} private val onError: (String) -> Unit = {}
) { ) {
private val callbackList: MutableList<(Uri) -> Unit> = mutableListOf()
fun addSuccessCallback(callback:(Uri) -> Unit) {
if (callbackList.contains(callback).not()) {
callbackList.add(callback)
}
}
/** /**
* 拍照方法 * 拍照方法
@@ -56,6 +62,9 @@ class PhotoCaptureHelper(
val photoUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile) val photoUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile)
Timber.d("照片保存成功: $photoUri") Timber.d("照片保存成功: $photoUri")
onSuccess(photoUri) onSuccess(photoUri)
callbackList.forEach {
it(photoUri)
}
} }
override fun onError(exception: ImageCaptureException) { override fun onError(exception: ImageCaptureException) {
@@ -11,7 +11,6 @@ import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.network.LoadingState import com.sw.inbound.network.LoadingState
import com.sw.inbound.repository.RemoteRepository import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.utils.ToastUtils import com.sw.inbound.utils.ToastUtils
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -110,18 +109,18 @@ abstract class BaseViewModel(
ToastUtils.showToast(message) ToastUtils.showToast(message)
} }
fun startSensorScale() { // fun startSensorScale() {
Timber.d("开始称重") // Timber.d("开始称重")
SensorScaleUtils.startScale(callback = { weight -> // SensorScaleUtils.startScale(callback = { weight ->
_weightInfo.value = weight // _weightInfo.value = weight
handleSensorScale(weight) // handleSensorScale(weight)
}) // })
} // }
//
fun stopSensorScale() { // fun stopSensorScale() {
Timber.d("关闭称重") // Timber.d("关闭称重")
SensorScaleUtils.stopContinuousRead() // SensorScaleUtils.stopContinuousRead()
} // }
abstract fun handleSensorScale(weight: Double) abstract fun handleSensorScale(weight: Double)
@@ -239,7 +238,7 @@ abstract class BaseViewModel(
response.result response.result
?.filter { it.id.isNullOrBlank().not() && it.title.isNullOrBlank().not() } ?.filter { it.id.isNullOrBlank().not() && it.title.isNullOrBlank().not() }
?.forEach { ?.forEach {
list.add(DictType(id = it.id, value = it.title)) list.add(DictType(id = it.value, value = it.title))
} }
GlobalData.storageTypeList = list GlobalData.storageTypeList = list
} }
@@ -1,10 +1,13 @@
package com.sw.inbound.viewmodel package com.sw.inbound.viewmodel
import android.net.Uri
import android.util.Log
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sw.inbound.ext.toFormattedString import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeBigDecimal import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.ext.toSafeFloat import com.sw.inbound.ext.toSafeFloat
import com.sw.inbound.model.request.GoodsAddParam
import com.sw.inbound.model.request.PurchaseWarehouseParam import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.request.UploadInfo import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.DictType
@@ -13,6 +16,7 @@ import com.sw.inbound.model.response.PurchaseInfo
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.repository.RemoteRepository import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.ToastUtils import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.utils.ext.toJsonString
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -245,12 +249,13 @@ class ReceiptViewModel @Inject constructor(
_amountUserInput.value = boolean _amountUserInput.value = boolean
} }
private var weightCallback:((Int)->Unit)?=null //private var weightCallback: ((Int) -> Unit)? = null
fun readWeight(callback:(Int)->Unit) { //fun readWeight(callback: (Int) -> Unit) {
weightCallback = callback // weightCallback = callback
} //}
override fun handleSensorScale(weight: Double) { override fun handleSensorScale(weight: Double) {
weightCallback?.invoke((weight*1000).toInt()) // weightCallback?.invoke((weight * 1000).toInt())
// val currentItem = _selectedItem.value // val currentItem = _selectedItem.value
// //
// currentItem?.let { info -> // currentItem?.let { info ->
@@ -346,4 +351,35 @@ class ReceiptViewModel @Inject constructor(
callback(resp.data == true) callback(resp.data == true)
} }
} }
fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) {
launchWithLoading {
val resp = repository.uploadImage(imageUri)
if (!parseResponse(resp)) {
callback(null)
return@launchWithLoading
}
callback(resp.data)
}
}
fun createNewGoods(imageUri: Uri? = null, param: GoodsAddParam, callback: (Boolean) -> Unit) {
launchWithLoading {
if (imageUri != null) {
val resp = repository.uploadImage(imageUri)
if (!parseResponse(resp)) {
callback(false)
return@launchWithLoading
}
param.relativeUrl = resp.data
}
Timber.tag("ReceiptViewModel").d("createNewGoods入参:${param.toJsonString()}")
val response = repository.selfPurchaseGoodsAdd(param)
if (!parseResponse(response)) {
callback(false)
return@launchWithLoading
}
callback(true)
}
}
} }
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:color="#FFDCDCF0" android:width="2dp"/>
<corners android:radius="12dp"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:color="#ff999999" android:width="2dp"/>
<corners android:radius="12dp"/>
</shape>
</item>
</selector>
@@ -56,6 +56,7 @@
android:paddingHorizontal="20dp"> android:paddingHorizontal="20dp">
<LinearLayout <LinearLayout
android:id="@+id/layoutTop"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dp" android:layout_height="100dp"
android:gravity="center_vertical" android:gravity="center_vertical"
@@ -68,12 +69,13 @@
android:textColor="#ff333333" android:textColor="#ff333333"
android:textSize="24sp" android:textSize="24sp"
android:textStyle="bold" android:textStyle="bold"
android:paddingVertical="8dp"
tools:text="采购单号:CG2506190526" /> tools:text="采购单号:CG2506190526" />
<androidx.camera.view.PreviewView <FrameLayout
android:id="@+id/previewView" android:id="@+id/flCameraPreview"
android:layout_width="2dp" android:layout_width="1dp"
android:layout_height="2dp" android:layout_height="1dp"
android:layout_marginStart="5dp" /> android:layout_marginStart="5dp" />
<Space <Space
@@ -129,6 +131,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:overScrollMode="never" android:overScrollMode="never"
tools:listitem="@layout/list_item_receipt_goods"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="8" /> tools:itemCount="8" />
+61 -36
View File
@@ -36,50 +36,60 @@
android:layout_width="430dp" android:layout_width="430dp"
android:layout_height="322dp" android:layout_height="322dp"
android:layout_marginTop="40dp" android:layout_marginTop="40dp"
android:background="@drawable/bg_white_radius10_stroke2_dash"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/llGoodsInfo"> app:layout_constraintTop_toTopOf="@+id/llGoodsInfo"
android:background="@drawable/bg_white_radius10_stroke2_dash">
<LinearLayout <!-- <LinearLayout-->
android:id="@+id/llStartPreview" <!-- android:id="@+id/llStartPreview"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:gravity="center"-->
<!-- android:orientation="vertical"-->
<!-- android:visibility="gone">-->
<!-- <ImageView-->
<!-- android:layout_width="96dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="center"-->
<!-- android:scaleType="centerCrop"-->
<!-- android:src="@mipmap/ic_camera_gray"-->
<!-- tools:ignore="ContentDescription" />-->
<!-- <TextView-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:text="图片采集"-->
<!-- android:textColor="#ffb4b4c8"-->
<!-- android:textSize="24sp" />-->
<!-- </LinearLayout>-->
<FrameLayout
android:id="@+id/flCameraPreview"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"/>
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView <androidx.cardview.widget.CardView
android:layout_width="96dp" android:id="@+id/cvImageBg"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:layout_gravity="center" android:layout_height="match_parent"
android:scaleType="centerCrop" app:cardBackgroundColor="@color/white"
android:src="@mipmap/ic_camera_gray" app:cardCornerRadius="10dp"
tools:ignore="ContentDescription" /> android:layout_margin="3dp"
app:cardElevation="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="图片采集"
android:textColor="#ffb4b4c8"
android:textSize="24sp" />
</LinearLayout>
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="428dp"
android:layout_height="320dp"
android:layout_gravity="center"
android:visibility="gone"/>
<ImageView <ImageView
android:id="@+id/ivGoodsImage" android:id="@+id/ivGoodsImage"
android:layout_width="428dp" android:layout_width="match_parent"
android:layout_height="320dp" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</androidx.cardview.widget.CardView>
</FrameLayout> </FrameLayout>
<Button <Button
@@ -120,6 +130,20 @@
tools:ignore="UseCompatTextViewDrawableXml" /> tools:ignore="UseCompatTextViewDrawableXml" />
</LinearLayout> </LinearLayout>
<Button
android:id="@+id/btnUploadImg"
android:layout_width="210dp"
android:layout_height="70dp"
android:layout_marginTop="39dp"
android:background="@drawable/bg_white_stroke_green_ripple"
android:text="上传图片"
android:textColor="#FF14CD71"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="@id/btnTakePhoto"
app:layout_constraintStart_toStartOf="@id/btnStartPreview"
app:layout_constraintTop_toBottomOf="@id/btnTakePhoto" />
<LinearLayout <LinearLayout
android:id="@+id/llGoodsInfo" android:id="@+id/llGoodsInfo"
android:layout_width="0dp" android:layout_width="0dp"
@@ -242,7 +266,7 @@
android:id="@+id/flGoodsType" android:id="@+id/flGoodsType"
android:layout_width="432dp" android:layout_width="432dp"
android:layout_height="60dp" android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"> android:background="@drawable/bg_gray_radius10">
<TextView <TextView
android:id="@+id/tvGoodsType" android:id="@+id/tvGoodsType"
@@ -253,7 +277,7 @@
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:ellipsize="end" android:ellipsize="end"
android:hint="请选择" android:hint="请选择"
android:textColor="#ff141428" android:textColor="#ff96a0aa"
android:textColorHint="#FF96A0AA" android:textColorHint="#FF96A0AA"
android:textSize="24sp" android:textSize="24sp"
android:textStyle="bold" android:textStyle="bold"
@@ -265,7 +289,8 @@
android:layout_gravity="end|center_vertical" android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down" android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription"
android:visibility="invisible"/>
</FrameLayout> </FrameLayout>
<FrameLayout <FrameLayout
+16 -16
View File
@@ -108,21 +108,20 @@
android:background="#FFDCDCF0" android:background="#FFDCDCF0"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
<!-- <Button--> <Button
<!-- android:id="@+id/btnAddGoods"--> android:id="@+id/btnAddGoods"
<!-- android:layout_width="240dp"--> android:layout_width="240dp"
<!-- android:layout_height="80dp"--> android:layout_height="80dp"
<!-- android:background="@drawable/bg_white_stroke_blue_ripple"--> android:background="@drawable/bg_white_stroke_blue_ripple"
<!-- android:text="添加物品"--> android:text="添加物品"
<!-- android:textColor="#FF0033CC"--> android:textColor="#FF0033CC"
<!-- android:textSize="30sp"--> android:textSize="30sp"
<!-- android:textStyle="bold"--> android:textStyle="bold"
<!-- app:layout_constraintBottom_toBottomOf="parent"--> app:layout_constraintBottom_toBottomOf="parent"
<!-- app:layout_constraintEnd_toStartOf="@+id/btnConfirm"--> app:layout_constraintEnd_toStartOf="@+id/btnConfirm"
<!-- app:layout_constraintHorizontal_chainStyle="packed"--> app:layout_constraintHorizontal_chainStyle="packed"
<!-- app:layout_constraintStart_toStartOf="parent"--> app:layout_constraintStart_toStartOf="parent"
<!-- app:layout_constraintTop_toTopOf="@id/dividerLine"--> app:layout_constraintTop_toTopOf="@id/dividerLine" />
<!-- android:visibility="gone"/>-->
<Button <Button
android:id="@+id/btnConfirm" android:id="@+id/btnConfirm"
@@ -133,9 +132,10 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" android:textStyle="bold"
android:layout_marginStart="30dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/btnAddGoods"
app:layout_constraintTop_toTopOf="@id/dividerLine" /> app:layout_constraintTop_toTopOf="@id/dividerLine" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@@ -170,6 +170,7 @@
tools:ignore="Autofill,TextFields" /> tools:ignore="Autofill,TextFields" />
<TextView <TextView
android:id="@+id/tvCountUnit"
android:layout_width="70dp" android:layout_width="70dp"
android:layout_height="70dp" android:layout_height="70dp"
android:layout_gravity="end|center_vertical" android:layout_gravity="end|center_vertical"
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="428dp"
android:layout_height="320dp"
android:layout_gravity="center"/>
</merge>
@@ -4,6 +4,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp" android:layout_marginHorizontal="10dp"
android:padding="2dp" android:padding="2dp"
android:background="@drawable/bg_selector_radius12_stroke2"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<ImageView <ImageView