This commit is contained in:
马增飞
2025-11-27 15:06:30 +08:00
parent 1e46a5ace7
commit 5b7b73dd55
10 changed files with 395 additions and 64 deletions
@@ -27,13 +27,13 @@ import com.sw.inbound.utils.BitmapCropper
import com.sw.inbound.utils.BitmapSaver
import com.sw.inbound.utils.CameraUtils
import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.utils.ext.addOnActionSearchListener
import com.sw.inbound.utils.ext.clickWithDebounce
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.hideKeyboard
import com.sw.inbound.utils.ext.invisible
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.utils.ext.toObject
import com.sw.inbound.utils.ext.toast
import com.sw.inbound.utils.ext.visible
@@ -69,11 +69,16 @@ class FoodCollectionActivity : ComponentActivity() {
FoodCollectionAdapter(collectList).apply {
addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
collectList[position].let {
it.imageFile = null
it.imageVector = null
it.bitmap = null
it.isFinish = false
it.isShowCamera = true
it.uploadSuccess = false
}
collectionAdapter.notifyItemChanged(position)
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
binding.btnUploadImage.text = "待上传图片${count}"
}
}
}
@@ -130,7 +135,14 @@ class FoodCollectionActivity : ComponentActivity() {
searchGoods()
}
}
binding.btnUploadImage.setOnClickListener {
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
if (count == 0) {
toast("已全部上传成功")
return@setOnClickListener
}
uploadAllImage()
}
binding.btnSave.setOnClickListener { _ ->
if (clickIndex == -1) {
toast("请选择物品名称")
@@ -142,7 +154,6 @@ class FoodCollectionActivity : ComponentActivity() {
return@setOnClickListener
}
vectorThread()
uploadAllImage()
}
binding.btnTakePhoto.clickWithDebounce {
@@ -170,9 +181,18 @@ class FoodCollectionActivity : ComponentActivity() {
loadEmptyView()
// binding.tvTitle.setOnClickListener {
// uploadImage(goodsImageList[7])
// }
binding.tvTitle.setOnClickListener {
startActivity<LocalImagePreviewActivity> { }
// val goodsImage = GoodsImage(goodsId = "1993493094888140802", goodsName = "多宝鱼", startTime = 1764120531856L, endTime = 1764121842825L)
// uploadImage(goodsImage)
// val goodsImage = GoodsImage(goodsId = "1986366073649287170", goodsName = "黑鱼(整条鱼)", startTime = 1764122703093L, endTime = 1764123156022L)
// uploadImage(goodsImage)
// val goodsImage = GoodsImage(goodsId = "1986699063868801025", goodsName = "鸡腿肉", startTime = 1764123375841L, endTime = 1764124039162L)
// uploadImage(goodsImage)
}
}
private var pageNo = 1
@@ -224,8 +244,11 @@ class FoodCollectionActivity : ComponentActivity() {
it.bitmap?.recycle()
}
it.bitmap = null
it.imageVector = null
it.imageFile = null
it.isShowCamera = true
it.isFinish = false
it.uploadSuccess = false
} catch (e: Exception) {
e.printStackTrace()
}
@@ -238,6 +261,7 @@ class FoodCollectionActivity : ComponentActivity() {
searchAdapter.notifyDataSetChanged()
loadEmptyView()
binding.ivFinish.invisible()
binding.btnUploadImage.text = "待上传图片${0}"
}
private val cameraCallback: (Uri) -> Unit = { uri ->
@@ -279,6 +303,8 @@ class FoodCollectionActivity : ComponentActivity() {
it.isShowCamera = false
}
collectionAdapter.notifyItemChanged(index)
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
binding.btnUploadImage.text = "待上传图片${count}"
}
} catch (e: Exception) {
e.printStackTrace()
@@ -409,20 +435,35 @@ class FoodCollectionActivity : ComponentActivity() {
}
}
// private val failList = mutableListOf<File>()
// private var successCount = 0
private fun uploadAllImage() {
val goods = searchGoodsList[clickIndex]
Loading.show(this)
val files = collectList.filter { it.imageFile!=null }.map { it.imageFile!! }
if (files.isEmpty()) {
return
}
for (index in files.indices step 5) {
val end = if(index + 5 < files.size - 1) index + 5 else files.size - 1
val list = files.subList(index, end)
viewModel.uploadMultipleImages(goods.id!!, goods.goodsName!!, list) {
Timber.tag(TAG).d("uploadMultipleImages: ${it}")
// successCount = 0
// failList.clear()
val goods = searchGoodsList[clickIndex]
for (index in collectList.indices step 5) {
val end = if(index + 5 < collectList.size - 1) index + 5 else collectList.size - 1
val subList = collectList.subList(index, end)
val subFiles = subList.map { it.imageFile }
viewModel.uploadMultipleImages(goods.id!!, goods.goodsName!!, subFiles) {isSuccess->
Timber.tag(TAG).d("uploadMultipleImages: ${isSuccess}")
//{"code":"00000","data":null,"msg":"成功","total":0}
// val resp = it?.toObject<RespData>()
// val resp = result?.toObject<RespData>()
// val isSuccess = resp?.code == "00000"
subList.filter { it.imageFile!=null }.forEach { it.uploadSuccess = isSuccess }
val count = collectList.count { it.imageFile!=null && it.uploadSuccess.not() }
runOnUiThread {
binding.btnUploadImage.text = "待上传图片${count}"
if (count == 0) {
Loading.dismiss()
}
}
// binding.ivFinish.run {
// if (isSuccess) visible() else invisible()
// }
@@ -515,52 +556,52 @@ class FoodCollectionActivity : ComponentActivity() {
// ))
// }
// private fun uploadImage(goodsImage: GoodsImage) {
// Loading.show(this)
// val cropFile = File(this.cacheDir, "crop")
// val list = mutableListOf<File>()
// val startTime = goodsImage.startTime
// val endTime = goodsImage.endTime
// cropFile.listFiles()?.forEach {
// if (it.isDirectory) {
// return@forEach
// }
// val start = "IMG_CROP_".length
// val end = it.name.indexOf(".jpg")
// val time = it.name.substring(start, end).toLong()
// if (time in startTime..endTime) {
// list.add(it)
// }
// if (list.size < 5) {
// return@forEach
// }
// viewModel.uploadMultipleImages(
// goodsId = goodsImage.goodsId,
// goodsName = goodsImage.goodsName,
// files = list
// ) { data ->
private fun uploadImage(goodsImage: GoodsImage) {
Loading.show(this)
val cropFile = File(this.cacheDir, "crop")
val list = mutableListOf<File>()
val startTime = goodsImage.startTime
val endTime = goodsImage.endTime
cropFile.listFiles()?.forEach {
if (it.isDirectory) {
return@forEach
}
val start = "IMG_CROP_".length
val end = it.name.indexOf(".jpg")
val time = it.name.substring(start, end).toLong()
if (time in startTime..endTime) {
list.add(it)
}
if (list.size < 5) {
return@forEach
}
viewModel.uploadMultipleImages(
goodsId = goodsImage.goodsId,
goodsName = goodsImage.goodsName,
files = list
) { isSuccess ->
// val resp = data?.toObject<RespData>()
// val isSuccess = resp?.code == "00000"
// binding.ivFinish.run {
// if (isSuccess) visible() else invisible()
// }
// }
// list.clear()
// }
// if (list.isNotEmpty()) {
// viewModel.uploadMultipleImages(
// goodsId = goodsImage.goodsId,
// goodsName = goodsImage.goodsName,
// files = list
// ) { data ->
binding.ivFinish.run {
if (isSuccess) visible() else invisible()
}
}
list.clear()
}
if (list.isNotEmpty()) {
viewModel.uploadMultipleImages(
goodsId = goodsImage.goodsId,
goodsName = goodsImage.goodsName,
files = list
) { isSuccess ->
// val resp = data?.toObject<RespData>()
// val isSuccess = resp?.code == "00000"
// binding.ivFinish.run {
// if (isSuccess) visible() else invisible()
// }
// }
// }
// Loading.dismiss()
// }
binding.ivFinish.run {
if (isSuccess) visible() else invisible()
}
}
}
Loading.dismiss()
}
}
@@ -0,0 +1,97 @@
package com.sw.inbound.activity
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.recyclerview.widget.GridLayoutManager
import coil.load
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.databinding.ActivityLocalImagePreviewBinding
import com.sw.inbound.databinding.ListItemImagePreviewBinding
import com.sw.inbound.dialog.Loading
import com.sw.inbound.utils.ext.copyText
import java.io.File
class LocalImagePreviewActivity : ComponentActivity() {
private lateinit var binding: ActivityLocalImagePreviewBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLocalImagePreviewBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.recyclerView.let {
it.layoutManager = GridLayoutManager(this, 6, GridLayoutManager.VERTICAL, false)
it.adapter = imageAdapter
}
binding.btnBack.setOnClickListener { finish() }
loadData()
}
fun loadData() {
Thread {
runOnUiThread {
Loading.show(this)
}
val cropFile = File(this.cacheDir, "crop")
cropFile.listFiles()?.forEach {
if (it.isDirectory) {
return@forEach
}
val start = "IMG_CROP_".length
val end = it.name.indexOf(".jpg")
val time = it.name.substring(start, end).toLong()
if (time >= 1764086400L) {
imageList.add(ImageBean(file = it, name = "$time"))
}
}
imageList.sortBy { it.name.toLong() }
runOnUiThread {
imageAdapter.notifyDataSetChanged()
Loading.dismiss()
}
}.start()
}
private var isCycle = true
private val imageList = mutableListOf<ImageBean>()
private val imageAdapter: ImageAdapter by lazy {
ImageAdapter(imageList).apply {
setOnItemClickListener { _, _, position ->
imageList[position].name.copyText(this@LocalImagePreviewActivity)
}
}
}
data class ImageBean(
var file: File,
var name: String
)
inner class ImageAdapter(var list: MutableList<ImageBean>) :
BaseQuickAdapter<ImageBean, ImageAdapter.VH>(list) {
inner class VH(var binding: ListItemImagePreviewBinding) : QuickViewHolder(binding.root)
override fun onBindViewHolder(holder: VH, position: Int, item: ImageBean?) {
holder.binding.let {
it.imageView.load(item!!.file)
it.textView.text = item.name
}
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemImagePreviewBinding.inflate(inflater, parent, false)
return VH(binding)
}
}
}
@@ -159,7 +159,8 @@ interface ApiService {
@Multipart
@POST
suspend fun uploadMultipleImages(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/inboundWeighingScale/add",
// @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/inboundWeighingScale/add",
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/inbound/pad/inboundWeighingScale/add",
@PartMap params: HashMap<String, RequestBody>,
@Part goodsPics: List<MultipartBody.Part>
): ApiResponse<String>
@@ -16,7 +16,8 @@ data class FoodCollectionBean(
var imageFile: File? = null,
var imageVector: FloatArray? = null,
var isShowCamera: Boolean = false,
var isFinish:Boolean = false
var isFinish:Boolean = false,
var uploadSuccess:Boolean = false
)
data class ReceiptGoodsInfo(
@@ -2,6 +2,8 @@ package com.sw.inbound.utils.ext
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
@@ -225,3 +227,25 @@ fun View.hideKeyboard() {
imm.hideSoftInputFromWindow(this.windowToken, 0)
this.clearFocus() // 清除焦点避免键盘再次弹出
}
/**
* 复制文本到剪贴板
* @param context 上下文
* @param text 要复制的文本内容
* @param showToast 是否显示复制成功提示,默认为true
*/
fun String.copyText(context: Context, showToast: Boolean = true) {
// 获取剪贴板管理器
val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
// 创建ClipData对象,包含要复制的文本
val clipData = ClipData.newPlainText("label", this)
// 将数据设置到剪贴板
clipboardManager.setPrimaryClip(clipData)
// 显示复制成功提示
if (showToast) {
Toast.makeText(context, "文本已复制到剪贴板", Toast.LENGTH_SHORT).show()
}
}
@@ -377,17 +377,22 @@ class ReceiptViewModel @Inject constructor(
callback(true)
}
}
fun uploadMultipleImages(goodsId:String, goodsName:String, files:List<File>, callback: (String?) -> Unit) {
fun uploadMultipleImages(goodsId:String, goodsName:String, files:List<File?>, callback: (Boolean) -> Unit) {
launchWithLoading {
val map = mutableMapOf<String, String>()
map["goodsId"] = goodsId
map["goodsName"] = goodsName
val resp = repository.uploadMultipleImages(fileList = files, param = map)
if (!parseResponse(resp)) {
callback(null)
val fileList = files.filterNotNull()
if (fileList.isEmpty()) {
callback(false)
return@launchWithLoading
}
callback(resp.data)
val resp = repository.uploadMultipleImages(fileList = fileList, param = map)
if (!parseResponse(resp)) {
callback(false)
return@launchWithLoading
}
callback(resp.code == "00000")
}
}