From 9a5258ad340655a0807f31f27b75a5a29a8ce1fb Mon Sep 17 00:00:00 2001 From: mazengfei <331023091@qq.com> Date: Tue, 3 Mar 2026 15:39:11 +0800 Subject: [PATCH] =?UTF-8?q?=20=E6=90=9C=E7=B4=A2=E8=8F=9C=E5=93=81?= =?UTF-8?q?=E5=85=A5=E5=BA=93=E6=94=B9=E4=B8=BA=E8=87=AA=E5=8A=A8=E6=8B=8D?= =?UTF-8?q?=E7=85=A7=E4=BF=9D=E5=AD=98,=E5=8F=96=E6=B6=88=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E6=8B=8D=E7=85=A7=E6=93=8D=E4=BD=9C;=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=90=91=E9=87=8F=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sw/inbound/activity/GoodsListActivity.kt | 18 +++-- .../inbound/activity/PurchaseOrderActivity.kt | 5 ++ .../sw/inbound/dialog/GoodsSearchDialog.kt | 6 +- .../com/sw/inbound/dialog/GoodsStoreDialog.kt | 81 ++++++++++--------- .../java/com/sw/inbound/objbox/FoodModule.kt | 21 +++-- .../java/com/sw/inbound/objbox/ObjectBox.kt | 5 ++ .../java/com/sw/inbound/utils/CameraUtils.kt | 10 ++- .../java/com/sw/inbound/utils/CrashHandler.kt | 43 +--------- .../java/com/sw/inbound/utils/LogSaveUtil.kt | 60 ++++++++++++++ app/src/main/res/layout/layout_take_photo.xml | 3 +- 10 files changed, 157 insertions(+), 95 deletions(-) create mode 100644 app/src/main/java/com/sw/inbound/utils/LogSaveUtil.kt diff --git a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt index 0920a23..5ad2b27 100644 --- a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt +++ b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt @@ -47,6 +47,7 @@ import com.sw.inbound.utils.BitmapCropper import com.sw.inbound.utils.CameraUtils import com.sw.inbound.utils.DateTimeUtils import com.sw.inbound.utils.ImageUtil +import com.sw.inbound.utils.LogSaveUtil import com.sw.inbound.utils.PreciseDelayHandler import com.sw.inbound.utils.ext.dp import com.sw.inbound.utils.ext.gone @@ -229,7 +230,7 @@ abstract class GoodsListActivity : ComponentActivity() { private var lastWeight = 0 private fun recognizeWeight(weight: Int) { - Timber.tag(TAG).d("recognizeWeight,lastWeight=$lastWeight,weight=$weight") + logInfo("recognizeWeight,lastWeight=$lastWeight,weight=$weight") //if (this.lastWeight - weight >= 0) { // this.lastWeight = weight // //从秤上取物品中 @@ -265,8 +266,7 @@ abstract class GoodsListActivity : ComponentActivity() { // Timber.tag(TAG).d("recognizeWeight, checkResult=true") // return // } - Timber.tag(TAG) - .d("recognizeWeight,recognizeFood:isShowRecognizeDialog=$isShowRecognizeDialog") + logInfo("recognizeWeight,recognizeFood:isShowRecognizeDialog=$isShowRecognizeDialog") //两次相差5克内视作重量未变,不进行重新识别 if (abs(lastWeight - weight) > 5) { recognizeFood() @@ -650,8 +650,7 @@ abstract class GoodsListActivity : ComponentActivity() { supplierId = supplierId, receiveGoodsInfos = goodsList ) - Timber.tag("SelfProcurementActivity") - .d("receiptSubmit确认收货提交数据:${uploadInfo.toJsonString()}") + logInfo("receiptSubmit确认收货提交数据:${uploadInfo.toJsonString()}") showWaitingDialog2("加载中") receiptViewModel.confirmReceipt(uploadInfo) { success -> hideWaitingDialog() @@ -690,8 +689,7 @@ abstract class GoodsListActivity : ComponentActivity() { buyToInventoryValue = it.buyToInventoryValue ?: "" ) } - Timber.tag("SelfProcurementActivity") - .d("selfProcurementSubmit自采入库提交数据:${submitData.toJsonString()}") + logInfo("selfProcurementSubmit自采入库提交数据:${submitData.toJsonString()}") showWaitingDialog2("加载中") receiptViewModel.addToWarehouse(submitData) { success -> hideWaitingDialog() @@ -796,4 +794,10 @@ abstract class GoodsListActivity : ComponentActivity() { tvTip?.text = tip } } + + private fun logInfo(msg:String) { + Timber.tag(TAG).d(msg) + LogSaveUtil.saveLogFile(msg) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt b/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt index d895c92..c13a034 100644 --- a/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt +++ b/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt @@ -64,6 +64,10 @@ class PurchaseOrderActivity : ComponentActivity() { putExtra(GoodsListActivity.IS_RECEIPT_PAGE, false) } } + } + + override fun onResume() { + super.onResume() Loading.show(this) viewModel.getOrderListNew(pageNum = 1, pageSize = 100) { suppliers -> runOnUiThread { @@ -82,6 +86,7 @@ class PurchaseOrderActivity : ComponentActivity() { binding.layoutEmptyView.visible() return } + list.clear() list.addAll(suppliers) adapter.notifyDataSetChanged() binding.rvOrderList.visible() diff --git a/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt b/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt index a5fd225..0890017 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsSearchDialog.kt @@ -32,9 +32,13 @@ class GoodsSearchDialog( override fun initView() { activity = getReceiptActivity() binding.ivClose.setOnClickListener { dismiss() } - binding.ivGoodsSearch.setOnClickListener { searchGoods() } + binding.ivGoodsSearch.setOnClickListener { + pageNo = 1 + searchGoods() + } binding.etInputGoods.let { v -> v.addOnActionSearchListener { + pageNo = 1 searchGoods() } } diff --git a/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt b/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt index 61a56f2..3a0d93d 100644 --- a/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt +++ b/app/src/main/java/com/sw/inbound/dialog/GoodsStoreDialog.kt @@ -284,10 +284,10 @@ class GoodsStoreDialog( } private fun confirmInputData() { - if (funcType == 1 && imageUri == null) { - context.toast("请采集图片") - return - } +// if (funcType == 1 && imageUri == null) { +// context.toast("请采集图片") +// return +// } val unitName = binding.tvProcurementUnit.text.trim().toString() if (unitName.isBlank()) { context.toast("请选择入库单位") @@ -328,11 +328,31 @@ class GoodsStoreDialog( return } if (funcType == 1) { - collectGoodsVector() + activity?.let { Loading.show(it) } + cameraUtils.takePhoto { uri -> + //imageUri = uri + collectGoodsVector(uri) { + activity?.uploadImage(goods.id!!, goods.goodsName!!, imageFile) + } + binding.root.postDelayed({ + Loading.dismiss() + confirm(unitName, count, price, totalPrice) + }, 500) + } + cameraUtils.addFailCallback { + binding.root.postDelayed({ + Loading.dismiss() + confirm(unitName, count, price, totalPrice) + }, 500) + } + } else { + confirm(unitName, count, price, totalPrice) } + } + + private fun confirm(unitName:String, count:Double, price:Double, totalPrice:Double?) { val id = binding.tvProcurementUnit.tag.toString() val unitVo = goods.unitVoList!!.first { it.businessUnitId == id } - activity?.uploadImage(goods.id!!, goods.goodsName!!, imageFile) confirmBlock( GoodsInfo( goodId = goods.id, @@ -389,15 +409,15 @@ class GoodsStoreDialog( }, 2600) } - private var imageUri: Uri? = null - private val takePhotoCallback: (Uri) -> Unit = { uri -> - takePhotoBinding?.let { - imageUri = uri - it.flCameraPreview.gone() - it.cvImageBg.visible() - it.ivGoodsImage.load(uri) - } - } +// private var imageUri: Uri? = null +// private val takePhotoCallback: (Uri) -> Unit = { uri -> +// takePhotoBinding?.let { +// imageUri = uri +// it.flCameraPreview.gone() +// it.cvImageBg.visible() +// it.ivGoodsImage.load(uri) +// } +// } private var previewView: PreviewView? = null private var takePhotoBinding: LayoutTakePhotoBinding? = null @@ -416,13 +436,13 @@ class GoodsStoreDialog( previewView = it.previewView it.flCameraPreview.visible() it.cvImageBg.gone() - it.btnStartPreview.setOnClickListener { _ -> - it.cvImageBg.gone() - it.flCameraPreview.visible() - } - it.btnTakePhoto.setOnClickListener { _ -> - cameraUtils.takePhoto(takePhotoCallback) - } +// it.btnStartPreview.setOnClickListener { _ -> +// it.cvImageBg.gone() +// it.flCameraPreview.visible() +// } +// it.btnTakePhoto.setOnClickListener { _ -> +// cameraUtils.takePhoto(takePhotoCallback) +// } } return } @@ -444,9 +464,9 @@ class GoodsStoreDialog( private var imageFile: File? = null // private var box: Box? = null - private fun collectGoodsVector() { + private fun collectGoodsVector(imageUri:Uri, block: ()-> Unit = {}) { try { - ImageUtil.uriToBitmap(context, imageUri!!)?.let { bitmap -> + ImageUtil.uriToBitmap(context, imageUri)?.let { bitmap -> val cropBitmap = BitmapCropper.cropCenter( original = bitmap, targetWidth = 1000, @@ -477,18 +497,7 @@ class GoodsStoreDialog( e.printStackTrace() } } -// Thread { -// try { -// val imageVector = FoodModule.bitmap2FloatArray(bitmap, true) -// if (imageVector != null) { -// ObjectBox.boxStore.runInTx { -// box?.put(Food(name = goods.goodsName + goods.goodsCode, foodIdx = 0, foodVector = imageVector)) -// } -// } -// } catch (e: Exception) { -// e.printStackTrace() -// } -// }.start() + block() } } catch (e: Exception) { e.printStackTrace() diff --git a/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt b/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt index 4cfcfcc..49c563b 100644 --- a/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt +++ b/app/src/main/java/com/sw/inbound/objbox/FoodModule.kt @@ -12,6 +12,7 @@ import com.sw.inbound.MyApp import com.sw.inbound.objbox.ObjectBox.boxStore import com.sw.inbound.utils.AssetsTool import com.sw.inbound.utils.ImageUtil +import com.sw.inbound.utils.LogSaveUtil import com.sw.inbound.utils.ext.toJsonString import io.objectbox.Box import io.objectbox.kotlin.boxFor @@ -82,6 +83,7 @@ object FoodModule { return outputTensor.dataAsFloatArray } catch (e: OutOfMemoryError) { e.printStackTrace() + logInfo("bitmap2FloatArray异常:${e.message}") } finally { if (rgb565Bitmap != null && rgb565Bitmap.isRecycled.not()) { rgb565Bitmap.recycle() @@ -130,20 +132,20 @@ object FoodModule { // query.close() // } - Timber.tag("FoodModule").d("queryFood向量:${floatArray.slice(0 until 50).toJsonString()}") + logInfo("queryFood向量:${floatArray.slice(0 until 50).toJsonString()}") val idScoreList = ObjectBox.query(floatArray, queryCount) val nameScoreList = mutableListOf() idScoreList.forEach { val name = ObjectBox.get(it.id)?.name ?: "" nameScoreList.add(IdNameScore(id = it.id, name = name, score = it.score)) } - Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}") + logInfo("queryFood数据:${nameScoreList.toJsonString()}") return nameScoreList } suspend fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List { val floatArray = bitmap2FloatArray(bitmap, false) ?: return emptyList() - Timber.tag("FoodModule").d("向量:${floatArray.toJsonString()}") + logInfo("向量:${floatArray.toJsonString()}") val nameScoreList = queryFoodNameScore(floatArray, queryCount) if (nameScoreList.isEmpty()) { return emptyList() @@ -168,7 +170,7 @@ object FoodModule { val sortedScoreList = maxScoreList.sortedWith(compareBy { orderList.indexOf(it.name) }) - Timber.tag("FoodModule").d("getFoodScoreList数据:${sortedScoreList.toJsonString()}") + logInfo("getFoodScoreList数据:${sortedScoreList.toJsonString()}") return sortedScoreList } @@ -211,7 +213,7 @@ object FoodModule { val size = embeddingsList.size val size2 = labelsList.size val size3 = foodMap.size - Log.d("TAG", "initDefFoodData: $size,$size2,$size3") + logInfo("initDefFoodData: $size,$size2,$size3") embeddingsList.forEachIndexed { index, floatList -> val classIdx = labelsList[index] val foodName = foodMap["$classIdx"] @@ -227,7 +229,7 @@ object FoodModule { action() } catch (e: Exception) { e.printStackTrace() - Log.d("TAG", "initDefFoodData: ---${e.message}--") + logInfo("initDefFoodData: ---${e.message}--") } } @@ -299,7 +301,7 @@ object FoodModule { return cacheFile.absolutePath } catch (e: IOException) { e.printStackTrace() - Timber.tag("FoodModule").d("文件拷贝失败 fileName=$fileName, error=${e.message}") + logInfo("文件拷贝失败 fileName=$fileName, error=${e.message}") // 拷贝失败时删除残缺文件,避免下次读取到损坏文件 if (cacheFile.exists()) { cacheFile.delete() @@ -311,4 +313,9 @@ object FoodModule { return null } + private fun logInfo(msg:String) { + Timber.tag("FoodModule").d(msg) + LogSaveUtil.saveLogFile(msg) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/objbox/ObjectBox.kt b/app/src/main/java/com/sw/inbound/objbox/ObjectBox.kt index af34d56..c7db823 100644 --- a/app/src/main/java/com/sw/inbound/objbox/ObjectBox.kt +++ b/app/src/main/java/com/sw/inbound/objbox/ObjectBox.kt @@ -21,6 +21,7 @@ import android.content.Context import android.os.Environment import android.util.Log import com.sw.inbound.MyApp +import com.sw.inbound.utils.LogSaveUtil import io.objectbox.Box import io.objectbox.BoxStore import io.objectbox.BoxStoreBuilder @@ -86,8 +87,10 @@ object ObjectBox { // Failed to build BoxStore due to database file issue, store message; // checked in NoteListActivity to notify user. dbExceptionMessage = e.toString() + LogSaveUtil.saveLogFile("ObjectBox.init异常1:$dbExceptionMessage") return } else { + LogSaveUtil.saveLogFile("ObjectBox.init异常2:${e.message}") // Failed to build BoxStore due to developer error. throw e } @@ -141,12 +144,14 @@ object ObjectBox { } catch (e: FileCorruptException) { // 操作中触发损坏,尝试重建数据库 e.printStackTrace() + LogSaveUtil.saveLogFile("safeDbOp出现FileCorruptException异常:${e.message},${e.errorCode}") //val context = boxStore.context //deleteDbFiles(context) init(MyApp.instance!!) null } catch (e: Exception) { e.printStackTrace() + LogSaveUtil.saveLogFile("safeDbOp出现其它异常:${e.message}") null } } diff --git a/app/src/main/java/com/sw/inbound/utils/CameraUtils.kt b/app/src/main/java/com/sw/inbound/utils/CameraUtils.kt index a1cd03e..d1b574c 100644 --- a/app/src/main/java/com/sw/inbound/utils/CameraUtils.kt +++ b/app/src/main/java/com/sw/inbound/utils/CameraUtils.kt @@ -13,14 +13,14 @@ class CameraUtils(private var activity: ComponentActivity) { private var photoCaptureHelper: PhotoCaptureHelper? = null // private var isCameraReady = false - fun takePhoto(callback: (Uri) -> Unit) { + fun takePhoto(successCallback: (Uri) -> Unit) { cameraController?.let { if (photoCaptureHelper == null) { initCaptureHelper() } } photoCaptureHelper?.let { - it.addSuccessCallback(callback) + it.addSuccessCallback(successCallback) it.bindCameraCallback { bind() } @@ -28,6 +28,11 @@ class CameraUtils(private var activity: ComponentActivity) { } } + private var failCallback:(()-> Unit)?=null + fun addFailCallback(callback:()->Unit) { + failCallback = callback + } + private fun initCaptureHelper() { photoCaptureHelper = PhotoCaptureHelper( context = activity, @@ -35,6 +40,7 @@ class CameraUtils(private var activity: ComponentActivity) { onSuccess = {}, onError = { msg -> //toast(msg) + failCallback?.invoke() } ) } diff --git a/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt b/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt index cdf84fe..d7af5da 100644 --- a/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt +++ b/app/src/main/java/com/sw/inbound/utils/CrashHandler.kt @@ -29,7 +29,6 @@ class CrashHandler private constructor(private val context: Context) : companion object { private const val TAG = "CrashHandler" - private const val CRASH_REPORTS_DIR = "crash_reports" private const val LOG_LINES = 500 // 收集最近500行日志 @Volatile @@ -109,7 +108,7 @@ class CrashHandler private constructor(private val context: Context) : val crashInfo = collectCrashInfo(thread, ex) // 保存日志文件 - saveCrashInfoToFile(crashInfo) + LogSaveUtil.saveLogFile("yyyy-MM-dd_HH-mm-ss",crashInfo) // 这里可以添加其他处理逻辑,比如上传到服务器等 } @@ -203,36 +202,11 @@ class CrashHandler private constructor(private val context: Context) : } } - private fun saveLog(logInfo:String) { - val time = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault()).format(Date()) - val fileName = "crash_$time.log" - - val crashDir = getCrashDir() - - val crashFile = File(crashDir, fileName) - FileOutputStream(crashFile).use { it.write(logInfo.toByteArray()) } - - Timber.tag(TAG).d("Crash info saved to: ${crashFile.absolutePath}") - } - - private fun saveCrashInfoToFile(crashInfo: String) { - try { - saveLog(crashInfo) - } catch (e: Exception) { - Timber.tag(TAG).e(e, "Error saving crash info to file") - try { - saveLog("Error saving crash info to file:${e.message}") - } catch (e: Exception) { - Timber.tag(TAG).e(e, "save exception") - } - } - } - /** * 清理旧的崩溃日志 */ fun cleanupOldCrashReports(maxAgeDays: Int = 7) { - val crashDir = getCrashDir() + val crashDir = LogSaveUtil.getCrashDir() if (!crashDir.exists() || !crashDir.isDirectory) return val now = System.currentTimeMillis() @@ -245,17 +219,4 @@ class CrashHandler private constructor(private val context: Context) : } } - private fun getCrashDir():File { - //val crashDir = File(context.getExternalFilesDir(null), CRASH_REPORTS_DIR) - var crashDir = File(context.filesDir, CRASH_REPORTS_DIR) - if (!crashDir.exists()) { - crashDir.mkdirs() - } - - if (!(crashDir.exists())) { - crashDir = File(context.cacheDir, CRASH_REPORTS_DIR) - } - return crashDir - } - } \ No newline at end of file diff --git a/app/src/main/java/com/sw/inbound/utils/LogSaveUtil.kt b/app/src/main/java/com/sw/inbound/utils/LogSaveUtil.kt new file mode 100644 index 0000000..a5e9bef --- /dev/null +++ b/app/src/main/java/com/sw/inbound/utils/LogSaveUtil.kt @@ -0,0 +1,60 @@ +package com.sw.inbound.utils + +import com.sw.inbound.MyApp +import timber.log.Timber +import java.io.File +import java.io.FileOutputStream +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +object LogSaveUtil { + + private const val TAG = "LogSaveUtil" + private const val CRASH_REPORTS_DIR = "crash_reports" + + public fun saveLogFile(msg: String) { + saveLogFile("yyyy-MM-dd", msg) + } + + public fun saveLogFile(pattern: String, msg: String) { + try { + saveLog(pattern, msg) + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Error saving crash info to file") + try { + saveLog(pattern, "Error saving crash info to file:${e.message}") + } catch (e: Exception) { + Timber.tag(TAG).e(e, "save exception") + } + } + } + + fun saveLog(pattern: String, logInfo: String) { + val time = SimpleDateFormat(pattern, Locale.getDefault()).format(Date()) + val fileName = "crash_$time.log" + + val crashDir = getCrashDir() + + val crashFile = File(crashDir, fileName) + + val saveTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) + FileOutputStream(crashFile, true).use { it.write("$saveTime||$logInfo\n".toByteArray()) } + + Timber.tag(TAG).d("Crash info saved to: ${crashFile.absolutePath}") + } + + fun getCrashDir(): File { + //val crashDir = File(context.getExternalFilesDir(null), CRASH_REPORTS_DIR) + var crashDir = File(MyApp.instance!!.filesDir, CRASH_REPORTS_DIR) + if (!crashDir.exists()) { + crashDir.mkdirs() + } + + if (!(crashDir.exists())) { + crashDir = File(MyApp.instance!!.cacheDir, CRASH_REPORTS_DIR) + } + return crashDir + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/layout_take_photo.xml b/app/src/main/res/layout/layout_take_photo.xml index c1a9430..bcab99f 100644 --- a/app/src/main/res/layout/layout_take_photo.xml +++ b/app/src/main/res/layout/layout_take_photo.xml @@ -80,7 +80,8 @@ android:layout_height="wrap_content" android:layout_marginTop="15dp" android:gravity="center_vertical" - android:orientation="horizontal"> + android:orientation="horizontal" + android:visibility="gone">