联调优化

This commit is contained in:
马增飞
2025-11-14 18:13:28 +08:00
parent 6e3e873764
commit 76fa364792
18 changed files with 317 additions and 251 deletions
+3
View File
@@ -153,6 +153,9 @@ dependencies {
} else { } else {
releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion") releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion")
} }
implementation("org.greenrobot:eventbus:3.3.1")
} }
apply(plugin = "io.objectbox") apply(plugin = "io.objectbox")
+33 -33
View File
@@ -1,42 +1,42 @@
{ {
"class_names": [ "class_names": [
"圆白菜[卷心菜]", "圆白菜[卷心菜,包菜]WP2025111000063",
"大白菜(代表值)", "大白菜WP2025111000064",
"大葱", "大葱WP2025111000060",
"洋葱(鲜)[葱头]", "洋葱(鲜)[葱头]WP2025111000061",
"番茄[西红柿]", "番茄WP2025110700016",
"胡萝卜(红)[金笋,丁香萝卜]", "胡萝卜WP2025110600008",
"芹菜(茎)[旱芹,药芹]", "芹菜WP2025111000065",
"茄子(代表值)", "茄子(紫皮,长)WP2025110700024",
"西兰花[绿菜花]", "西兰花[绿菜花]WP2025110700029",
"辣椒(青,尖)", "辣椒(青辣椒,螺丝椒)WP2025110700017",
"黄瓜(鲜)[胡瓜]" "黄瓜(鲜)[胡瓜]WP2025110700031"
], ],
"class_to_idx": { "class_to_idx": {
"圆白菜[卷心菜]": 0, "圆白菜[卷心菜,包菜]WP2025111000063": 0,
"大白菜(代表值)": 1, "大白菜WP2025111000064": 1,
"大葱": 2, "大葱WP2025111000060": 2,
"洋葱(鲜)[葱头]": 3, "洋葱(鲜)[葱头]WP2025111000061": 3,
"番茄[西红柿]": 4, "番茄WP2025110700016": 4,
"胡萝卜(红)[金笋,丁香萝卜]": 5, "胡萝卜WP2025110600008": 5,
"芹菜(茎)[旱芹,药芹]": 6, "芹菜WP2025111000065": 6,
"茄子(代表值)": 7, "茄子(紫皮,长)WP2025110700024": 7,
"西兰花[绿菜花]": 8, "西兰花[绿菜花]WP2025110700029": 8,
"辣椒(青,尖)": 9, "辣椒(青辣椒,螺丝椒)WP2025110700017": 9,
"黄瓜(鲜)[胡瓜]": 10 "黄瓜(鲜)[胡瓜]WP2025110700031": 10
}, },
"idx_to_class": { "idx_to_class": {
"0": "圆白菜[卷心菜]", "0": "圆白菜[卷心菜,包菜]WP2025111000063",
"1": "大白菜(代表值)", "1": "大白菜WP2025111000064",
"2": "大葱", "2": "大葱WP2025111000060",
"3": "洋葱(鲜)[葱头]", "3": "洋葱(鲜)[葱头]WP2025111000061",
"4": "番茄[西红柿]", "4": "番茄WP2025110700016",
"5": "胡萝卜(红)[金笋,丁香萝卜]", "5": "胡萝卜WP2025110600008",
"6": "芹菜(茎)[旱芹,药芹]", "6": "芹菜WP2025111000065",
"7": "茄子(代表值)", "7": "茄子(紫皮,长)WP2025110700024",
"8": "西兰花[绿菜花]", "8": "西兰花[绿菜花]WP2025110700029",
"9": "辣椒(青,尖)", "9": "辣椒(青辣椒,螺丝椒)WP2025110700017",
"10": "黄瓜(鲜)[胡瓜]" "10": "黄瓜(鲜)[胡瓜]WP2025110700031"
}, },
"embedding_dim": 512, "embedding_dim": 512,
"total_images": 770, "total_images": 770,
@@ -276,7 +276,13 @@ class FoodCollectionActivity : ComponentActivity() {
private fun image2VectorTask(bitmap: Bitmap, position: Int) { private fun image2VectorTask(bitmap: Bitmap, position: Int) {
try { try {
initBox() initBox()
val imageVector = FoodModule.bitmap2FloatArray(bitmap) val imageVector = try {
FoodModule.bitmap2FloatArray(bitmap)
} catch (e: Exception) {
e.printStackTrace()
//toast("保存失败")
return
}
box?.put( box?.put(
Food( Food(
name = searchGoodsList[clickIndex].goodsName, name = searchGoodsList[clickIndex].goodsName,
@@ -10,6 +10,7 @@ import androidx.activity.viewModels
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.lifecycle.viewModelScope
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
@@ -45,13 +46,15 @@ import com.sw.inbound.utils.ext.toJsonString
import com.sw.inbound.utils.ext.toast import com.sw.inbound.utils.ext.toast
import com.sw.inbound.viewmodel.ReceiptViewModel import com.sw.inbound.viewmodel.ReceiptViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.min import kotlin.math.min
typealias RecognizeCallback = (List<SearchGoodsInfo.Record>)->Unit typealias RecognizeCallback = (List<SearchGoodsInfo.Record>) -> Unit
@AndroidEntryPoint @AndroidEntryPoint
abstract class GoodsListActivity : ComponentActivity() { abstract class GoodsListActivity : ComponentActivity() {
@@ -147,14 +150,16 @@ abstract class GoodsListActivity : ComponentActivity() {
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
binding.root.postDelayed({ binding.root.postDelayed({
SensorScaleUtils.addWeightListener { SensorScaleUtils.addWeightListener {
try { runOnUiThread {
weightCallback?.invoke(it) try {
recognizeWeight(weight = it) weightCallback?.invoke(it)
} catch (e: Exception) { recognizeWeight(weight = it)
e.printStackTrace() } catch (e: Exception) {
e.printStackTrace()
}
} }
} }
}, 3 * 1000) }, 1 * 1000)
} }
private var weightCallback: ((weight: Int) -> Unit)? = null private var weightCallback: ((weight: Int) -> Unit)? = null
@@ -171,13 +176,13 @@ abstract class GoodsListActivity : ComponentActivity() {
// return // return
//} //}
if (weight < 200) { if (weight < 200) {
if (abs(weight) < 10) { // if (abs(weight) < 10) {
if (DialogManager.getDialogList().size == 1 && // if (DialogManager.getDialogList().size == 1 &&
DialogManager.contains("GoodsRecognizeDialog") && // DialogManager.contains("GoodsRecognizeDialog") &&
goodsRecognizeDialog?.isShowing == true) { // goodsRecognizeDialog?.isShowing == true) {
goodsRecognizeDialog?.dismiss() // goodsRecognizeDialog?.dismiss()
} // }
} // }
return return
} }
this.lastWeight = weight this.lastWeight = weight
@@ -192,7 +197,8 @@ abstract class GoodsListActivity : ComponentActivity() {
// Timber.tag(TAG).d("recognizeWeight, checkResult=true") // Timber.tag(TAG).d("recognizeWeight, checkResult=true")
// return // return
// } // }
Timber.tag(TAG).d("recognizeWeight,recognizeFoodisShowRecognizeDialog=$isShowRecognizeDialog") Timber.tag(TAG)
.d("recognizeWeight,recognizeFoodisShowRecognizeDialog=$isShowRecognizeDialog")
recognizeFood() recognizeFood()
} }
@@ -201,19 +207,29 @@ abstract class GoodsListActivity : ComponentActivity() {
private val takePhotoSuccessCallback: (Uri) -> Unit = { uri -> private val takePhotoSuccessCallback: (Uri) -> Unit = { uri ->
Thread { Thread {
searchFood(uri) try {
searchFood(uri)
} catch (e: Exception) {
e.printStackTrace()
}
}.start() }.start()
} }
fun delayRecognizeFood() { fun delayRecognizeFood() {
window.decorView.postDelayed({ if (abs(lastWeight) < 10) {
return
}
window.decorView.postDelayed(
{
recognizeFood() recognizeFood()
}, },
DELAY_TIME.toLong()) DELAY_TIME.toLong()
)
} }
fun recognizeFood() { fun recognizeFood() {
if (isShowRecognizeDialog.not()) { if (isShowRecognizeDialog.not()) {
if(goodsRecognizeDialog == null) { if (goodsRecognizeDialog == null) {
isShowRecognizeDialog = true isShowRecognizeDialog = true
} }
return return
@@ -231,7 +247,7 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
} }
private var recognizeCallback:RecognizeCallback?=null private var recognizeCallback: RecognizeCallback? = null
var isAgainRecognize = false var isAgainRecognize = false
fun againRecognizeFood(callback: RecognizeCallback) { fun againRecognizeFood(callback: RecognizeCallback) {
@@ -267,33 +283,47 @@ abstract class GoodsListActivity : ComponentActivity() {
targetWidth = 1000, targetHeight = 1300, targetWidth = 1000, targetHeight = 1300,
offsetX = 30, offsetY = 100 offsetX = 30, offsetY = 100
) )
val file = BitmapSaver.saveToAppFilesDir( if (bitmap.isRecycled.not()) {
newBmp, bitmap.recycle()
this, }
"IMG_CROP_${System.currentTimeMillis()}.jpg" // val file = BitmapSaver.saveToAppFilesDir(
) // newBmp,
Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}") // this,
//val foodList = FoodModule.queryFood(newBmp) // "IMG_CROP_${System.currentTimeMillis()}.jpg"
// )
// Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}")
//var foodList = FoodModule.queryFood(newBmp)
//物品编号
//foodList = foodList.map { "WP"+it.split("WP")[1] }
//物品名称
//foodList = foodList.map { it.split("WP")[0] }
val foodList = FoodModule.getFoodScoreList(newBmp) val foodList = FoodModule.getFoodScoreList(newBmp)
runOnUiThread { if (newBmp.isRecycled.not()) {
if (foodList.isEmpty()) { newBmp.recycle()
handleGoodsResult() }
return@runOnUiThread if (foodList.isEmpty()) {
} recognizeFoodError()
viewModel.recognizeGoodsList( return@let
//nameList = foodList, }
scoreList = foodList, foodList.forEach {
) { goodsList -> it.name = it.name.split("WP")[0]
}
viewModel.recognizeGoodsList(
//nameList = foodList,
scoreList = foodList,
) { goodsList ->
runOnUiThread {
if (isAgainRecognize) { if (isAgainRecognize) {
Loading.dismiss() Loading.dismiss()
recognizeCallback?.invoke(goodsList) recognizeCallback?.invoke(goodsList)
isAgainRecognize = false isAgainRecognize = false
return@recognizeGoodsList return@runOnUiThread
} }
handleGoodsResult( handleGoodsResult(
goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(), goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(),
file = file, // file = null,
name = foodList.joinToString(",") // name = foodList.joinToString(",")
) )
} }
} }
@@ -302,8 +332,8 @@ abstract class GoodsListActivity : ComponentActivity() {
private fun handleGoodsResult( private fun handleGoodsResult(
goodsList: List<SearchGoodsInfo.Record> = mutableListOf(), goodsList: List<SearchGoodsInfo.Record> = mutableListOf(),
file: File?=null, file: File? = null,
name: String?=null, name: String? = null,
) { ) {
runOnUiThread { runOnUiThread {
if (goodsRecognizeDialog?.isShowing == true) { if (goodsRecognizeDialog?.isShowing == true) {
@@ -383,7 +413,8 @@ abstract class GoodsListActivity : ComponentActivity() {
val finalWeight = item.goodsWeight?.toDouble().plus2(goods.goodsWeight?.toDouble()) val finalWeight = item.goodsWeight?.toDouble().plus2(goods.goodsWeight?.toDouble())
val finalNum = item.receivedNum.plus2(goods.receivedNum) val finalNum = item.receivedNum.plus2(goods.receivedNum)
val finalAmount = item.recPriceInItem.plus2(goods.recPriceInItem) val finalAmount = item.recPriceInItem.plus2(goods.recPriceInItem)
val finalPrice = if (finalAmount == 0.toDouble() || finalNum == 0.toDouble()) 0.toDouble() else finalAmount / finalNum val finalPrice =
if (finalAmount == 0.toDouble() || finalNum == 0.toDouble()) 0.toDouble() else finalAmount / finalNum
item.run { item.run {
receivedNum = finalNum receivedNum = finalNum
recUnitPriceTaxIn = finalPrice.roundedDecimalPlace(2) recUnitPriceTaxIn = finalPrice.roundedDecimalPlace(2)
@@ -453,7 +484,10 @@ abstract class GoodsListActivity : ComponentActivity() {
val count = goodsList.count { it.isLocalGoods } val count = goodsList.count { it.isLocalGoods }
// 处理返回事件 // 处理返回事件
if (count > 0) { if (count > 0) {
WarnDialog(context = this@GoodsListActivity, content = "存在未收货的物品,请确认是否放弃收货,若放弃则数据不会保存?") { WarnDialog(
context = this@GoodsListActivity,
content = "存在未收货的物品,请确认是否放弃收货,若放弃则数据不会保存?"
) {
//onBackPressedDispatcher.onBackPressed() //onBackPressedDispatcher.onBackPressed()
finish() finish()
}.show() }.show()
@@ -531,18 +565,18 @@ abstract class GoodsListActivity : ComponentActivity() {
} }
} }
fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { // fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) {
viewModel.uploadImage(imageUri) { imgUrl -> // viewModel.uploadImage(imageUri) { imgUrl ->
if (imgUrl.isNullOrBlank()) { // if (imgUrl.isNullOrBlank()) {
callback(null) // callback(null)
return@uploadImage // return@uploadImage
} // }
callback(imgUrl) // callback(imgUrl)
} // }
} // }
fun createNewGoods(imageUri: Uri, param: GoodsAddParam, callback: (Boolean) -> Unit) { fun createNewGoods(file: File, param: GoodsAddParam, callback: (Boolean) -> Unit) {
viewModel.uploadImage(imageUri) { imgUrl -> viewModel.uploadImage(file) { imgUrl ->
if (imgUrl.isNullOrBlank()) { if (imgUrl.isNullOrBlank()) {
toast("图片上传失败") toast("图片上传失败")
return@uploadImage return@uploadImage
@@ -551,4 +585,15 @@ abstract class GoodsListActivity : ComponentActivity() {
viewModel.createNewGoods(param = param, callback = callback) viewModel.createNewGoods(param = param, callback = callback)
} }
} }
private fun recognizeFoodError() {
if (isAgainRecognize) {
Loading.dismiss()
recognizeCallback?.invoke(mutableListOf())
isAgainRecognize = false
} else {
handleGoodsResult()
}
}
} }
@@ -19,7 +19,10 @@ import com.sw.inbound.ext.toSafeBigDecimal
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.GoodsAddParam
import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.DictType
import com.sw.inbound.utils.BitmapCropper
import com.sw.inbound.utils.BitmapSaver
import com.sw.inbound.utils.CameraUtils import com.sw.inbound.utils.CameraUtils
import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.ext.dp import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.gone import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.toast import com.sw.inbound.utils.ext.toast
@@ -46,6 +49,7 @@ class AddGoodsDialog(
private val cameraUtils: CameraUtils by lazy { private val cameraUtils: CameraUtils by lazy {
CameraUtils(activity!!) CameraUtils(activity!!)
} }
override fun show() { override fun show() {
super.show() super.show()
cameraUtils.setPreviewController(previewView) cameraUtils.setPreviewController(previewView)
@@ -71,7 +75,10 @@ class AddGoodsDialog(
} }
cameraUtils.initCamera() cameraUtils.initCamera()
val previewBinding = val previewBinding =
LayoutCameraPreviewBinding.inflate(LayoutInflater.from(context), binding.flCameraPreview) LayoutCameraPreviewBinding.inflate(
LayoutInflater.from(context),
binding.flCameraPreview
)
previewBinding.previewView.let { previewBinding.previewView.let {
it.updateLayoutParams { it.updateLayoutParams {
width = 428.dp width = 428.dp
@@ -98,9 +105,9 @@ class AddGoodsDialog(
cameraUtils.takePhoto(takePhotoCallback) cameraUtils.takePhoto(takePhotoCallback)
} }
binding.btnUploadImg.gone() binding.btnUploadImg.gone()
binding.btnUploadImg.setOnClickListener { // binding.btnUploadImg.setOnClickListener {
uploadImage() // uploadImage()
} // }
binding.tvGoodsType.let { tv -> binding.tvGoodsType.let { tv ->
tv.text = "原材料" tv.text = "原材料"
tv.tag = GlobalData.goodsTypeList.firstOrNull { it.value == "原材料" }?.id tv.tag = GlobalData.goodsTypeList.firstOrNull { it.value == "原材料" }?.id
@@ -111,7 +118,7 @@ class AddGoodsDialog(
textView = binding.tvProcurementUnit, textView = binding.tvProcurementUnit,
arrowImage = binding.ivProcurementArrow, arrowImage = binding.ivProcurementArrow,
list = GlobalData.unitTypeList, list = GlobalData.unitTypeList,
height = 2*71.dp height = 2 * 71.dp
) )
// showDropDownList( // showDropDownList(
// binding.flGoodsType, // binding.flGoodsType,
@@ -129,7 +136,7 @@ class AddGoodsDialog(
textView = binding.tvWarehouseUnit, textView = binding.tvWarehouseUnit,
arrowImage = binding.ivWarehouseArrow, arrowImage = binding.ivWarehouseArrow,
list = GlobalData.unitTypeList, list = GlobalData.unitTypeList,
height = 3*71.dp height = 3 * 71.dp
) { ) {
binding.tvSelectUseUnit.text = it.value binding.tvSelectUseUnit.text = it.value
binding.tvSelectProcurementUnit.text = it.value binding.tvSelectProcurementUnit.text = it.value
@@ -144,7 +151,7 @@ class AddGoodsDialog(
height: Int = 355.dp, height: Int = 355.dp,
block: (DictType) -> Unit = {} block: (DictType) -> Unit = {}
) { ) {
dropdownView.setOnClickListener {v-> dropdownView.setOnClickListener { v ->
dropdownList.clear() dropdownList.clear()
val tempList = val tempList =
list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() } list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
@@ -238,31 +245,51 @@ class AddGoodsDialog(
purchaseValue = goodsCount.toSafeFloat(), purchaseValue = goodsCount.toSafeFloat(),
purchasePrice = goodsPrice.toSafeBigDecimal(), purchasePrice = goodsPrice.toSafeBigDecimal(),
) )
activity?.createNewGoods(imageUri!!, param) { activity?.let {
if (it.not()) { Loading.show(it)
context.toast("新增物品失败") }
return@createNewGoods ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap ->
val newBmp = BitmapCropper.cropCenter(
original = bitmap,
targetWidth = 1000, targetHeight = 1300,
offsetX = 30, offsetY = 100
)
val file = BitmapSaver.saveToAppFilesDir(
newBmp,
context,
"IMG_CROP_${System.currentTimeMillis()}.jpg"
)
if(file == null) {
context.toast("请重新拍照后再试")
Loading.dismiss()
return@let
}
activity?.createNewGoods(file, param) {
Loading.dismiss()
if (it.not()) {
context.toast("新增物品失败")
return@createNewGoods
}
context.toast("新增物品成功")
confirmBlock(goodsName)
dismiss()
} }
context.toast("新增物品成功")
confirmBlock(goodsName)
dismiss()
} }
} }
private var imageUri: Uri? = null private var imageUri: Uri? = null
private fun uploadImage() { // private fun uploadImage() {
if (imageUri == null) { // if (imageUri == null) {
context.toast("请采集图片") // context.toast("请采集图片")
return // return
} // }
activity?.uploadImage(imageUri!!) { imgUrl -> // activity?.uploadImage(imageUri!!) { imgUrl ->
if (imgUrl.isNullOrBlank()) { // if (imgUrl.isNullOrBlank()) {
context.toast("图片上传失败") // context.toast("图片上传失败")
return@uploadImage // return@uploadImage
} // }
context.toast(imgUrl) // context.toast(imgUrl)
} // }
} // }
} }
@@ -151,7 +151,7 @@ class CollectSearchDialog(
confirmBlock = { confirmBlock = {
Thread { Thread {
activity?.runOnUiThread { activity?.runOnUiThread {
Loading.show(context) Loading.show(activity!!)
} }
val name = list[position].goodsName val name = list[position].goodsName
val filterIdList = box?.all?.filter { it.name == name }?.map { it.id } val filterIdList = box?.all?.filter { it.name == name }?.map { it.id }
@@ -191,7 +191,7 @@ class CollectSearchDialog(
list.clear() list.clear()
var queryList = box?.all?.distinctBy { it.name } var queryList = box?.all?.distinctBy { it.name }
if (searchName.isNullOrBlank().not()) { if (searchName.isNullOrBlank().not()) {
queryList = queryList?.filter { it.name?.contains(searchName) == true } queryList = queryList?.filter { it.name?.contains(searchName!!) == true }
} }
queryList?.forEach { queryList?.forEach {
list.add((SearchGoodsInfo.Record(goodsName = it.name))) list.add((SearchGoodsInfo.Record(goodsName = it.name)))
@@ -88,14 +88,14 @@ class GoodsRecognizeDialog(
binding.btnAgainRecognize.setOnClickListener { binding.btnAgainRecognize.setOnClickListener {
//dismiss() //dismiss()
activity?.againRecognizeFood { goodsList -> activity?.againRecognizeFood { goodsList ->
binding.rvRecognize.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
list.clear() list.clear()
list.addAll(goodsList) list.addAll(goodsList)
recognizeAdapter.notifyDataSetChanged()
if (recognizeAdapter.list.isEmpty()) { if (recognizeAdapter.list.isEmpty()) {
loadEmptyView() loadEmptyView()
return@againRecognizeFood return@againRecognizeFood
} }
binding.rvRecognize.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
recognizeAdapter.notifyDataSetChanged()
} }
} }
} }
@@ -10,7 +10,6 @@ import android.text.style.StyleSpan
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
import android.widget.FrameLayout
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
@@ -25,7 +24,6 @@ import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.databinding.DialogGoodsStoreBinding import com.sw.inbound.databinding.DialogGoodsStoreBinding
import com.sw.inbound.databinding.LayoutImagePreviewBinding import com.sw.inbound.databinding.LayoutImagePreviewBinding
import com.sw.inbound.databinding.LayoutTakePhotoBinding import com.sw.inbound.databinding.LayoutTakePhotoBinding
import com.sw.inbound.ext.toFormattedString
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
@@ -97,6 +95,9 @@ class GoodsStoreDialog(
binding.btnConfirm.setOnClickListener { binding.btnConfirm.setOnClickListener {
confirmInputData() confirmInputData()
} }
binding.tvTitle.setOnClickListener {
SensorScaleUtils.startScale(autoScale = true)
}
// binding.ivAddUnit.setOnClickListener { // binding.ivAddUnit.setOnClickListener {
// AddProcurementUnitDialog(context).show() // AddProcurementUnitDialog(context).show()
// } // }
@@ -124,13 +125,12 @@ class GoodsStoreDialog(
} }
} }
val first = goods.unitVoList!!.first { it.businessUnitId == dictType.id } val first = goods.unitVoList!!.first { it.businessUnitId == dictType.id }
val stringBuilder = StringBuilder() val stringBuilder =
.append("1").append(dictType.value).append("=") StringBuilder().append("1").append(dictType.value).append("=")
.append(first.purchaseValue!!.toInt().toString()) .append(first.purchaseValue!!.toInt().toString())
.append(goods.kcUnitName) .append(goods.kcUnitName).append("").append("1")
.append("") .append(goods.kcUnitName).append("=").append(first.consumeValue)
.append("1").append(goods.kcUnitName).append("=") .append("")
.append(first.consumeValue).append("")
binding.tvUnitCalculate.text = stringBuilder.toString() binding.tvUnitCalculate.text = stringBuilder.toString()
//val count = getUnitCount(dictType.id!!) //val count = getUnitCount(dictType.id!!)
//if (count.isBlank() || "0" == count) { //if (count.isBlank() || "0" == count) {
@@ -268,9 +268,7 @@ class GoodsStoreDialog(
StyleSpan(Typeface.BOLD) StyleSpan(Typeface.BOLD)
) )
appendText( appendText(
"", "", ForegroundColorSpan("#FF000033".toColorInt()), StyleSpan(Typeface.BOLD)
ForegroundColorSpan("#FF000033".toColorInt()),
StyleSpan(Typeface.BOLD)
) )
} }
} }
@@ -375,6 +373,9 @@ class GoodsStoreDialog(
} }
} }
} }
binding.root.postDelayed({
SensorScaleUtils.startScale()
}, 2600)
} }
private var imageUri: Uri? = null private var imageUri: Uri? = null
@@ -435,8 +436,10 @@ class GoodsStoreDialog(
ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap -> ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap ->
val cropBitmap = BitmapCropper.cropCenter( val cropBitmap = BitmapCropper.cropCenter(
original = bitmap, original = bitmap,
targetWidth = 1000, targetHeight = 1300, targetWidth = 1000,
offsetX = 30, offsetY = 100 targetHeight = 1300,
offsetX = 30,
offsetY = 100
) )
val file = BitmapSaver.saveToAppFilesDir( val file = BitmapSaver.saveToAppFilesDir(
cropBitmap, context, "IMG_CROP_${System.currentTimeMillis()}.jpg" cropBitmap, context, "IMG_CROP_${System.currentTimeMillis()}.jpg"
@@ -448,7 +451,11 @@ class GoodsStoreDialog(
Thread { Thread {
try { try {
val imageVector = FoodModule.bitmap2FloatArray(bitmap) val imageVector = FoodModule.bitmap2FloatArray(bitmap)
box?.put(Food(name = goods.goodsName, foodIdx = 0, foodVector = imageVector)) box?.put(
Food(
name = goods.goodsName, foodIdx = 0, foodVector = imageVector
)
)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@@ -1,26 +1,30 @@
package com.sw.inbound.dialog package com.sw.inbound.dialog
import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.WindowManager
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import com.sw.inbound.R import com.sw.inbound.R
import com.sw.inbound.databinding.DialogLoadingBinding import com.sw.inbound.databinding.DialogLoadingBinding
import kotlin.let
import kotlin.run
object Loading { object Loading {
private var dialog: LoadingDialog? = null private var dialog: LoadingDialog? = null
fun show(context: Context) { fun show(activity: Activity) {
try { try {
if (activity.isFinishing || activity.isDestroyed) {
return
}
if (dialog?.isShowing == true) { if (dialog?.isShowing == true) {
dialog?.dismiss() dialog?.dismiss()
} }
if (dialog == null) { if (dialog == null) {
dialog = LoadingDialog(context) dialog = LoadingDialog(activity)
} }
dialog?.show() dialog?.show()
} catch (e: Exception) { } catch (e: Exception) {
@@ -56,10 +60,10 @@ class LoadingDialog(
setCanceledOnTouchOutside(true) setCanceledOnTouchOutside(true)
window?.run { window?.run {
setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
//setFlags( // setFlags(
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//) // )
} }
setOnDismissListener { setOnDismissListener {
onDismiss() onDismiss()
@@ -67,83 +71,3 @@ class LoadingDialog(
} }
} }
//class LoadingDialog3(
// private val activity: Activity,
// private val message: String = "加载中……",
// private val onDismiss: () -> Unit = {}
//) : DialogFragment() {
//
// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// return SafeDialog(
// activity = activity,
// themeResId = R.style.ToastDialogTheme,
// ).apply {
// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
// binding.tvMessage.text = message
// setContentView(binding.root)
// setCancelable(true)
// window?.run {
// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
// setFlags(
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// );
// }
// setOnDismissListener {
// onDismiss()
// }
// }
// }
//
// override fun dismiss() {
// super.dismiss()
// }
//
// override fun show(manager: FragmentManager, tag: String?) {
// runCatching {
// super.show(manager, tag)
// Handler(Looper.getMainLooper()).postDelayed({
// super.dismiss()
// }, 800)
// }.onFailure {
// it.printStackTrace()
// }
// }
//
//}
//class LoadingDialog(
// private val activity: Activity,
// private val message: String = "加载中……",
// private val onDismiss: () -> Unit = {}
//) : SafeDialog(
// activity = activity,
// themeResId = R.style.ToastDialogTheme,
//) {
//
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
// binding.tvMessage.text = message
// setContentView(binding.root)
// setCancelable(true)
// window?.run {
// setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
// setFlags(
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// );
// }
// setOnDismissListener {
// onDismiss()
// }
// }
//
// fun show(manager: FragmentManager, tag: String?) {
// show()
// Handler(Looper.getMainLooper()).postDelayed({
// super.dismiss()
// }, 800)
// }
//
//}
@@ -61,14 +61,8 @@ object FoodModule {
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()
// return floatArrayOf()
val floatArray = outputTensor.dataAsFloatArray val floatArray = outputTensor.dataAsFloatArray
// try {
// if (bitmap.isRecycled.not()) {
// bitmap.recycle()
// }
// } catch (e: Exception) {
// e.printStackTrace()
// }
return floatArray return floatArray
} }
@@ -110,8 +104,13 @@ object FoodModule {
} }
fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> { fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val floatArray = bitmap2FloatArray(bitmap) val floatArray = bitmap2FloatArray(bitmap)
// return emptyList()
val nameScoreList = queryFoodNameScore(floatArray, queryCount) val nameScoreList = queryFoodNameScore(floatArray, queryCount)
val maxScoreList = nameScoreList.groupBy { it.name }.map { (_, value) -> value.minByOrNull { it.score }!! }.toMutableList() val maxScoreList = nameScoreList
.filter { it.score < 0.20 }
.groupBy { it.name }
.map { (_, value) -> value.minByOrNull { it.score }!! }
.toMutableList()
val map = mutableMapOf<String, Int>() val map = mutableMapOf<String, Int>()
nameScoreList.forEach { nameScoreList.forEach {
val key = it.name val key = it.name
@@ -142,7 +141,7 @@ object FoodModule {
data class IdNameScore( data class IdNameScore(
val id:Long, val id:Long,
val name:String, var name:String,
val score: Double val score: Double
) )
@@ -20,6 +20,7 @@ import com.sw.inbound.network.api.ApiService
import com.sw.inbound.utils.ContextUtils import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.FileUtils import com.sw.inbound.utils.FileUtils
import timber.log.Timber import timber.log.Timber
import java.io.File
import javax.inject.Inject import javax.inject.Inject
/** /**
@@ -126,6 +127,22 @@ class RemoteRepository @Inject constructor(
} }
} }
} }
suspend fun uploadImage(file:File): ApiResponse<String> {
return safeApiCall {
//val codeRequestBody = RequestBody.create(
// MultipartBody.FORM,
// "4"
//)
val part = FileUtils.genRequestPart(file)
if (part == null) {
ApiResponse(code = "-1", msg = "解析图片失败")
} else {
//apiService.uploadImage(code = codeRequestBody, file = part)
apiService.uploadImage(file = part)
}
}
}
/** /**
* 部分收货 * 部分收货
@@ -2,12 +2,17 @@ package com.sw.inbound.sdk
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import com.sw.inbound.utils.MessageEvent
import com.sw.inbound.utils.ThreadUtils
import com.sw.inbound.utils.ToastUtils import com.sw.inbound.utils.ToastUtils
import com.wabon.wbintelligenthardwaresdk.api.SensorScale import com.wabon.wbintelligenthardwaresdk.api.SensorScale
import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult
import kotlinx.coroutines.delay
import org.greenrobot.eventbus.EventBus
import timber.log.Timber import timber.log.Timber
import kotlin.math.roundToInt import kotlin.math.roundToInt
typealias WeightCallback = (Int) -> Unit typealias WeightCallback = (Int) -> Unit
/** /**
@@ -18,18 +23,24 @@ object SensorScaleUtils {
const val serialPort = "/dev/ttyS7" const val serialPort = "/dev/ttyS7"
const val baudRate = 115200 const val baudRate = 115200
private var mSensorScale: SensorScale? = null private var mSensorScale: SensorScale? = null
var isValidWeight = false
private fun init() { private fun init() {
if (mSensorScale != null) {
return
}
mSensorScale = SensorScale(object : OnScaleResult { mSensorScale = SensorScale(object : OnScaleResult {
/** /**
* 读取重量 * 读取重量
*/ */
override fun readWeight(state: Int, value: Double) { override fun readWeight(state: Int, value: Double) {
Handler(Looper.getMainLooper()).post { isValidWeight = true
callbackList.forEach { callbackList.forEach {
it.invoke((value * 1000).roundToInt()) it.invoke((value * 1000).roundToInt())
}
} }
// EventBus.getDefault().post(MessageEvent((value * 1000).roundToInt()))
} }
/** /**
@@ -40,9 +51,11 @@ object SensorScaleUtils {
} }
override fun fail(errCode: Int) { override fun fail(errCode: Int) {
isValidWeight = false
Timber.e("fail code = $errCode") Timber.e("fail code = $errCode")
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
ToastUtils.showToast("秤读取数据异常") ToastUtils.showToast("秤读取数据异常")
startScale()
} }
} }
}) })
@@ -61,15 +74,16 @@ object SensorScaleUtils {
init() init()
mSensorScale?.openScale(serialPort, baudRate) { open -> mSensorScale?.openScale(serialPort, baudRate) { open ->
if (open && autoScale) { if (open && autoScale) {
Handler(Looper.getMainLooper()).postDelayed({ // Handler(Looper.getMainLooper()).postDelayed({
mSensorScale?.readWeight() // mSensorScale?.readWeight()
mSensorScale?.startContinuousRead() // mSensorScale?.startContinuousRead()
}, 1500) // }, 1500)
// ThreadUtils.launchOnIo { ThreadUtils.launchOnIo {
// delay(1000) delay(1000)
// // 打开后需要等待后才能调用,否则会 1001 SDK未初始化 // 打开后需要等待后才能调用,否则会 1001 SDK未初始化
// mSensorScale?.startContinuousRead() mSensorScale?.readWeight()
// } mSensorScale?.startContinuousRead()
}
} }
} }
} }
@@ -1,5 +1,6 @@
package com.sw.inbound.utils package com.sw.inbound.utils
import android.graphics.Bitmap import android.graphics.Bitmap
import android.util.DisplayMetrics
object BitmapCropper { object BitmapCropper {
/** /**
@@ -22,8 +23,11 @@ object BitmapCropper {
startY = startY.coerceAtLeast(0) startY = startY.coerceAtLeast(0)
val actualWidth = minOf(targetWidth, originalWidth - startX) val actualWidth = minOf(targetWidth, originalWidth - startX)
val actualHeight = minOf(targetHeight, originalHeight - startY) val actualHeight = minOf(targetHeight, originalHeight - startY)
return Bitmap.createBitmap(original, startX, startY, actualWidth, actualHeight) return Bitmap.createBitmap(original, startX, startY, actualWidth, actualHeight).also {
// it.setConfig(Bitmap.Config.RGB_565)
// it.density = DisplayMetrics.DENSITY_LOW
}
} }
} }
@@ -27,7 +27,7 @@ object BitmapSaver {
context: Context, context: Context,
fileName: String, fileName: String,
format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG, format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG,
quality: Int = 100 quality: Int = 10
): File? { ): File? {
//val dir = context.getExternalFilesDir(null) //val dir = context.getExternalFilesDir(null)
val dir = context.cacheDir val dir = context.cacheDir
@@ -51,6 +51,9 @@ object FileUtils {
Timber.d("genRequestPart imageUri = $imageUri") Timber.d("genRequestPart imageUri = $imageUri")
// 1. 从Uri获取文件 // 1. 从Uri获取文件
val file = getFileFromUri(context, imageUri) val file = getFileFromUri(context, imageUri)
return genRequestPart(file)
}
fun genRequestPart(file: File?): MultipartBody.Part? {
if (file == null) { if (file == null) {
Timber.e("getFileFromUri file is null") Timber.e("getFileFromUri file is null")
return null return null
@@ -6,9 +6,11 @@ import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
object ImageUtil { object ImageUtil {
fun uriToBitmap(context: Context, uri: Uri): Bitmap? { fun uriToBitmap(context: Context, uri: Uri): Bitmap? {
return try { return try {
val options = BitmapFactory.Options()
options.inSampleSize = 10; // 这会将图片的尺寸缩小到原来的1/2
options.inPreferredConfig = Bitmap.Config.RGB_565
context.contentResolver.openInputStream(uri)?.use { stream -> context.contentResolver.openInputStream(uri)?.use { stream ->
BitmapFactory.decodeStream(stream) BitmapFactory.decodeStream(stream)
} }
@@ -10,6 +10,7 @@ import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.ext.toJsonString import com.sw.inbound.utils.ext.toJsonString
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import timber.log.Timber import timber.log.Timber
import java.io.File
import javax.inject.Inject import javax.inject.Inject
/** /**
@@ -335,9 +336,20 @@ class ReceiptViewModel @Inject constructor(
} }
} }
fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) { // fun uploadImage(imageUri: Uri, callback: (String?) -> Unit) {
// launchWithLoading {
// val resp = repository.uploadImage(imageUri)
// if (!parseResponse(resp)) {
// callback(null)
// return@launchWithLoading
// }
// callback(resp.data)
// }
// }
fun uploadImage(file:File, callback: (String?) -> Unit) {
launchWithLoading { launchWithLoading {
val resp = repository.uploadImage(imageUri) val resp = repository.uploadImage(file)
if (!parseResponse(resp)) { if (!parseResponse(resp)) {
callback(null) callback(null)
return@launchWithLoading return@launchWithLoading
@@ -365,4 +377,6 @@ class ReceiptViewModel @Inject constructor(
callback(true) callback(true)
} }
} }
} }
@@ -10,6 +10,7 @@
tools:ignore="HardcodedText"> tools:ignore="HardcodedText">
<TextView <TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="14" android:layout_weight="14"