出入库功能改版

This commit is contained in:
2025-10-28 19:22:31 +08:00
parent f4e7cab2d0
commit b22f42d92a
121 changed files with 8271 additions and 3141 deletions
+26 -4
View File
@@ -1,10 +1,15 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
id("com.google.devtools.ksp")
// alias(libs.plugins.android.application)
// alias(libs.plugins.kotlin.android)
// alias(libs.plugins.kotlin.compose)
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
id("kotlin-parcelize")
// id("compose.compiler")
kotlin("kapt")
alias(libs.plugins.kotlin.compose)
}
android {
@@ -54,7 +59,11 @@ android {
}
buildFeatures {
compose = true
viewBinding = true
}
// composeOptions {
// kotlinCompilerExtensionVersion = "1.5.4"
// }
sourceSets {
named("main") {
jniLibs.srcDirs("libs")
@@ -119,7 +128,20 @@ dependencies {
implementation(libs.core)
implementation(libs.android.core)
implementation(libs.material)
implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("androidx.compose.foundation:foundation:1.7.0")
implementation("androidx.compose.foundation:foundation-layout:1.7.0")
implementation (libs.pytorch.android)
implementation (libs.pytorch.android.torchvision)
implementation("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha")
implementation("io.github.scwang90:refresh-header-classics:3.0.0-alpha")
val objectboxVersion = "5.0.1"
debugImplementation("io.objectbox:objectbox-android-objectbrowser:$objectboxVersion")
// releaseImplementation("io.objectbox:objectbox-android:$objectboxVersion")
}
apply(plugin = "io.objectbox")
Binary file not shown.
+3
View File
@@ -49,6 +49,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.sw.inbound.activity.ReceiptActivity"
android:screenOrientation="landscape"/>
<activity android:name="com.sw.inbound.activity.SelfProcurementActivity" />
<!-- <activity-->
<!-- android:name=".InitActivity"-->
Binary file not shown.
+38
View File
@@ -0,0 +1,38 @@
{
"class_names": [
"上海青",
"土豆",
"胡萝卜",
"芹菜",
"茄子",
"蒜苔",
"西红柿",
"青椒",
"黄瓜"
],
"class_to_idx": {
"上海青": 0,
"土豆": 1,
"胡萝卜": 2,
"芹菜": 3,
"茄子": 4,
"蒜苔": 5,
"西红柿": 6,
"青椒": 7,
"黄瓜": 8
},
"idx_to_class": {
"0": "上海青",
"1": "土豆",
"2": "胡萝卜",
"3": "芹菜",
"4": "茄子",
"5": "蒜苔",
"6": "西红柿",
"7": "青椒",
"8": "黄瓜"
},
"embedding_dim": 512,
"total_images": 450,
"build_time": "2025-10-21T10:14:29.510882"
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
@@ -43,7 +43,7 @@ object GlobalData {
/**
* 具体业务baseurl
*/
var appBaseUrl: String = ""
var appBaseUrl: String = "http://192.168.1.201:14801"
/**
* 设备id
+5 -2
View File
@@ -1,6 +1,7 @@
package com.sw.inbound
import android.app.Application
import com.sw.inbound.objbox.ObjectBox
import com.sw.inbound.utils.AppUtil
import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.CrashHandler
@@ -12,20 +13,22 @@ import timber.log.Timber
class MyApp : Application() {
companion object {
const val DEBUG: Boolean = true
var instance: MyApp?=null
}
override fun onCreate() {
super.onCreate()
instance = this
Timber.plant(Timber.DebugTree())
ContextUtils.initAppContext(this)
GlobalData.appVersion = AppUtil.getAppVersionCode(this).toString()
var deviceId = AppUtil.getUDID(this)
deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212"
///deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212"
GlobalData.deviceId = deviceId
val spUtil = SPUtil.getInstance(context = ContextUtils.getAppContext())
GlobalData.appToken = spUtil.get(GlobalKey.KEY_TOKEN, "") as String
ObjectBox.init(this)
// 初始化崩溃处理器
CrashHandler.init(this)
}
@@ -0,0 +1,410 @@
package com.sw.inbound.activity
import android.net.Uri
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.camera.core.CameraSelector
import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController
import androidx.camera.view.PreviewView
import androidx.core.graphics.toColorInt
import com.shuwei.intelligent.shelves.utils.ext.appendText
import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString
import com.sw.inbound.GlobalData
import com.sw.inbound.databinding.ActivityGoodsListBinding
import com.sw.inbound.databinding.ListItemReceiptGoodsBinding
import com.sw.inbound.databinding.ListItemSelfProcurementBinding
import com.sw.inbound.dialog.DropdownPopup
import com.sw.inbound.dialog.GoodsRecognizeDialog
import com.sw.inbound.dialog.GoodsSearchDialog
import com.sw.inbound.dialog.NotReceiptWarnDialog
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.objbox.FoodModule
import com.sw.inbound.utils.BitmapCropper
import com.sw.inbound.utils.BitmapSaver
import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.PhotoCaptureHelper
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.toJsonString
import com.sw.inbound.utils.ext.toast
import com.sw.inbound.viewmodel.ReceiptViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.runBlocking
import timber.log.Timber
import kotlin.math.min
@AndroidEntryPoint
abstract class GoodsListActivity : ComponentActivity() {
companion object {
public const val ID = "id"
public const val SUPPLIER_ID = "supplierId"
public const val IS_RECEIPT_PAGE = "isReceiptPage"
public const val IS_NEW_RECEIPT = "isNewReceipt"
const val PAGE_SIZE = 10
}
var isReceiptPage: Boolean = false
var isNewReceipt: Boolean = false
var id: String = ""
var supplierId: String = ""
lateinit var binding: ActivityGoodsListBinding
val viewModel: ReceiptViewModel by viewModels()
val goodsList: MutableList<GoodsInfo> = mutableListOf()
abstract fun initRecyclerView()
abstract fun initView()
abstract fun getWarehouseList(): List<DictType>
private lateinit var backPressedCallback: OnBackPressedCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityGoodsListBinding.inflate(layoutInflater)
setContentView(binding.root)
initBackDispatcher()
isReceiptPage = intent.getBooleanExtra(IS_RECEIPT_PAGE, true)
isNewReceipt = intent.getBooleanExtra(IS_NEW_RECEIPT, false)
id = intent.getStringExtra(ID) ?: ""
supplierId = intent.getStringExtra(SUPPLIER_ID) ?: ""
FoodModule.init(this)
initCamera()
replaceIncludeContent()
initRecyclerView()
initView()
binding.btnBack.setOnClickListener { handleBackEvent() }
binding.flWarehouseDropdown.setOnClickListener { v ->
if (GlobalData.warehouseTypeList.isEmpty()) {
toast("暂无仓库数据")
return@setOnClickListener
}
if (dropdownPopup == null) {
dropdownList.clear()
dropdownList.addAll(GlobalData.warehouseTypeList)
dropdownPopup = DropdownPopup(
context = this,
list = dropdownList,
popHeight = min(355.dp, dropdownList.size * 71.dp)
) {
binding.tvWareHouse.run {
text = it.value
tag = it.id
}
}
}
dropdownPopup?.showAsDropDown(v)
}
binding.tvUserName.text = GlobalData.deviceId
binding.ivLogout.gone()
setPreviewController(binding.previewView)
viewModel.startSensorScale()
binding.root.postDelayed({
viewModel.readWeight {
weightCallback?.invoke(it)
recognizeWeight(weight = it)
}
}, 5 * 1000)
}
private var weightCallback: ((weight: Int) -> Unit)? = null
fun readWeightInfo(callback: (weight: Int) -> Unit) {
weightCallback = callback
}
private fun recognizeWeight(weight: Int) {
if (weight < 200) {
return
}
if (searchFoodEnable.not()) {
return
}
runOnUiThread {
recognizeFood()
}
}
fun recognizeFood() {
searchFoodEnable = false
takePhoto { uri ->
Thread {
searchFood(uri)
}.start()
}
}
private var dropdownPopup: DropdownPopup? = null
private val dropdownList: MutableList<DictType> = mutableListOf()
fun getSpannable(text: String, num: Int, color: String): SpannableStringBuilder {
return buildSpannableString {
appendText(text, ForegroundColorSpan("#FF141428".toColorInt()))
appendText(num.toString(), ForegroundColorSpan(color.toColorInt()))
}
}
private var searchFoodEnable = true
private fun searchFood(uri: Uri) {
ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
val newBmp = BitmapCropper.cropCenter(
original = bitmap,
targetWidth = 1000, targetHeight = 1300,
offsetX = 30, offsetY = 100
)
val file = BitmapSaver.saveToAppFilesDir(
newBmp,
this,
"IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}")
val foodNameList = FoodModule.queryFood(newBmp)
searchMultipleGoods(foodNameList) { goodsList ->
//if (goodsList.size != foodNameList.size) {
// toast("系统异常,请稍后重试!!!")
// searchFoodEnable = true
// return@searchMultipleGoods
//}
handleGoodsResult(
if (goodsList.size == foodNameList.size) goodsList
else mutableListOf()
)
}
}
}
private fun handleGoodsResult(goodsList: MutableList<SearchGoodsInfo.Record>) {
runOnUiThread {
if (goodsRecognizeDialog?.isShowing == true) {
searchFoodEnable = true
return@runOnUiThread
}
goodsRecognizeDialog = GoodsRecognizeDialog(this, goodsList, {
goodsRecognizeDialog = null
searchFoodEnable = true
}) {
GoodsSearchDialog(this).show()
}.apply {
if (isFinishing || isDestroyed) {
return@apply
}
show()
}
}
}
private var goodsRecognizeDialog: GoodsRecognizeDialog? = null
private var cameraController: LifecycleCameraController? = null
private var photoCaptureHelper: PhotoCaptureHelper? = null
private var isCameraReady = false
fun takePhoto(cameraCallback: (Uri) -> Unit) {
cameraController?.let {
if (photoCaptureHelper == null) {
photoCaptureHelper = PhotoCaptureHelper(
context = this,
cameraController = cameraController!!,
onSuccess = cameraCallback,
onError = { msg ->
//toast(msg)
}
)
}
}
photoCaptureHelper?.takePhoto()
}
fun setPreviewController(previewView: PreviewView?) {
previewView?.controller = cameraController
}
fun initCamera() {
if (cameraController == null) {
cameraController = LifecycleCameraController(this).apply {
// 必须设置有效的用例
setEnabledUseCases(
CameraController.IMAGE_CAPTURE or
CameraController.VIDEO_CAPTURE
)
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
}
cameraController?.bindToLifecycle(this)
}
// if (isCameraReady.not()) {
// try {
// cameraController!!.initializationFuture.addListener({
// isCameraReady = true
// Timber.d("Camera initialized successfully")
// }, ContextCompat.getMainExecutor(this))
// } catch (e: Exception) {
// Timber.d("Camera initialized error = ${e.message}")
// }
// }
}
private fun replaceIncludeContent() {
binding.flContainer.removeAllViews()
if (isReceiptPage) {
val tempBinding =
ListItemReceiptGoodsBinding.inflate(layoutInflater, binding.flContainer, false)
binding.flContainer.addView(tempBinding.root)
} else {
val tempBinding =
ListItemSelfProcurementBinding.inflate(layoutInflater, binding.flContainer, false)
binding.flContainer.addView(tempBinding.root)
}
}
override fun onDestroy() {
super.onDestroy()
cameraController?.unbind()
viewModel.stopSensorScale()
isCameraReady = false
}
fun addGoods(it: GoodsInfo) {
goodsList.add(it)
binding.rvGoodsList.adapter?.notifyItemInserted(goodsList.size - 1)
}
fun searchGoods(
searchName: String,
pageNo: Int,
pageSize: Int = PAGE_SIZE,
callback: (List<SearchGoodsInfo.Record>) -> Unit
) {
runBlocking {
val records = searchGoodsBlock(searchName, pageNo, pageSize)
runOnUiThread {
callback(records)
}
}
}
suspend fun searchGoodsBlock(
searchName: String,
pageNo: Int,
pageSize: Int = PAGE_SIZE
): List<SearchGoodsInfo.Record> {
return viewModel.searchGoodsInfoList2(
goodsName = searchName,
pageNo = pageNo,
pageSize = pageSize
)
}
fun searchMultipleGoods(
goodsNameList: List<String>,
callback: (MutableList<SearchGoodsInfo.Record>) -> Unit
) {
runBlocking {
val list = mutableListOf<SearchGoodsInfo.Record>()
for (goodsName in goodsNameList) {
val records = searchGoodsBlock(goodsName, 1, 1)
if (records.isNotEmpty()) {
list.add(records[0])
}
}
callback(list)
}
}
private fun initBackDispatcher() {
// 创建回调,true表示初始启用状态
backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
handleBackEvent()
}
}
// 注册回调,使用lifecycleOwner确保生命周期安全
onBackPressedDispatcher.addCallback(this, backPressedCallback)
}
private fun handleBackEvent() {
val count = goodsList.count { it.isLocalGoods }
// 处理返回事件
if (count > 0) {
NotReceiptWarnDialog(context = this@GoodsListActivity) {
//onBackPressedDispatcher.onBackPressed()
finish()
}.show()
} else {
// 允许默认行为
backPressedCallback.isEnabled = false
//onBackPressedDispatcher.onBackPressed()
finish()
}
}
fun receiptSubmit() {
if (binding.tvWareHouse.tag == null) {
toast("请选择仓库")
return
}
val submitData = goodsList.filter { it.isSelected }.also {
it.forEach { goodsInfo ->
goodsInfo.warehouseId = binding.tvWareHouse.tag.toString()
goodsInfo.warehouseName = binding.tvWareHouse.text.toString()
}
}
val uploadInfo = UploadInfo(
id = id,
supplierId = supplierId,
receiveGoodsInfos = submitData
)
Timber.tag("SelfProcurementActivity")
.d("receiptSubmit确认收货提交数据:${uploadInfo.toJsonString()}")
viewModel.confirmReceipt(uploadInfo) { success ->
if (success) {
toast("确认收货成功")
finish()
} else {
toast("确认收货失败")
}
}
}
fun selfProcurementSubmit() {
if (binding.tvWareHouse.tag == null) {
toast("请选择仓库")
return
}
val submitData = goodsList.map {
PurchaseWarehouseParam(
goodsId = it.goodId ?: "",
goodsName = it.goodName,
kcUnitId = it.kcUnitId,
goodsCount = it.receiveCount ?: 0.0,
goodsUnitPrice = it.recUnitPriceTaxIn ?: 0.0,
goodsPrice = it.recPriceExItem ?: 0.0,
//goodPurId = it.goodsPurId,
warehouseId = binding.tvWareHouse.tag.toString(),
buyToInventoryValue = it.consumeValue ?: ""
)
}
Timber.tag("SelfProcurementActivity")
.d("selfProcurementSubmit自采入库提交数据:${submitData.toJsonString()}")
viewModel.addToWarehouse(submitData) { success ->
if (success) {
toast("提交入库成功")
finish()
} else {
toast("提交入库失败")
}
}
}
}
@@ -0,0 +1,98 @@
package com.sw.inbound.activity
import android.annotation.SuppressLint
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.inbound.adapter.ReceiptGoodsAdapter
import com.sw.inbound.model.response.DictType
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.toast
import com.sw.inbound.utils.ext.visible
import kotlinx.coroutines.launch
class ReceiptActivity : GoodsListActivity() {
private val adapter by lazy {
ReceiptGoodsAdapter(goodsList).apply {
setOnItemClickListener { adapter, view, position ->
goodsList[position].let {
it.isSelected = it.isSelected.not()
}
notifyItemChanged(position)
}
}
}
override fun initRecyclerView() {
binding.rvGoodsList.let {
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
it.adapter = adapter
}
}
@SuppressLint("NotifyDataSetChanged")
override fun initView() {
//initRvTestData()
binding.tvConfirmNum.run {
if (isNewReceipt) gone() else visible()
}
binding.tvNotConfirmNum.run {
if (isNewReceipt) gone() else visible()
}
binding.btnConfirmReceipt.setOnClickListener {
if (isNewReceipt) {
selfProcurementSubmit()
} else {
receiptSubmit()
}
}
if (isNewReceipt.not()) {
viewModel.getReceiveDetail(id) { detail ->
runOnUiThread {
if (detail == null) {
toast("未查询到数据")
return@runOnUiThread
}
binding.tvPurchaseNo.text = "采购单号:${detail.purCode}"
val list = detail.receiveGoodsInfoList
goodsList.addAll(list)
adapter.notifyDataSetChanged()
val confirmOrderCount = list.count { it.isAdjusted }
binding.tvConfirmNum.text =
getSpannable("已确认 ", num = confirmOrderCount, color = "#FF009632")
val notConfirmOrderCount = goodsList.size - confirmOrderCount
binding.tvNotConfirmNum.text =
getSpannable("未确认 ", num = notConfirmOrderCount, color = "#FFFF0000")
}
}
} else {
binding.tvPurchaseNo.text = "新增收货"
}
// lifecycleScope.launch {
// repeatOnLifecycle(Lifecycle.State.CREATED) {
// launch {
// viewModel.adjustedOrders.collect {
// val confirmOrderCount = it.size
// binding.tvConfirmNum.text = getSpannable("已确认 ", num = confirmOrderCount, color = "#FF009632")
// val notConfirmOrderCount = goodsList.size - confirmOrderCount
// binding.tvNotConfirmNum.text = getSpannable("未确认 ", num = notConfirmOrderCount, color = "#FF009632")
// }
// }
// }
// }
}
override fun getWarehouseList(): List<DictType> {
return goodsList.filter {
it.warehouseId.isNullOrBlank().not() && it.warehouseName.isNullOrBlank().not()
}
.distinctBy { it.warehouseId }
.map {
DictType(id = it.warehouseId!!, value = it.warehouseName!!)
}
}
}
@@ -0,0 +1,54 @@
package com.sw.inbound.activity
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.inbound.R
import com.sw.inbound.adapter.SelfProcurementAdapter
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.DictType
import com.sw.inbound.utils.ext.toJsonString
import com.sw.inbound.utils.ext.toast
import timber.log.Timber
import kotlin.getValue
class SelfProcurementActivity : GoodsListActivity() {
private val adapter by lazy {
SelfProcurementAdapter(goodsList).apply {
setOnItemClickListener { adapter, view, position ->
goodsList[position].let {
it.isSelected = it.isSelected.not()
}
notifyItemChanged(position)
}
addOnItemChildClickListener(R.id.ivState) { adapter, view, position ->
removeAt(position)
}
}
}
override fun initRecyclerView() {
binding.rvGoodsList.let {
it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
it.adapter = adapter
}
}
override fun initView() {
binding.tvPurchaseNo.text = "自采入库"
binding.btnConfirmReceipt.setOnClickListener {
selfProcurementSubmit()
}
}
override fun getWarehouseList(): List<DictType> {
return goodsList.filter {
it.warehouseId.isNullOrBlank().not() && it.warehouseName.isNullOrBlank().not()
}
.distinctBy { it.warehouseId }
.map {
DictType(id = it.warehouseId!!, value = it.warehouseName!!)
}
}
}
@@ -0,0 +1,31 @@
package com.sw.inbound.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.databinding.ListItemDropdownBinding
import com.sw.inbound.model.response.DictType
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.visible
class DropdownAdapter(var list: MutableList<DictType>) :
BaseQuickAdapter<DictType, DropdownAdapter.VH>(list) {
inner class VH(var binding: ListItemDropdownBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemDropdownBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: DictType?) {
holder.binding.tvDropdown.text = item?.value
holder.binding.divider.run {
if (position == list.size - 1) gone() else visible()
}
}
}
@@ -0,0 +1,50 @@
package com.sw.inbound.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.graphics.toColorInt
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.R
import com.sw.inbound.databinding.ListItemGoodsSearchBinding
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.setShapeDrawable
class GoodsSearchAdapter(var list: MutableList<SearchGoodsInfo.Record>) :
BaseQuickAdapter<SearchGoodsInfo.Record, GoodsSearchAdapter.VH>(list) {
inner class VH(var binding: ListItemGoodsSearchBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemGoodsSearchBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: SearchGoodsInfo.Record?) {
holder.binding.let {
it.tvGoodsName.run {
text = item!!.goodsName
setTextColor(if (item!!.isSelected) "#FF0032C8".toColorInt() else "#FF666666".toColorInt())
}
it.root.run {
if (item!!.isSelected) {
setShapeDrawable(
solidColor = "#FFEAF0FF",
strokeColor = "#FF0033CC",
strokeWidth = 2.dp,
radius = 10.dp
)
} else {
setShapeDrawable(
solidColor = "#FFF5F5F5",
radius = 10.dp
)
}
}
}
}
}
@@ -0,0 +1,79 @@
package com.sw.inbound.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.graphics.toColorInt
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.R
import com.sw.inbound.databinding.ListItemReceiptGoodsBinding
import com.sw.inbound.model.bean.ReceiptGoodsInfo
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.ifNullOrBlank
import com.sw.inbound.utils.ext.ifNullOrZero
import com.sw.inbound.utils.ext.setShapeDrawable
import com.sw.inbound.utils.ext.visible
class ReceiptGoodsAdapter(var list: MutableList<GoodsInfo>) :
BaseQuickAdapter<GoodsInfo, ReceiptGoodsAdapter.VH>(list) {
inner class VH(var binding: ListItemReceiptGoodsBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemReceiptGoodsBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: GoodsInfo?) {
holder.binding.run {
root.updateLayoutParams<RecyclerView.LayoutParams> {
height = 100.dp
topMargin = 2.dp
bottomMargin = 3.dp
}
root.setShapeDrawable(
solidColor = if (item!!.isSelected) "#FFD5E1FF" else "#FFFFFFFF",
radius = 6.dp
)
updateTextView(
tvGoodsName, tvProcurementUnit,
tvProcurementCount, tvProcurementPrice,
tvProcurementAmount, tvReceiptCount, tvGoodsWeight,
)
tvGoodsName.text = item.goodName.ifNullOrBlank("-")
tvProcurementUnit.text = item.unitName.ifNullOrBlank("-")
tvProcurementCount.text = item.receiveCountStr.ifNullOrBlank("-")
tvProcurementPrice.text = item.recUnitPriceTaxInStr.ifNullOrBlank("-")
tvProcurementAmount.text = item.recPriceExItemStr.ifNullOrBlank("-")
tvReceiptCount.text = item.receivedNumStr.ifNullOrBlank("-")
tvGoodsWeight.text = item.goodsWeightStr.ifNullOrBlank("-")
tvState.gone()
ivState.run {
visible()
setImageResource(
if (item.isSelected.not()) R.mipmap.ic_receipt_no
else if (item.isLocalGoods) R.mipmap.ic_receipt_local
else if ((item.receivedNum?:0.toDouble()) < (item.receiveCount?:0.toDouble())) R.mipmap.ic_receipt_part
else R.mipmap.ic_receipt_all
)
}
}
}
private fun updateTextView(vararg views: TextView) {
views.forEach {
it.setTextColor("#FF1E2832".toColorInt())
it.paint.isFakeBoldText = true
}
}
}
@@ -0,0 +1,48 @@
package com.sw.inbound.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import coil.load
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.databinding.ListItemRecognizeBinding
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.setShapeDrawable
import com.sw.inbound.utils.ext.setShapeDrawable2
class RecognizeAdapter(var list: MutableList<SearchGoodsInfo.Record>) :
BaseQuickAdapter<SearchGoodsInfo.Record, RecognizeAdapter.VH>(list) {
inner class VH(var binding: ListItemRecognizeBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemRecognizeBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: SearchGoodsInfo.Record?) {
holder.binding.let {
it.tvRecName.run {
text = item?.goodsName
setShapeDrawable2(
solidColor = "#DEF5F5F5",
bottomRightRadius = 12.dp,
bottomLeftRadius = 12.dp
)
}
it.ivRecImage.load(item!!.relativeUrl)
it.root.run {
setShapeDrawable(
strokeColor = if (item.isSelected) "#FF0033CC" else "#FFDCDCF0",
strokeWidth = 2.dp,
radius = 12.dp
)
//setPadding(if (item.isSelected) 2.dp else 0)
}
}
}
}
@@ -0,0 +1,65 @@
package com.sw.inbound.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.graphics.toColorInt
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.inbound.databinding.ListItemSelfProcurementBinding
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.ifNullOrBlank
import com.sw.inbound.utils.ext.setShapeDrawable
import com.sw.inbound.utils.ext.visible
class SelfProcurementAdapter(var list: MutableList<GoodsInfo>) :
BaseQuickAdapter<GoodsInfo, SelfProcurementAdapter.VH>(list) {
inner class VH(var binding: ListItemSelfProcurementBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemSelfProcurementBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: GoodsInfo?) {
holder.binding.run {
root.updateLayoutParams<RecyclerView.LayoutParams> {
height = 100.dp
topMargin = 2.dp
bottomMargin = 3.dp
}
root.setShapeDrawable(
solidColor = if (item!!.isSelected) "#FFD5E1FF" else "#FFFFFFFF",
radius = 6.dp
)
updateTextView(
tvGoodsName, tvProcurementUnit,
tvProcurementCount, tvProcurementPrice,
tvProcurementAmount
)
tvGoodsName.text = item.goodName.ifNullOrBlank("-")
tvProcurementUnit.text = item.unitName.ifNullOrBlank("-")
tvProcurementCount.text = item.receiveCountStr.ifNullOrBlank("-")
tvProcurementPrice.text = item.recUnitPriceTaxInStr.ifNullOrBlank("-")
tvProcurementAmount.text = item.recPriceExItemStr.ifNullOrBlank("-")
tvState.gone()
ivState.visible()
}
}
private fun updateTextView(vararg views: TextView) {
views.forEach {
it.setTextColor("#FF1E2832".toColorInt())
it.paint.isFakeBoldText = true
}
}
}
@@ -0,0 +1,146 @@
//package com.sw.inbound.dialog
//
//import android.content.Context
//import android.graphics.SurfaceTexture
//import android.view.LayoutInflater
//import android.view.TextureView
//import android.view.View
//import android.widget.FrameLayout
//import android.widget.TextView
//import androidx.compose.ui.text.style.LineHeightStyle
//import com.sw.inbound.GlobalData
//import com.sw.inbound.activity.GoodsListActivity
//import com.sw.inbound.databinding.DialogAddGoodsBinding
//import com.sw.inbound.model.response.DictType
//import com.sw.inbound.utils.ext.dp
//import com.sw.inbound.utils.ext.gone
//import com.sw.inbound.utils.ext.toast
//import com.sw.inbound.utils.ext.visible
//import kotlin.math.min
//
//class AddGoodsDialog(
// context: Context,
// var cancelBlock: () -> Unit = {},
// var confirmBlock: () -> Unit = {},
//) : BaseDialog(context) {
//
// private lateinit var binding: DialogAddGoodsBinding
// override fun getRootView(): View {
// val inflater = LayoutInflater.from(context)
// binding = DialogAddGoodsBinding.inflate(inflater)
// return binding.root
// }
//
// private var dropdownPopup: DropdownPopup? = null
//
// private val dropdownList: MutableList<DictType> = mutableListOf()
// private var activity: GoodsListActivity? = null
// override fun initView() {
// activity = getReceiptActivity()
// binding.previewView.let {
// it.visible()
// activity?.setPreviewController(it)
// activity?.setPreviewController(it)
//// val textureView = it.getChildAt(0) as? TextureView
//// textureView?.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
//// override fun onSurfaceTextureAvailable(
//// surface: SurfaceTexture,
//// width: Int,
//// height: Int
//// ) {
//// it.visible()
//// activity?.setPreviewController(it)
//// }
////
//// override fun onSurfaceTextureSizeChanged(
//// surface: SurfaceTexture,
//// width: Int,
//// height: Int
//// ) {
//// }
////
//// override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
//// return true
//// }
////
//// override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
//// }
//// }
// }
// binding.ivGoodsImage.gone()
// binding.btnClose.setOnClickListener {
// cancelBlock()
// dismiss()
// }
// binding.btnConfirm.setOnClickListener {
// confirmBlock()
// dismiss()
// }
// binding.btnStartPreview.setOnClickListener {
// binding.ivGoodsImage.gone()
// }
// binding.btnTakePhoto.setOnClickListener {
// activity?.takePhoto { uri ->
// binding.ivGoodsImage.setImageURI(uri)
// binding.ivGoodsImage.visible()
// }
// }
// showDropDownList(
// binding.flProcurementUnit,
// textView = binding.tvProcurementUnit,
// list = GlobalData.unitTypeList,
// height = 213.dp
// )
// showDropDownList(
// binding.flGoodsType,
// textView = binding.tvGoodsType,
// list = GlobalData.goodsTypeList,
// )
// showDropDownList(
// binding.flStorageType,
// textView = binding.tvStorageType,
// list = GlobalData.storageTypeList,
// )
// showDropDownList(
// dropdownView = binding.flWarehouseUnit,
// textView = binding.tvWarehouseUnit,
// list = GlobalData.unitTypeList
// ) {
// binding.tvSelectUseUnit.text = it.value
// }
// }
//
// private fun showDropDownList(
// dropdownView: FrameLayout,
// textView: TextView,
// list: List<DictType>,
// height: Int = 355.dp,
// block:(DictType)-> Unit= {}
// ) {
// dropdownView.setOnClickListener {
// dropdownList.clear()
// val tempList =
// list.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
// if (tempList.isEmpty()) {
// context.toast("暂无下拉数据")
// return@setOnClickListener
// }
// dropdownList.addAll(tempList)
// val realHeight = min(height, dropdownList.size * 71.dp)
// dropdownPopup = DropdownPopup(
// context = context,
// list = dropdownList,
// popWidth = dropdownView.width,
// popHeight = realHeight
// ) {
// textView.text = it.value
// block(it)
// }
// dropdownPopup?.showAsDropDown(dropdownView)
// dropdownPopup?.setOnDismissListener {
// dropdownPopup = null
// }
// }
// }
//
//}
@@ -0,0 +1,32 @@
//package com.sw.inbound.dialog
//
//import android.content.Context
//import android.view.LayoutInflater
//import android.view.View
//import com.sw.inbound.databinding.DialogAddProcurementUnitBinding
//
//class AddProcurementUnitDialog(
// context: Context,
// var cancelBlock: () -> Unit = {},
// var confirmBlock: () -> Unit = {},
//) : BaseDialog(context) {
//
// private lateinit var binding: DialogAddProcurementUnitBinding
// override fun getRootView(): View {
// val inflater = LayoutInflater.from(context)
// binding = DialogAddProcurementUnitBinding.inflate(inflater)
// return binding.root
// }
//
// override fun initView() {
// binding.tvSelectUnit.text = "箱"
// binding.btnCancel.setOnClickListener {
// cancelBlock()
// dismiss()
// }
// binding.btnConfirm.setOnClickListener {
// confirmBlock()
// dismiss()
// }
// }
//}
@@ -0,0 +1,50 @@
package com.sw.inbound.dialog
import android.app.Dialog
import android.content.Context
import android.content.ContextWrapper
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.View
import com.sw.inbound.R
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.hideKeyboard
abstract class BaseDialog(
context: Context,
var defWidth: Int = 1500.dp,
var defHeight: Int = 900.dp
) : Dialog(context, R.style.DialogTheme) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val rootView = getRootView()
setContentView(rootView)
setCancelable(false)
setCanceledOnTouchOutside(false)
window?.apply {
setLayout(defWidth, defHeight)
setBackgroundDrawable(ColorDrawable())
setGravity(Gravity.CENTER)
}
rootView.setOnClickListener { it.hideKeyboard() }
initView()
}
abstract fun getRootView(): View
abstract fun initView()
fun getReceiptActivity(): GoodsListActivity? {
var ctx = context
while (ctx is ContextWrapper) {
ctx = ctx.baseContext
if (ctx is GoodsListActivity) {
return ctx
}
}
return null
}
}
@@ -0,0 +1,60 @@
package com.sw.inbound.dialog
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.sw.inbound.R
import com.sw.inbound.adapter.DropdownAdapter
import com.sw.inbound.model.response.DictType
import com.sw.inbound.utils.ext.dp
class DropdownPopup(
var context: Context,
var list: MutableList<DictType>,
var popWidth:Int = 280.dp,
var popHeight:Int = 284.dp,
var onPopupItemClick: (DictType) -> Unit
) : PopupWindow() {
init {
// 初始化PopupWindow
val popupView = LayoutInflater.from(context).inflate(R.layout.layout_popup_dropdown, null)
contentView = popupView
width = ViewGroup.LayoutParams.WRAP_CONTENT
height = ViewGroup.LayoutParams.WRAP_CONTENT
// 设置透明背景,避免覆盖圆角
setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
isOutsideTouchable = true
isFocusable = true
// 设置动画样式
// animationStyle = R.style.PopupAnimation
// 初始化视图和事件
initViews(popupView)
}
private fun initViews(view: View) {
// 获取关闭按钮并设置点击事件
view.findViewById<RecyclerView>(R.id.rvWarehouse)?.let {
it.updateLayoutParams {
width = popWidth
height = popHeight
}
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
it.adapter = DropdownAdapter(list).setOnItemClickListener { adapter, view, position ->
onPopupItemClick(list[position])
dismiss()
}
}
}
}
@@ -0,0 +1,87 @@
package com.sw.inbound.dialog
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.adapter.RecognizeAdapter
import com.sw.inbound.databinding.DialogGoodsRecognizeBinding
import com.sw.inbound.databinding.LayoutEmptyRecognizeBinding
import com.sw.inbound.model.response.SearchGoodsInfo
@SuppressLint("NotifyDataSetChanged")
class GoodsRecognizeDialog(
context: Context,
var list: MutableList<SearchGoodsInfo.Record>,
var dismissDialog: () -> Unit,
var findGoods: () -> Unit
) : BaseDialog(context) {
private lateinit var binding: DialogGoodsRecognizeBinding
private lateinit var inflater: LayoutInflater
override fun getRootView(): View {
inflater = LayoutInflater.from(context)
binding = DialogGoodsRecognizeBinding.inflate(inflater)
return binding.root
}
override fun dismiss() {
dismissDialog()
super.dismiss()
}
private val recognizeAdapter by lazy {
RecognizeAdapter(list).apply {
isStateViewEnable = true
setOnItemClickListener { adapter, view, position ->
if (list[position].isSelected) {
GoodsStoreDialog(context, list[position]) {
activity?.addGoods(it)
}.show()
return@setOnItemClickListener
}
list.forEach { item ->
item.isSelected = false
}
list[position].isSelected = true
notifyDataSetChanged()
GoodsStoreDialog(context, list[position]) {
activity?.addGoods(it)
}.show()
}
}
}
private var activity: GoodsListActivity? = null
override fun initView() {
activity = getReceiptActivity()
binding.rvRecognize.let {
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
it.adapter = recognizeAdapter
}
if (recognizeAdapter.list.isEmpty()) {
loadEmptyView()
}
binding.ivClose.setOnClickListener { dismiss() }
binding.btnManuallyFind.setOnClickListener {
findGoods()
//dismiss()
}
binding.btnAgainRecognize.setOnClickListener {
dismiss()
activity?.recognizeFood()
}
}
private var emptyBinding: LayoutEmptyRecognizeBinding? = null
private fun loadEmptyView() {
if (emptyBinding == null) {
emptyBinding = LayoutEmptyRecognizeBinding.inflate(inflater, binding.rvRecognize, false)
}
emptyBinding?.root?.let {
recognizeAdapter.stateView = it
}
}
}
@@ -0,0 +1,156 @@
package com.sw.inbound.dialog
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.adapter.GoodsSearchAdapter
import com.sw.inbound.databinding.DialogGoodsSearchBinding
import com.sw.inbound.databinding.LayoutEmptySearchBinding
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.utils.ext.addOnActionSearchListener
import com.sw.inbound.utils.ext.hideKeyboard
import com.sw.inbound.utils.ext.toast
class GoodsSearchDialog(
context: Context
) : BaseDialog(context) {
private lateinit var inflater: LayoutInflater
private var emptyBinding: LayoutEmptySearchBinding? = null
private lateinit var binding: DialogGoodsSearchBinding
override fun getRootView(): View {
inflater = LayoutInflater.from(context)
binding = DialogGoodsSearchBinding.inflate(inflater)
return binding.root
}
private var activity: GoodsListActivity? = null
override fun initView() {
activity = getReceiptActivity()
binding.ivClose.setOnClickListener { dismiss() }
binding.ivGoodsSearch.setOnClickListener { searchGoods() }
binding.etInputGoods.let { v ->
v.addOnActionSearchListener {
searchGoods()
}
}
// binding.btnAddGoods.setOnClickListener {
// AddGoodsDialog(context).show()
// }
binding.btnConfirm.setOnClickListener {
if (list.isEmpty()) {
context.toast("请搜索物品")
return@setOnClickListener
}
if (clickIndex == -1) {
context.toast("请选择物品")
return@setOnClickListener
}
GoodsStoreDialog(context, list[clickIndex]) {
activity?.addGoods(it)
}.show()
}
binding.rvSearch.let {
it.layoutManager = GridLayoutManager(context, 2, LinearLayoutManager.VERTICAL, false)
it.adapter = searchAdapter
}
binding.refreshLayout.let {
it.setEnableRefresh(true)
it.setEnableLoadMore(false)
it.setOnRefreshListener {
pageNo = 1
searchGoods()
}
it.setOnLoadMoreListener {
searchGoods()
}
}
loadEmptyView()
}
private var pageNo = 1
companion object {
private const val PAGE_SIZE = 10
}
@SuppressLint("NotifyDataSetChanged")
private fun searchGoods() {
val searchName = binding.etInputGoods.text.toString().trim()
if (searchName.isBlank()) {
activity?.toast("请输入物品名称")
finishRefresh()
return
}
activity?.searchGoods(
searchName = searchName,
pageNo = pageNo,
pageSize = PAGE_SIZE
) { records ->
finishRefresh()
binding.etInputGoods.hideKeyboard()
if (pageNo == 1) {
list.clear()
}
list.addAll(records)
if (list.isEmpty()) {
loadEmptyView()
return@searchGoods
}
val enableLoadMore = records.size >= PAGE_SIZE
binding.refreshLayout.setEnableLoadMore(enableLoadMore)
if (enableLoadMore) {
pageNo++
}
binding.rvSearch.layoutManager =
GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false)
searchAdapter.notifyDataSetChanged()
}
}
private fun loadEmptyView() {
binding.rvSearch.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
if (emptyBinding == null) {
emptyBinding = LayoutEmptySearchBinding.inflate(inflater, binding.rvSearch, false)
}
emptyBinding?.root?.let { layout ->
layout.setOnClickListener { layout.hideKeyboard() }
searchAdapter.stateView = layout
}
}
private var clickIndex = -1
private val list: MutableList<SearchGoodsInfo.Record> = mutableListOf()
private val searchAdapter by lazy {
GoodsSearchAdapter(list).apply {
isStateViewEnable = true
setOnItemClickListener { adapter, view, position ->
this@GoodsSearchDialog.clickIndex = position
if (list[position].isSelected) {
return@setOnItemClickListener
}
list.forEach { item ->
item.isSelected = false
}
list[position].isSelected = true
notifyDataSetChanged()
}
}
}
private fun finishRefresh() {
binding.refreshLayout.let {
if (pageNo == 1) {
it.finishRefresh(500)
} else {
it.finishLoadMore(500)
}
}
}
}
@@ -0,0 +1,205 @@
package com.sw.inbound.dialog
import android.content.Context
import android.graphics.Typeface
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import androidx.core.graphics.toColorInt
import androidx.core.widget.addTextChangedListener
import coil.load
import com.shuwei.intelligent.shelves.utils.ext.appendText
import com.shuwei.intelligent.shelves.utils.ext.buildSpannableString
import com.sw.inbound.GlobalData
import com.sw.inbound.R
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.databinding.DialogGoodsStoreBinding
import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.toast
import kotlin.Int
class GoodsStoreDialog(
context: Context,
var goods: SearchGoodsInfo.Record,
var cancelBlock: () -> Unit = {},
var confirmBlock: (GoodsInfo) -> Unit = {},
) : BaseDialog(context) {
private lateinit var binding: DialogGoodsStoreBinding
private lateinit var inflater: LayoutInflater
override fun getRootView(): View {
inflater = LayoutInflater.from(context)
binding = DialogGoodsStoreBinding.inflate(inflater)
return binding.root
}
private val dropdownList: MutableList<DictType> = mutableListOf()
private var dropdownPopup: DropdownPopup? = null
private var realWeight: Int = 0
private var activity: GoodsListActivity? = null
override fun initView() {
activity = getReceiptActivity()
activity?.readWeightInfo { weight ->
this.realWeight = weight
binding.tvTotalWeight.text = getSpannable(weight)
}
binding.etGoodsName.run {
setText(goods.goodsName)
isEnabled = false
}
binding.ivGoodsImage.load(goods.relativeUrl)
binding.btnCancel.setOnClickListener {
cancelBlock()
dismiss()
}
binding.btnConfirm.setOnClickListener {
confirmInputData()
}
// binding.ivAddUnit.setOnClickListener {
// AddProcurementUnitDialog(context).show()
// }
binding.flUnitDropdown.setOnClickListener { v ->
if (dropdownPopup == null) {
dropdownList.clear()
dropdownList.addAll(GlobalData.unitTypeList)
dropdownPopup = DropdownPopup(
context = context,
list = dropdownList,
popWidth = 428.dp
) {
binding.tvProcurementUnit.run {
text = it.value
tag = it.id
}
}
}
dropdownPopup?.showAsDropDown(v)
}
binding.btnClearZero.setOnClickListener {
SensorScaleUtils.tare()
}
//addPriceInputListener(binding.etProcurementPrice) {
// val countText = binding.etProcurementCount.text.trim().toString()
// val count = if (countText.isNotBlank()) countText.toInt() else 0
// val amount = (it * count).toFormattedString(2)
// binding.etProcurementAmount.setText(amount)
//}
addPriceInputListener(binding.etProcurementAmount) {
val countText = binding.etProcurementCount.text.trim().toString()
val count = if (countText.isNotBlank()) countText.toInt() else 0
val price = (it / count).toFormattedString(2)
binding.tvProcurementPrice.text = price
}
binding.etProcurementCount.run {
addTextChangedListener(onTextChanged = { it, _, _, _ ->
try {
if (isFocused.not()) {
return@addTextChangedListener
}
val amountText = binding.etProcurementAmount.text.toString().trim()
if (amountText.isEmpty()) {
return@addTextChangedListener
}
val input = it ?: ""
val count = if (input.isNotBlank()) input.toString().toInt() else 0
val amount = amountText.toDouble()
val price = amount / count
binding.tvProcurementPrice.text = price.toFormattedString(2)
} catch (e: Exception) {
e.printStackTrace()
}
})
}
}
private fun addPriceInputListener(editText: EditText, action: (Double) -> Unit) {
editText.run {
addTextChangedListener(onTextChanged = { it, _, _, _ ->
try {
if (editText.isFocused.not()) {
return@addTextChangedListener
}
val input = it ?: ""
if (input.startsWith(".")) {
setText("0.")
setSelection(length())
} else if (input.contains(".")) {
val index = input.indexOf(".")
if (input.length - index > 3) {
setText(input.substring(0, index + 3))
setSelection(length())
}
}
val value = if (input.toString() == "0.") 0.0 else input.toString().toDouble()
action(value)
} catch (e: Exception) {
e.printStackTrace()
}
})
}
}
private fun getSpannable(num: Int): SpannableStringBuilder {
return buildSpannableString {
appendText(
num.toString(),
ForegroundColorSpan("#FF141428".toColorInt()),
StyleSpan(Typeface.BOLD)
)
appendText(
"",
ForegroundColorSpan("#FF000033".toColorInt()),
StyleSpan(Typeface.BOLD)
)
}
}
private fun confirmInputData() {
val unit = binding.tvProcurementUnit.text.trim().toString()
if (unit.isBlank()) {
context.toast("请选择单位")
return
}
val countText = binding.etProcurementCount.text.trim().toString()
if (countText.isBlank()) {
context.toast("请录入数量")
return
}
val priceText = binding.tvProcurementPrice.text.trim().toString()
if (priceText.isBlank()) {
context.toast("请录入单价")
return
}
val amountText = binding.etProcurementAmount.text.trim().toString()
if (amountText.isBlank()) {
context.toast("请录入金额")
return
}
confirmBlock(
GoodsInfo(
goodId = goods.id,
goodName = goods.goodsName,
consumeValue = goods.purchaseValue,
//goodsPurId = binding.tvProcurementUnit.tag.toString(),
kcUnitId = binding.tvProcurementUnit.tag.toString(),
unitName = unit,
receiveCount = countText.toDoubleOrNull(),
recUnitPriceTaxIn = priceText.toDoubleOrNull(),
recPriceExItem = amountText.toDoubleOrNull(),
goodsWeight = realWeight.toBigDecimal(),
isLocalGoods = true
)
)
dismiss()
}
}
@@ -0,0 +1,34 @@
package com.sw.inbound.dialog
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import com.sw.inbound.databinding.DialogNotReceiptWarnBinding
import com.sw.inbound.utils.ext.dp
class NotReceiptWarnDialog(
context: Context,
var cancelBlock: () -> Unit = {},
var confirmBlock: () -> Unit = {},
) : BaseDialog(context = context, defWidth = 960.dp, defHeight = 540.dp) {
private lateinit var binding: DialogNotReceiptWarnBinding
override fun getRootView(): View {
val inflater = LayoutInflater.from(context)
binding = DialogNotReceiptWarnBinding.inflate(inflater)
return binding.root
}
override fun initView() {
binding.btnCancel.setOnClickListener {
cancelBlock()
dismiss()
}
binding.btnConfirm.setOnClickListener {
confirmBlock()
dismiss()
}
}
}
@@ -0,0 +1,48 @@
package com.sw.inbound.model.bean
data class ReceiptGoodsInfo(
var goodsId: String? = "",
var goodsName: String? = "",
var procurementUnit: String? = "",
var procurementCount: Int? = 0,
var procurementPrice: Double? = 0.0,
var procurementAmount: Double? = 0.0,
var receiptCount: Int? = 0,
var goodsWeight: Int? = 0,
var goodsState: String? = "",
var isSelected: Boolean = false,
var isLocalGoods: Boolean = false
)
//data class DropdownInfo(
// var id: String,
// var name: String
//)
//data class RecognizeResult(
// var name: String? = null,
// var image: String? = null,
// var isSelected: Boolean = false
//)
//data class GoodsSearchInfo(
// var id: String? = null,
// var name: String? = null,
// var isSelected: Boolean = false
//)
data class OperateBean(
var obj: Any? = null,
var typeList: MutableList<OperateType> = mutableListOf(),
var isSelected: Boolean = false,
var isLocalGoods: Boolean = false,
var isReceiptPage: Boolean = true
)
data class OperateType(
var value: String = "",
var width: Int = 0,
var textColor: String = "#FF999999",
var isBoldFont: Boolean = false,
var isShowIcon: Boolean = false
)
@@ -21,7 +21,8 @@ data class GoodsAddParam(
/**
* 物品类型
*/
var goodType: Int? = null,
// var goodType: Int? = null,
var goodType: String? = null,
/**
* 存储方式
@@ -85,7 +86,7 @@ data class GoodsAddParam(
storageTypeStr = value
}
get() {
return GlobalData.storageTypeList.find { it.id == storageType }?.value ?: ""
return GlobalData.storageTypeList.find { it.id == storageType.toString() }?.value ?: ""
}
val netRateStr: String
@@ -99,7 +100,7 @@ data class GoodsAddParam(
val unitIdStr: String
get() {
return GlobalData.unitTypeList.find { it.id == unitId }?.value ?: ""
return GlobalData.unitTypeList.find { it.id == unitId.toString() }?.value ?: ""
}
val unitIdStrPlace: String
@@ -121,13 +122,13 @@ data class GoodsAddParam(
if (purchaseUnit == 0) {
return ""
}
return GlobalData.unitTypeList.find { it.id == purchaseUnit }?.value ?: ""
return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: ""
}
fun hasNullField(): String? {
if (goodName == null || goodName!!.isEmpty())
return "请录入物品名称"
if (goodType == null || goodType == 0) {
if (goodType.isNullOrBlank() || goodType == "0") {
return "请选择物品类型"
}
if (storageType == null || storageType == 0) {
@@ -19,7 +19,7 @@ data class GoodsPurchaseUnitParam(
val unitIdStr: String
get() {
if (unitId == 0) return ""
return GlobalData.unitTypeList.find { it.id == unitId }?.value ?: ""
return GlobalData.unitTypeList.find { it.id == unitId.toString() }?.value ?: ""
}
val purchaseUnitStr: String
@@ -27,7 +27,7 @@ data class GoodsPurchaseUnitParam(
if (purchaseUnit == 0) {
return ""
}
return GlobalData.unitTypeList.find { it.id == purchaseUnit }?.value ?: ""
return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: ""
}
fun hasNullField(): String? {
@@ -17,11 +17,11 @@ data class PurchaseWarehouseParam(
/**
* 物品id
*/
var goodsId: Int = 0,
var goodsId: String = "",
/**
* 库存单位
*/
var kcUnitId: Int = -1,
var kcUnitId: String? = "",
/**
* 入库数量
*/
@@ -45,11 +45,11 @@ data class PurchaseWarehouseParam(
/**
* (物品列表里 businessUnitId字段的值)
*/
var goodPurId: Int = -1,
var goodPurId: String?="",
/**
* 仓库id
*/
var warehouseId: Int = -1,
var warehouseId: String?="",
/**
* 采购库存转换关系
@@ -75,10 +75,10 @@ data class PurchaseWarehouseParam(
val warehouseNameStr: String
get() {
if (warehouseId == -1) {
if (warehouseId.isNullOrBlank()) {
return ""
}
return GlobalData.warehouseTypeList.find { it.id == warehouseId }?.value ?: ""
return GlobalData.warehouseTypeList.find { it.id == warehouseId.toString() }?.value ?: ""
// if (warehouseName == null) {
// return ""
// }
@@ -111,15 +111,15 @@ data class PurchaseWarehouseParam(
return goodsName!!
}
val unitDictTypeList: List<DictType>
get() {
return if (unitList == null) emptyList()
else {
unitList!!.filter { it.businessUnitId != null && it.purchaseUnitName != null }.map {
DictType(it.businessUnitId?.toInt() ?: 0, it.purchaseUnitName ?: "")
}
}
}
// val unitDictTypeList: List<DictType>
// get() {
// return if (unitList == null) emptyList()
// else {
// unitList!!.filter { it.businessUnitId != null && it.purchaseUnitName != null }.map {
// DictType(it.businessUnitId?.toInt() ?: 0, it.purchaseUnitName ?: "")
// }
// }
// }
val unitNameStr: String
get() {
@@ -152,12 +152,12 @@ data class PurchaseWarehouseParam(
}
fun hasNullField(): String? {
if (goodsId == null || goodsId == 0 || goodsName == null || goodsName!!.isEmpty())
if (goodsId.isNullOrBlank() || goodsName == null || goodsName!!.isEmpty())
return "请选择物品"
if (warehouseId == null || warehouseId == -1) {
if (warehouseId.isNullOrBlank()) {
return "请选择仓库"
}
if (goodPurId == null || goodPurId == -1) {
if (goodPurId.isNullOrBlank()) {
return "请选择采购单位"
}
if (goodsCount == null || goodsCount == 0.0) {
@@ -14,11 +14,11 @@ data class UploadInfo(
/**
* 收货单id
*/
var id: Int,
var id: String,
/**
* 供应商id
*/
var supplierId: Int? = null,
var supplierId: String? = null,
/**
*
* 物品信息 【全部收货使用】
@@ -77,7 +77,7 @@ private data class UploadGoodsInfo(
/**
* 采购单位id
*/
var purchaseUnitId: Int = 0,
var purchaseUnitId: String = "",
/**
* 收货数量
@@ -1,11 +1,24 @@
package com.sw.inbound.model.response
//data class ApiResponse<T>(
// val code: Int,
// val success: Boolean? = false,
// val message: String? = "",
// val result: T? = null,
// val timestamp: Long? = 0
//) {
// fun isSuccess(): Boolean = code == 200
//}
data class ApiResponse<T>(
val code: Int,
val success: Boolean? = false,
val message: String? = "",
val result: T? = null,
val timestamp: Long? = 0
val code: String,
val msg: String? = "",
val data: T? = null
) {
fun isSuccess(): Boolean = code == 200
fun isSuccess(): Boolean = code == "00000"
val result: T?
get() = data
val message: String?
get() = msg
}
@@ -8,6 +8,6 @@ import kotlinx.parcelize.Parcelize
*/
@Parcelize
data class DictType(
val id: Int,
val value: String
val id: String?=null,
val value: String?=null
) : Parcelable
@@ -16,11 +16,11 @@ data class GoodsInfo(
/**
* 数据id
*/
var id: Int? = 0,
var id: String? = "",
/**
* 物品Id
*/
var goodId: Int? = 0,
var goodId: String? = "",
/**
* 物品名称
*/
@@ -28,7 +28,7 @@ data class GoodsInfo(
/**
* 单价
*/
var recUnitPriceTaxIn: Float? = null,
var recUnitPriceTaxIn: Double? = null,
// 单价 界面显示
var recUnitPriceTaxInTemp: String = "",
@@ -36,7 +36,7 @@ data class GoodsInfo(
/**
* 新单价 部分收货需要
*/
var newRecUnitPriceTaxIn: Float? = null,
var newRecUnitPriceTaxIn: Double? = null,
var newRecUnitPriceTaxInTemp: String = "",
/**
@@ -47,22 +47,22 @@ data class GoodsInfo(
/**
* 采购单位id
*/
var purchaseUnitId: Int? = null,
var purchaseUnitId: String? = null,
/**
* 采购数量
*/
var receiveCount: Float? = null,
var receiveCount: Double? = null,
/**
* 金额
*/
var recPriceExItem: Float? = null,
var recPriceExItem: Double? = null,
// 金额 界面显示
var recPriceExItemTemp: String = "",
/**
* 仓库id
*/
var warehouseId: Int? = null,
var warehouseId: String? = null,
/**
* 仓库名称
*/
@@ -71,7 +71,7 @@ data class GoodsInfo(
/**
* 物品采购单位关系
*/
var goodsPurId: Int? = 0,
var goodsPurId: String? = "",
/**
* 采购库存转换值
*/
@@ -86,7 +86,7 @@ data class GoodsInfo(
var consumeValue: String? = "",
// 收货数量 收货入参
var receivedNum: Float? = null,
var receivedNum: Double? = null,
// 收货数量显示
var receivedNumTemp: String = "",
// 重量 收货入参
@@ -96,7 +96,12 @@ data class GoodsInfo(
var isAdjusted: Boolean = false,
// 选中物品的可选单位
var unitList: List<UnitVo> = emptyList<UnitVo>()
var unitList: List<UnitVo> = emptyList<UnitVo>(),
//--------------------------------------------------------
var isSelected: Boolean = false,
var isLocalGoods: Boolean = false,
var kcUnitId: String?=""
//--------------------------------------------------------
) : Parcelable, BaseBean() {
val goodNameStr: String
@@ -120,7 +125,7 @@ data class GoodsInfo(
val receivedNumCount: String
get() {
if (receivedNum == null || receivedNum == 0f)
if (receivedNum == null || receivedNum == 0.toDouble())
return "0"
return receivedNum?.toSafeString(unitName) ?: "0"
@@ -128,9 +133,9 @@ data class GoodsInfo(
val dualCountStr: String
get() {
return if (receivedNum != null && receivedNum != 0f && receiveCount != null && receiveCount != 0f) {
return if (receivedNum != null && receivedNum != 0.toDouble() && receiveCount != null && receiveCount != 0.toDouble()) {
"${receivedNum.toSafeString(unitName)}/${receiveCount.toSafeString(unitName)}"
} else if (receivedNum != null && receivedNum != 0f) {
} else if (receivedNum != null && receivedNum != 0.toDouble()) {
"${receivedNum.toSafeString(unitName)}/-"
} else {
receiveCountListStr
@@ -139,33 +144,33 @@ data class GoodsInfo(
val recUnitPriceTaxInStr: String
get() {
if (recUnitPriceTaxIn == 0f) return ""
if (recUnitPriceTaxIn == 0.toDouble()) return ""
return recUnitPriceTaxIn?.toFormattedString() ?: ""
}
val recUnitPriceTaxInListStr: String
get() {
if (recUnitPriceTaxIn == 0f) return "-"
if (recUnitPriceTaxIn == 0.toDouble()) return "-"
return recUnitPriceTaxIn?.toFormattedString() ?: "-"
}
val newRecUnitPriceTaxInListStr: String
get() {
if (newRecUnitPriceTaxIn == 0f) return "-"
if (newRecUnitPriceTaxIn == 0.toDouble()) return "-"
return newRecUnitPriceTaxIn?.toFormattedString() ?: "-"
}
val receiveCountStr: String
get() {
return when (receiveCount) {
0f -> ""
0.toDouble() -> ""
else -> receiveCount?.toSafeString(unitName) ?: ""
}
}
val receiveCountListStr: String
get() {
return when (receiveCount) {
0f -> "-"
0.toDouble() -> "-"
else -> receiveCount?.toSafeString(unitName) ?: "-"
}
}
@@ -173,14 +178,14 @@ data class GoodsInfo(
val recPriceExItemStr: String
get() {
return when (recPriceExItem) {
0f -> ""
0.toDouble() -> ""
else -> recPriceExItem?.toFormattedString() ?: ""
}
}
val recPriceExItemListStr: String
get() {
return when (recPriceExItem) {
0f -> "-"
0.toDouble() -> "-"
else -> recPriceExItem?.toFormattedString() ?: "-"
}
}
@@ -217,7 +222,7 @@ data class GoodsInfo(
purchaseUnitIdStr = value
}
get() {
return GlobalData.unitTypeList.find { it.id == purchaseUnitId }?.value ?: ""
return GlobalData.unitTypeList.find { it.id == purchaseUnitId.toString() }?.value ?: ""
}
val warehouseNameStr: String
@@ -229,16 +234,16 @@ data class GoodsInfo(
}
fun hasNullField(): String? {
if (warehouseId == null) {
if (warehouseId.isNullOrBlank()) {
return "请选择仓库"
}
if (receivedNum == null || receivedNum == 0f) {
if (receivedNum == null || receivedNum == 0.toDouble()) {
return "请输入收货数量或进行称重"
}
if (newRecUnitPriceTaxIn == null || newRecUnitPriceTaxIn == 0f) {
if (newRecUnitPriceTaxIn == null || newRecUnitPriceTaxIn == 0.toDouble()) {
return "请输入收货单价"
}
if (recPriceExItem == null || recPriceExItem == 0f) {
if (recPriceExItem == null || recPriceExItem == 0.toDouble()) {
return "请输入收货金额"
}
if (goodsWeight == null || goodsWeight!!.toFloat() <= 0) {
@@ -27,7 +27,7 @@ data class GoodsType(
* 物品id
*/
@SerializedName("id")
val id: Int? = 0,
val id: String? = "",
@SerializedName("idResult")
val idResult: String? = "",
@SerializedName("kidTypes")
@@ -37,7 +37,7 @@ data class GoodsType(
@SerializedName("pageSize")
val pageSize: String? = "",
@SerializedName("status")
val status: Int? = 0,
val status: Boolean? = false,
@SerializedName("superName")
val superName: String? = "",
@SerializedName("typeCode")
@@ -7,11 +7,11 @@ data class PurchaseInfo(
/**
* 单据id
*/
var id: Int = 0,
var id: String,
/**
* 供应商id
*/
var supplierId: Int = 0,
var supplierId: String,
/**
* 供应商名称
*/
@@ -31,13 +31,17 @@ data class SearchGoodsInfo(
) : Parcelable {
@Parcelize
data class Record(
@SerializedName("relativeUrl")
val relativeUrl: String? = "",
@SerializedName("goodsCode")
val goodsCode: String? = "",
@SerializedName("id")
val id: String? = "",
/**
* 物品id
*/
@SerializedName("goodsId")
val goodsId: Int? = 0,
val goodsId: String? = "",
/**
* 物品名称
*/
@@ -58,6 +62,7 @@ data class SearchGoodsInfo(
* 库存与克的转换值
*/
val consumeValue: String? = "",
val purchaseValue: String? = "",
@SerializedName("specification")
val specification: String? = "",
@@ -71,7 +76,8 @@ data class SearchGoodsInfo(
@SerializedName("unitVoList")
val unitVoList: List<UnitVo>? = listOf(),
@SerializedName("zjmCode")
val zjmCode: String? = ""
val zjmCode: String? = "",
var isSelected: Boolean = false
) : Parcelable {
val goodsNameStr: String
get() {
@@ -1,53 +1,62 @@
package com.sw.inbound.model.response
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
//import android.os.Parcelable
//import com.google.gson.annotations.SerializedName
//import kotlinx.parcelize.Parcelize
/**
* 存储方式
*/
@Parcelize
data class StorageType(
@SerializedName("childList")
val childList: List<String?>? = listOf(),
@SerializedName("createTime")
val createTime: String? = "",
@SerializedName("createUserNo")
val createUserNo: String? = "",
@SerializedName("depth")
val depth: String? = "",
@SerializedName("description")
val description: String? = "",
@SerializedName("dictId")
val dictId: String? = "",
@SerializedName("eaId")
val eaId: Int? = 0,
@SerializedName("fid")
val fid: String? = "",
@SerializedName("id")
val id: Int? = 0,
@SerializedName("idc")
val idc: String? = "",
/**
* 名称
*/
@SerializedName("itemText")
val itemText: String? = "",
/**
* 对应值
*/
@SerializedName("itemValue")
val itemValue: String? = "",
@SerializedName("level")
val level: Int? = 0,
@SerializedName("sortOrder")
val sortOrder: Int? = 0,
@SerializedName("status")
val status: Int? = 0,
@SerializedName("updateTime")
val updateTime: String? = "",
@SerializedName("updateUserNo")
val updateUserNo: String? = ""
) : Parcelable
val id:String?=null,
val value:String?=null,
val text:String?=null,
val title:String?=null,
val label:String?=null,
)
//@Parcelize
//data class StorageType(
// @SerializedName("childList")
// val childList: List<String?>? = listOf(),
// @SerializedName("createTime")
// val createTime: String? = "",
// @SerializedName("createUserNo")
// val createUserNo: String? = "",
// @SerializedName("depth")
// val depth: String? = "",
// @SerializedName("description")
// val description: String? = "",
// @SerializedName("dictId")
// val dictId: String? = "",
// @SerializedName("eaId")
// val eaId: Int? = 0,
// @SerializedName("fid")
// val fid: String? = "",
// @SerializedName("id")
// val id: String? = "",
// @SerializedName("idc")
// val idc: String? = "",
// /**
// * 名称
// */
// @SerializedName("itemText")
// val itemText: String? = "",
// /**
// * 对应值
// */
// @SerializedName("itemValue")
// val itemValue: String? = "",
// @SerializedName("level")
// val level: Int? = 0,
// @SerializedName("sortOrder")
// val sortOrder: Int? = 0,
// @SerializedName("status")
// val status: Int? = 0,
// @SerializedName("updateTime")
// val updateTime: String? = "",
// @SerializedName("updateUserNo")
// val updateUserNo: String? = ""
//) : Parcelable
@@ -33,7 +33,7 @@ data class SupplierInfo(
* 订单id
*/
@SerializedName("id")
val id: Int = 0,
val id: String? = "",
@SerializedName("pageNum")
val pageNum: String? = "",
@SerializedName("pageSize")
@@ -100,7 +100,7 @@ data class SupplierInfo(
* 供应商id
*/
@SerializedName("supplierId")
val supplierId: Int = 0,
val supplierId: String ? = "",
/**
* 供应商
*/
@@ -13,6 +13,7 @@ import com.sw.inbound.model.response.GoodsType
import com.sw.inbound.model.response.PurchaseInfo
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.model.response.StorageType
import com.sw.inbound.model.response.SupplierInfo
import com.sw.inbound.model.response.SupplierResponse
import com.sw.inbound.model.response.User
import okhttp3.MultipartBody
@@ -30,6 +31,10 @@ import retrofit2.http.Url
* api接口
*/
interface ApiService {
private val apiPrefix: String
get() = "/terminal/neglect/inbound"
/**
* device获取token
*/
@@ -56,28 +61,33 @@ interface ApiService {
suspend fun login(
@Url url: String = "${GlobalData.appBaseUrl}/sys/loginPad",
@Body body: LoginParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<User>
/**
* 采购单入库-列表
*/
@GET//("pad/receivePage")
// @GET//("pad/receivePage")
// suspend fun getReceiveList(
// @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/receivePage",
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int,
//
// ): ApiResponse<SupplierResponse>
@POST
suspend fun getReceiveList(
@Url url: String = "${GlobalData.appBaseUrl}/pad/receivePage",
@Query("pageNo") pageNo: Int,
@Query("pageSize") pageSize: Int,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<SupplierResponse>
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/receivePage",
@Body param:Map<String, String>
): ApiResponse<List<SupplierInfo>?>
/**
* 采购单入库-详情
*/
@GET//("pad/receiveDetail")
suspend fun getReceiveDetail(
@Url url: String = "${GlobalData.appBaseUrl}/pad/receiveDetail",
@Query("id") id: Int,
@Header("x-access-token") token: String = GlobalData.appToken
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/receiveDetail",
@Query("id") id: String
): ApiResponse<PurchaseInfo>
/**
@@ -85,9 +95,8 @@ interface ApiService {
*/
@POST//("pad/partialReceiptGoods")
suspend fun partialReceipt(
@Url url: String = "${GlobalData.appBaseUrl}/pad/partialReceiptGoods",
@Body uploadInfo: UploadInfo,
@Header("x-access-token") token: String = GlobalData.appToken
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/partialReceiptGoods",
@Body uploadInfo: UploadInfo
): ApiResponse<Boolean>
/**
@@ -95,9 +104,8 @@ interface ApiService {
*/
@POST//("pad/saveAndReceiveAndGoWare")
suspend fun confirmReceipt(
@Url url: String = "${GlobalData.appBaseUrl}/pad/saveAndReceiveAndGoWare",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/saveAndReceiveAndGoWare",
@Body uploadInfo: UploadInfo,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean>
/**
@@ -105,9 +113,10 @@ interface ApiService {
*/
@GET//("sys/dict/getDictItemByF")
suspend fun getGoodsStorageType(
@Url url: String = "${GlobalData.appBaseUrl}/sys/dict/getDictItemByF",
@Query("dictCode") dictCode: String = "goods_storage_type",
@Header("x-access-token") token: String = GlobalData.appToken
// @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/sys/dict/getDictItemByF",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/getDictItemByF",
// @Query("dictCode") dictCode: String = "goods_storage_type",
@Query("dictCode") dictCode: String = "ccfs",
): ApiResponse<List<StorageType>>
/**
@@ -115,8 +124,7 @@ interface ApiService {
*/
@GET//("pad/notLimitList")
suspend fun getGoodsType(
@Url url: String = "${GlobalData.appBaseUrl}/pad/notLimitList",
@Header("x-access-token") token: String = GlobalData.appToken
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/notLimitList",
): ApiResponse<GoodsType>
/**
@@ -124,9 +132,8 @@ interface ApiService {
*/
@GET//("pad/dataList")
suspend fun getDictType(
@Url url: String = "${GlobalData.appBaseUrl}/pad/dataList",
@Query("type") type: String,
@Header("x-access-token") token: String = GlobalData.appToken
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/dataList",
@Query("type") type: String
): ApiResponse<List<DictType>>
/**
@@ -135,22 +142,21 @@ interface ApiService {
@Multipart
@POST//("sys/common/upload")
suspend fun uploadImage(
@Url url: String = "${GlobalData.appBaseUrl}/sys/common/upload",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/sys/common/upload",
@Part("code") code: RequestBody,
@Part file: MultipartBody.Part,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<String>
/**
* 搜索物品列表
*/
@GET//("pad/goodsInfoList")
@POST//("pad/goodsInfoList")
suspend fun searchGoodsInfoList(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsInfoList",
@Query("goodsName") goodsName: String,
@Query("pageNo") pageNo: Int,
@Query("pageSize") pageSize: Int,
@Header("x-access-token") token: String = GlobalData.appToken
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsInfoList",
@Body param:Map<String, String>
// @Query("goodsName") goodsName: String,
// @Query("pageNum" ) pageNo: Int,
// @Query("pageSize" ) pageSize: Int,
): ApiResponse<SearchGoodsInfo>
/**
@@ -158,9 +164,8 @@ interface ApiService {
*/
@POST//("pad/goodsAdd")
suspend fun selfPurchaseGoodsAdd(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsAdd",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAdd",
@Body goodsAddParam: GoodsAddParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<SearchGoodsInfo>
/**
@@ -168,9 +173,8 @@ interface ApiService {
*/
@POST//("pad/goodsAddUnit")
suspend fun goodsAddUnit(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsAddUnit",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAddUnit",
@Body purchaseUnitParam: GoodsPurchaseUnitParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean>
/**
@@ -178,9 +182,8 @@ interface ApiService {
*/
@POST//("pad/SelfPurchasedGoods")
suspend fun selfPurchaseWarehousing(
@Url url: String = "${GlobalData.appBaseUrl}/pad/SelfPurchasedGoods",
@Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/selfPurchasedGoods",
@Body list: List<PurchaseWarehouseParam>,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean>
}
@@ -17,6 +17,8 @@ class RequestInterceptor : Interceptor {
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("deviceId", GlobalData.deviceId)
.header("X-DEVICE-CODE", GlobalData.deviceId)
.header("x-access-token", GlobalData.appToken)
// .header("Authorization", "Bearer ${getToken()}")
// .header("x-access-token", getToken())
@@ -0,0 +1,18 @@
package com.sw.inbound.objbox
import android.graphics.Bitmap
import android.net.Uri
data class FoodClassInfo(
var class_names: List<String>,
var class_to_idx: Map<String, Int>,
var idx_to_class: Map<String, String>
)
data class FoodCollectionBean(
var imageUri: Uri? = null,
var bitmap: Bitmap? = null,
var imageVector: FloatArray? = null,
var isShowCamera: Boolean = false,
var isFinish:Boolean = false
)
@@ -0,0 +1,37 @@
package com.sw.inbound.objbox
import io.objectbox.annotation.Entity
import io.objectbox.annotation.HnswIndex
import io.objectbox.annotation.Id
import io.objectbox.annotation.VectorDistanceType
@Entity
data class Food(
@Id var id: Long = 0,
var name: String? = null,
var foodIdx: Int = 0,
@HnswIndex(dimensions = 512, distanceType = VectorDistanceType.DOT_PRODUCT)
var foodVector: FloatArray? = null
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Food
if (id != other.id) return false
if (foodIdx != other.foodIdx) return false
if (name != other.name) return false
if (!foodVector.contentEquals(other.foodVector)) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + foodIdx
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + (foodVector?.contentHashCode() ?: 0)
return result
}
}
@@ -0,0 +1,172 @@
package com.sw.inbound.objbox
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.sw.inbound.MyApp
import com.sw.inbound.utils.AssetsTool
import com.sw.inbound.utils.ImageUtil
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import io.objectbox.query.Query
import org.pytorch.IValue
import org.pytorch.Module
import org.pytorch.torchvision.TensorImageUtils
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
object FoodModule {
private lateinit var module_mobile: Module
private lateinit var box: Box<Food>
private lateinit var embeddingsList: List<List<Float>>
private lateinit var labelsList: IntArray
private lateinit var classInfo: FoodClassInfo
val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f)
val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f)
fun init(context: Context) {
Thread{
module_mobile = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt"))
box = ObjectBox.boxStore.boxFor(Food::class)
// if (box.all.isNotEmpty()) {
// box.removeAll()
// }
if (box.all.isEmpty()) {
initFoodData(context)
}
}.start()
}
fun uri2FloatArray(uri: Uri): FloatArray? {
return MyApp.instance?.let { context ->
ImageUtil.uriToBitmap(context, uri)?.let {
bitmap2FloatArray(it)
}
}
}
fun bitmap2FloatArray(bitmap: Bitmap): FloatArray {
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
bitmap,
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
)
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
return outputTensor.dataAsFloatArray
}
fun queryFood(uri: Uri, queryCount:Int = 15): List<String>? {
return uri2FloatArray(uri)?.let {
queryFood(it, queryCount)
}
}
fun queryFood(bitmap: Bitmap, queryCount:Int = 15): List<String> {
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
bitmap,
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
)
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
val floatArray = outputTensor.dataAsFloatArray
return queryFood(floatArray,queryCount)
}
fun queryFood(floatArray: FloatArray, queryCount:Int = 15): List<String> {
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 map = mutableMapOf<String, Int>()
query.findIdsWithScores().forEach {
val food = box.get(it.id)
//FoodQueryResult(id = it.id, name = food.name, foodIdx = food.foodIdx, score = it.score)
food.name?.let { key ->
val count = map[key] ?: 0
map.put(key, count + 1)
}
}
val list = map.entries.sortedByDescending { it.value }.map { it.key }
return list
}
private fun initFoodData(context: Context) {
if (box.all.isNotEmpty()) {
return
}
val embeddingsJson = AssetsTool.readAssetsFile(context, "data/embeddings.json")
val labelsJson = AssetsTool.readAssetsFile(context, "data/labels.json")
val classInfoJson = AssetsTool.readAssetsFile(context, "data/class_info.json")
embeddingsList =
Gson().fromJson(embeddingsJson, object : TypeToken<List<List<Float>>>() {}.type)
labelsList = Gson().fromJson(labelsJson, IntArray::class.java)
classInfo =
Gson().fromJson(classInfoJson, FoodClassInfo::class.java)
val foodMap = classInfo.idx_to_class
embeddingsList.forEachIndexed { index, floatList ->
val classIdx = labelsList[index]
val foodName = foodMap["$classIdx"]
val array = floatList.toFloatArray()
box.put(Food(name = foodName, foodVector = array, foodIdx = index))
}
}
/**
* ,此方法的主要目的是:从assets 拷贝到 app的cache目录
* @param context
* @param fileName
* @return 例如是这样:/data/user/0/com.frizzle.pluginhookandroid9/cache/plugin-debug.apk
*
* 不可能反正SD
*/
fun copyAssetToCache(context: Context, fileName: String): String? {
// 此app的缓存目录 --> 会默认在 cache目录...,可以自己去看看哦
val cacheDir = context.getCacheDir()
if (!cacheDir.exists()) {
cacheDir.mkdirs() // TODO 如果没有缓存目录,就创建
}
val outPath = File(cacheDir, fileName) // TODO 创建输出的文件位置
if (outPath.exists()) {
outPath.delete() // TODO 如果该文件已经存在,就删掉
}
var `is`: InputStream? = null // 读取
var fos: FileOutputStream? = null // 写入
try {
// 创建文件,如果创建成功,就返回true
val res = outPath.createNewFile()
if (res) {
`is` = context.getAssets().open(fileName) // 拿到main/assets目录的输入流,用于读取字节
fos = FileOutputStream(outPath) // 读取出来的字节最终写到outPath
val buf = ByteArray(`is`.available()) // 缓存区
var byteCount: Int
// 开始循环读取
while ((`is`.read(buf).also { byteCount = it }) != -1) {
fos.write(buf, 0, byteCount)
}
return outPath.getAbsolutePath()
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
// TODO 一定要记得关闭资源,为了不去性能的磨损
fos!!.flush()
`is`!!.close()
fos.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return null
}
}
@@ -0,0 +1,109 @@
/*
* Copyright 2024 ObjectBox Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sw.inbound.objbox
import android.content.Context
import android.util.Log
import io.objectbox.BoxStore
import io.objectbox.BoxStoreBuilder
import io.objectbox.android.Admin
import io.objectbox.exception.DbException
import io.objectbox.exception.FileCorruptException
import io.objectbox.sync.Sync
import java.io.File
import java.util.zip.GZIPOutputStream
import kotlin.io.copyTo
import kotlin.io.inputStream
import kotlin.io.outputStream
import kotlin.io.use
import kotlin.jvm.java
import kotlin.jvm.javaClass
/**
* Singleton to keep BoxStore reference and provide current list of Notes Objects.
* Inserts demo data if no Objects are stored.
*/
object ObjectBox {
// 确保所有设备/版本使用相同的objectbox-models/default.json
// 避免直接修改自动生成的MyObjectBox类
// 跨版本升级时使用boxStore.runInTx执行数据迁移
private const val TAG = "ObjectBox"
lateinit var boxStore: BoxStore
private set
/**
* If building the [boxStore] failed, contains the thrown error message.
*/
var dbExceptionMessage: String? = null
private set
fun init(context: Context) {
// On Android make sure to pass a Context when building the Store.
boxStore = try {
MyObjectBox.builder()
.androidContext(context.applicationContext)
.build()
} catch (e: DbException) {
if (e.javaClass.equals(DbException::class.java) || e is FileCorruptException) {
// Failed to build BoxStore due to database file issue, store message;
// checked in NoteListActivity to notify user.
dbExceptionMessage = e.toString()
return
} else {
// Failed to build BoxStore due to developer error.
throw e
}
}
// if (BuildConfig.DEBUG) {
var syncAvailable = if (Sync.isAvailable()) "available" else "unavailable"
Log.d(TAG,"Using ObjectBox ${BoxStore.getVersion()} (${BoxStore.getVersionNative()}, sync $syncAvailable)")
// Enable ObjectBox Admin on debug builds.
// https://docs.objectbox.io/data-browser
Admin(boxStore).start(context.applicationContext)
// }
}
/**
* If the database file is not in use, compresses (GZIP) and copies it to the given [target].
*/
fun copyAndGzipDatabaseFileTo(target: File, context: Context): Boolean {
if (BoxStore.isDatabaseOpen(context, null)) {
// Do not copy if database file is still in use.
// If it would be open, the copy will likely get corrupted
// as BoxStore may currently write data to the file.
Log.e(TAG, "Database file is still in use, can not copy.")
return false
}
// If a name was given when building BoxStore use that instead of the default below.
val dbName = BoxStoreBuilder.DEFAULT_NAME
File(context.filesDir, "objectbox/$dbName/data.mdb").inputStream().use { input ->
target.parentFile?.mkdirs()
GZIPOutputStream(target.outputStream()).use { output ->
input.copyTo(output, DEFAULT_BUFFER_SIZE)
}
}
return true
}
}
@@ -3,7 +3,7 @@ package com.sw.inbound.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.sw.inbound.InitActivity
import com.sw.inbound.MainActivity
import timber.log.Timber
/**
@@ -14,7 +14,7 @@ class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
Timber.d("设备启动完成,开始执行自启动逻辑")
val intent = Intent(context, InitActivity::class.java)
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
@@ -25,31 +25,31 @@ abstract class BaseRepository {
// } else {
// "HTTP Error: ${e.code()} - ${e.message()}"
// }
ApiResponse(code = e.code(), message = e.message())
ApiResponse(code = "${e.code()}", msg = e.message())
}
is SocketTimeoutException -> {
ApiResponse(code = -2, message = "请求超时: ${e.message}")
ApiResponse(code = "-2", msg = "请求超时: ${e.message}")
}
is ConnectException -> {
ApiResponse(code = -3, message = "连接失败: ${e.message}")
ApiResponse(code = "-3", msg = "连接失败: ${e.message}")
}
is SSLHandshakeException -> {
ApiResponse(code = -4, message = "SSL握手失败: ${e.message}")
ApiResponse(code = "-4", msg = "SSL握手失败: ${e.message}")
}
is JsonParseException -> {
ApiResponse(code = -5, message = "JSON解析错误: ${e.message}")
ApiResponse(code = "-5", msg = "JSON解析错误: ${e.message}")
}
is IOException -> {
ApiResponse(code = -6, message = "网络IO错误: ${e.message}")
ApiResponse(code = "-6", msg = "网络IO错误: ${e.message}")
}
else -> {
ApiResponse(code = -1, message = "未知错误: ${e.message ?: "无错误信息"}")
ApiResponse(code = "-1", msg = "未知错误: ${e.message ?: "无错误信息"}")
}
}
}
@@ -0,0 +1,57 @@
//package com.sw.inbound.repository
//
//import com.google.gson.JsonParseException
//import com.sw.inbound.model.response.ApiResponse
//import retrofit2.HttpException
//import timber.log.Timber
//import java.io.IOException
//import java.net.ConnectException
//import java.net.SocketTimeoutException
//import javax.net.ssl.SSLHandshakeException
//
//abstract class BaseRepositoryBak {
// suspend fun <T> safeApiCall(apiCall: suspend () -> ApiResponse<T>): ApiResponse<T> {
// return try {
// apiCall()
// } catch (e: Exception) {
// Timber.e("safeApiCall Exception: ${e.stackTraceToString()}")
//
// when (e) {
// is HttpException -> {
// // 对于HTTP异常,尝试从响应体中获取错误信息
//// val errorBody = e.response()?.errorBody()?.string()
//// val errorMsg = if (!errorBody.isNullOrEmpty()) {
//// errorBody
//// } else {
//// "HTTP Error: ${e.code()} - ${e.message()}"
//// }
// ApiResponse(code = e.code(), message = e.message())
// }
//
// is SocketTimeoutException -> {
// ApiResponse(code = -2, message = "请求超时: ${e.message}")
// }
//
// is ConnectException -> {
// ApiResponse(code = -3, message = "连接失败: ${e.message}")
// }
//
// is SSLHandshakeException -> {
// ApiResponse(code = -4, message = "SSL握手失败: ${e.message}")
// }
//
// is JsonParseException -> {
// ApiResponse(code = -5, message = "JSON解析错误: ${e.message}")
// }
//
// is IOException -> {
// ApiResponse(code = -6, message = "网络IO错误: ${e.message}")
// }
//
// else -> {
// ApiResponse(code = -1, message = "未知错误: ${e.message ?: "无错误信息"}")
// }
// }
// }
// }
//}
@@ -13,6 +13,7 @@ import com.sw.inbound.model.response.GoodsType
import com.sw.inbound.model.response.PurchaseInfo
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.model.response.StorageType
import com.sw.inbound.model.response.SupplierInfo
import com.sw.inbound.model.response.SupplierResponse
import com.sw.inbound.model.response.User
import com.sw.inbound.network.api.ApiService
@@ -56,13 +57,18 @@ class RemoteRepository @Inject constructor(
return safeApiCall { apiService.login(body = loginParam) }
}
suspend fun getReceiveList(pageNum: Int, pageSize: Int): ApiResponse<SupplierResponse> {
suspend fun getReceiveList(pageNum: Int, pageSize: Int): ApiResponse<List<SupplierInfo>?> {
return safeApiCall {
apiService.getReceiveList(pageNo = pageNum, pageSize = pageSize)
apiService.getReceiveList(
param = mutableMapOf(
"pageNum" to pageNum.toString(),
"pageSize" to pageSize.toString(),
)
)
}
}
suspend fun getReceiveDetail(id: Int): ApiResponse<PurchaseInfo> {
suspend fun getReceiveDetail(id: String): ApiResponse<PurchaseInfo> {
return safeApiCall {
apiService.getReceiveDetail(id = id)
}
@@ -115,7 +121,7 @@ class RemoteRepository @Inject constructor(
val part =
FileUtils.genRequestPart(context = ContextUtils.getAppContext(), imageUri = uri)
if (part == null) {
ApiResponse(code = -1, message = "解析图片失败", result = "")
ApiResponse(code = "-1", msg = "解析图片失败")
} else {
apiService.uploadImage(code = codeRequestBody, file = part)
}
@@ -146,11 +152,12 @@ class RemoteRepository @Inject constructor(
pageSize: Int = 10
): ApiResponse<SearchGoodsInfo> {
return safeApiCall {
apiService.searchGoodsInfoList(
goodsName = goodsName,
pageNo = pageNo,
pageSize = pageSize
val map = mutableMapOf(
"goodsName" to goodsName,
"pageNum" to pageNo.toString(),
"pageSize" to pageSize.toString()
)
apiService.searchGoodsInfoList(param = map)
}
}
@@ -29,9 +29,9 @@ import com.sw.inbound.R
import com.sw.inbound.ui.page.HomeScreen
import com.sw.inbound.ui.page.LoginScreen
import com.sw.inbound.ui.page.PurchaseOrderScreen
import com.sw.inbound.ui.page.ReceiptProductScreen
import com.sw.inbound.ui.page.SelfProcurementScreen
import com.sw.inbound.ui.page.TestScreen
//import com.sw.inbound.ui.page.ReceiptProductScreen
//import com.sw.inbound.ui.page.SelfProcurementScreen
//import com.sw.inbound.ui.page.TestScreen
import com.sw.inbound.ui.weight.GlobalLoading
import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ToastUtils
@@ -107,11 +107,12 @@ private fun NavHost(
.fillMaxSize()
.padding(padding),
navController = navController,
startDestination = if (token.isEmpty()) Screen.Login.route else Screen.Home.route
//startDestination = if (token.isEmpty()) Screen.Login.route else Screen.Home.route
startDestination = Screen.Home.route
) {
composable(Screen.Test.route) {
TestScreen(modifier = Modifier, navController)
}
// composable(Screen.Test.route) {
// TestScreen(modifier = Modifier, navController)
// }
// 首页
composable(Screen.Home.route) {
HomeScreen(modifier = Modifier, navController, onBackRequest = onBackRequest)
@@ -128,28 +129,28 @@ private fun NavHost(
) {
PurchaseOrderScreen(modifier = Modifier.fillMaxSize(), navController)
}
// 自采单
composable(
Screen.SelfProcurement.route,
enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
exitTransition = { fadeOut(animationSpec = tween(0)) } // 无退出动画
) {
SelfProcurementScreen(modifier = Modifier, navController)
}
// 收货
composable(
Screen.ReceiptProduct.route,
enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
exitTransition = { fadeOut(animationSpec = tween(0)) }, // 无退出动画
arguments = listOf(
navArgument(name = "id", builder = { type = NavType.IntType }),
navArgument(name = "supplierId", builder = { type = NavType.IntType })
)
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: 0
val supplierId = backStackEntry.arguments?.getInt("supplierId") ?: 0
ReceiptProductScreen(modifier = Modifier, navController, id, supplierId)
}
// // 自采单
// composable(
// Screen.SelfProcurement.route,
// enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
// exitTransition = { fadeOut(animationSpec = tween(0)) } // 无退出动画
// ) {
// SelfProcurementScreen(modifier = Modifier, navController)
// }
// // 收货
// composable(
// Screen.ReceiptProduct.route,
// enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
// exitTransition = { fadeOut(animationSpec = tween(0)) }, // 无退出动画
// arguments = listOf(
// navArgument(name = "id", builder = { type = NavType.IntType }),
// navArgument(name = "supplierId", builder = { type = NavType.IntType })
// )
// ) { backStackEntry ->
// val id = backStackEntry.arguments?.getString("id") ?: ""
// val supplierId = backStackEntry.arguments?.getString("supplierId") ?: ""
// ReceiptProductScreen(modifier = Modifier, navController, id, supplierId)
// }
}
}
@@ -161,15 +162,15 @@ sealed class Screen(val route: String) {
data object PurchaseOrder : Screen("purchase_order")
// 自采单入库
data object SelfProcurement : Screen("self_procurement")
// data object SelfProcurement : Screen("self_procurement")
// 收货
data object ReceiptProduct : Screen("receipt_product?id={id}&supplierId={supplierId}") {
fun createRoute(id: Int, supplierId: Int) =
"receipt_product?id=${id}&supplierId=${supplierId}"
}
// data object ReceiptProduct : Screen("receipt_product?id={id}&supplierId={supplierId}") {
// fun createRoute(id: Int, supplierId: Int) =
// "receipt_product?id=${id}&supplierId=${supplierId}"
// }
// 添加物品
data object AddProduct : Screen("addProduct")
data object Test : Screen("Test")
// data object AddProduct : Screen("addProduct")
// data object Test : Screen("Test")
}
@@ -23,11 +23,13 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.rememberNavController
import com.sw.inbound.R
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.activity.SelfProcurementActivity
import com.sw.inbound.ui.Screen
import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.viewmodel.UserViewModel
import timber.log.Timber
@@ -78,6 +80,11 @@ fun HomeScreen(
indication = null
) {
navController.navigate(Screen.PurchaseOrder.route)
//navController.context.startActivity<ReceiptActivity> {
// putExtra(GoodsListActivity.ID, "123123")
// putExtra(GoodsListActivity.SUPPLIER_ID, "123123123123")
// putExtra(GoodsListActivity.IS_RECEIPT_PAGE, true)
//}
},
painter = painterResource(R.mipmap.ic_order_purchase),
contentDescription = "采购单入库"
@@ -91,14 +98,19 @@ fun HomeScreen(
interactionSource = remember { MutableInteractionSource() },
indication = null
) {
navController.navigate(
Screen.SelfProcurement.route, navOptions = NavOptions.Builder()
.setEnterAnim(0)
.setExitAnim(0)
.setPopEnterAnim(0)
.setPopExitAnim(0)
.build()
)
// navController.navigate(
// Screen.SelfProcurement.route, navOptions = NavOptions.Builder()
// .setEnterAnim(0)
// .setExitAnim(0)
// .setPopEnterAnim(0)
// .setPopExitAnim(0)
// .build()
// )
navController.context.startActivity<SelfProcurementActivity> {
putExtra(GoodsListActivity.ID, "2342342343")
putExtra(GoodsListActivity.SUPPLIER_ID, "23423423424234")
putExtra(GoodsListActivity.IS_RECEIPT_PAGE, false)
}
},
painter = painterResource(R.mipmap.ic_order_self_procurement),
contentDescription = "自采入库"
@@ -49,7 +49,6 @@ import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.weight.CustomButton
import com.sw.inbound.utils.QRCodeUtil
import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.viewmodel.UserViewModel
import timber.log.Timber
@@ -120,12 +119,17 @@ fun LoginScreen(
.height(120.dp),
text = "登录",
onClick = {
if (username.isEmpty() || password.isEmpty()) {
ToastUtils.showToast("用户名或密码不能为空")
return@CustomButton
}
//if (username.isEmpty() || password.isEmpty()) {
// ToastUtils.showToast("用户名或密码不能为空")
// return@CustomButton
//}
viewModel.login(username, password)
// viewModel.test()
// TODO: 测试功能,临时打开新页面
controller.navigate(Screen.Home.route)
// controller.context.startActivity<ReceiptActivity> {
// putExtra(GoodsListActivity.ID, "123123")
// putExtra(GoodsListActivity.SUPPLIER_ID, "123123123123")
// }
},
borderColor = colorResource(R.color.blue),
textColor = colorResource(R.color.white),
@@ -51,14 +51,17 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.sw.inbound.R
import com.sw.inbound.activity.GoodsListActivity
import com.sw.inbound.activity.ReceiptActivity
import com.sw.inbound.activity.SelfProcurementActivity
import com.sw.inbound.ext.dashedBorder
import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.model.response.SupplierInfo
import com.sw.inbound.ui.Screen
import com.sw.inbound.ui.theme.AppTypography.blackTextStyle
import com.sw.inbound.ui.theme.AppTypography.grayTextStyle
import com.sw.inbound.ui.weight.BottomActionBar
import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.viewmodel.PurchaseOrderViewModel
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -148,14 +151,20 @@ fun PurchaseOrderScreen(
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(30.dp)
) {
items(items = products, key = { it!!.id }) {
items(items = products, key = { it!!.id?:"" }) {
PurchaseOrderItem(it!!) {
navController.navigate(
Screen.ReceiptProduct.createRoute(
it.id,
it.supplierId
)
)
// navController.navigate(
// Screen.ReceiptProduct.createRoute(
// it.id,
// it.supplierId
// )
// )
navController.context.startActivity<ReceiptActivity> {
putExtra(GoodsListActivity.ID,it!!.id)
putExtra(GoodsListActivity.SUPPLIER_ID,it.supplierId)
putExtra(GoodsListActivity.IS_RECEIPT_PAGE,true)
putExtra(GoodsListActivity.IS_NEW_RECEIPT,false)
}
}
}
@@ -180,7 +189,14 @@ fun PurchaseOrderScreen(
modifier = Modifier, onLeftButtonClick = {
navController.popBackStack()
}, onRight2ButtonClick = {
navController.navigate(Screen.SelfProcurement.route)
//navController.navigate(Screen.SelfProcurement.route)
navController.context.startActivity<SelfProcurementActivity> {}
//navController.context.startActivity<ReceiptActivity> {
// //xtra(GoodsListActivity.ID,it!!.id)
// //xtra(GoodsListActivity.SUPPLIER_ID,it.supplierId)
// putExtra(GoodsListActivity.IS_RECEIPT_PAGE,true)
// putExtra(GoodsListActivity.IS_NEW_RECEIPT,true)
//}
})
}
}
@@ -336,7 +352,7 @@ fun PurchaseOrderItem(product: SupplierInfo, onItemClick: (SupplierInfo) -> Unit
}) {
Text(
if (product.receiveStatus == 4) "部分收货" else "收货",
style = TextStyle(fontWeight = FontWeight.Bold, fontSize = 30.sp)
style = TextStyle(fontWeight = FontWeight.Bold, fontSize = 26.sp)
)
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,15 +1,15 @@
package com.sw.inbound.ui.page
import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun TestScreen(modifier: Modifier.Companion, navController: NavHostController) {
}
//package com.sw.inbound.ui.page
//
//
//import android.annotation.SuppressLint
//import androidx.compose.runtime.Composable
//import androidx.compose.ui.Modifier
//import androidx.navigation.NavHostController
//
//
//@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
//@Composable
//fun TestScreen(modifier: Modifier.Companion, navController: NavHostController) {
//
//}
//
@@ -1,113 +1,113 @@
package com.sw.inbound.ui.weight
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.sw.inbound.R
import com.sw.inbound.model.response.DictType
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Black_141428
/**
* 表单中的下拉菜单
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomDropdownTextField(
value: String,
onValueChange: (String) -> Unit,
dropdownItems: List<DictType>,
modifier: Modifier = Modifier,
placeholderValue: String = "请选择",
textAlign: TextAlign = TextAlign.Start,
textStyle: TextStyle? = null,
enabled: Boolean = true,
) {
var expanded by remember { mutableStateOf(false) }
var newTextStyle = textStyle
?: LocalTextStyle.current.copy(
color = Black_141428,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
textAlign = textAlign
)
ExposedDropdownMenuBox(
modifier = modifier,
expanded = expanded || !enabled,
onExpandedChange = { expanded = it },
) {
TextField(
value = value,
onValueChange = onValueChange,
readOnly = true,
textStyle = newTextStyle,
shape = RoundedCornerShape(10.dp),
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
},
colors = ExposedDropdownMenuDefaults.textFieldColors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
),
placeholder = {
Text(
modifier = modifier.fillMaxWidth(),
text = placeholderValue, style = AppTypography.gray96a0aaTextStyle.copy(
textAlign = textAlign
)
)
},
modifier = Modifier
.fillMaxWidth()
.background(Color.Transparent)
.border(
width = 2.dp,
color = colorResource(R.color.border_line),
shape = RoundedCornerShape(10.dp)
)
.menuAnchor(PrimaryNotEditable, true)
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
dropdownItems.forEach { item ->
DropdownMenuItem(
text = { Text(text = item.value, style = AppTypography.black141428TextStyle) },
onClick = {
onValueChange(item.value)
expanded = false
}
)
}
}
}
}
//package com.sw.inbound.ui.weight
//
//import androidx.compose.foundation.background
//import androidx.compose.foundation.border
//import androidx.compose.foundation.layout.fillMaxWidth
//import androidx.compose.foundation.shape.RoundedCornerShape
//import androidx.compose.material3.DropdownMenuItem
//import androidx.compose.material3.ExperimentalMaterial3Api
//import androidx.compose.material3.ExposedDropdownMenuBox
//import androidx.compose.material3.ExposedDropdownMenuDefaults
//import androidx.compose.material3.LocalTextStyle
//import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
//import androidx.compose.material3.Text
//import androidx.compose.material3.TextField
//import androidx.compose.runtime.Composable
//import androidx.compose.runtime.getValue
//import androidx.compose.runtime.mutableStateOf
//import androidx.compose.runtime.remember
//import androidx.compose.runtime.setValue
//import androidx.compose.ui.Modifier
//import androidx.compose.ui.graphics.Color
//import androidx.compose.ui.res.colorResource
//import androidx.compose.ui.text.TextStyle
//import androidx.compose.ui.text.font.FontWeight
//import androidx.compose.ui.text.style.TextAlign
//import androidx.compose.ui.unit.dp
//import androidx.compose.ui.unit.sp
//import com.sw.inbound.R
//import com.sw.inbound.model.response.DictType
//import com.sw.inbound.ui.theme.AppTypography
//import com.sw.inbound.ui.theme.Black_141428
//
///**
// * 表单中的下拉菜单
// */
//@OptIn(ExperimentalMaterial3Api::class)
//@Composable
//fun CustomDropdownTextField(
// value: String,
// onValueChange: (String) -> Unit,
// dropdownItems: List<DictType>,
// modifier: Modifier = Modifier,
// placeholderValue: String = "请选择",
// textAlign: TextAlign = TextAlign.Start,
// textStyle: TextStyle? = null,
// enabled: Boolean = true,
//) {
// var expanded by remember { mutableStateOf(false) }
// var newTextStyle = textStyle
// ?: LocalTextStyle.current.copy(
// color = Black_141428,
// fontSize = 24.sp,
// fontWeight = FontWeight.Bold,
// textAlign = textAlign
// )
//
// ExposedDropdownMenuBox(
// modifier = modifier,
// expanded = expanded || !enabled,
// onExpandedChange = { expanded = it },
// ) {
// TextField(
// value = value,
// onValueChange = onValueChange,
// readOnly = true,
// textStyle = newTextStyle,
//
// shape = RoundedCornerShape(10.dp),
// trailingIcon = {
// ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
// },
// colors = ExposedDropdownMenuDefaults.textFieldColors(
// focusedContainerColor = Color.Transparent,
// unfocusedContainerColor = Color.Transparent,
// disabledContainerColor = Color.Transparent,
// focusedIndicatorColor = Color.Transparent,
// unfocusedIndicatorColor = Color.Transparent
// ),
// placeholder = {
// Text(
// modifier = modifier.fillMaxWidth(),
// text = placeholderValue, style = AppTypography.gray96a0aaTextStyle.copy(
// textAlign = textAlign
// )
// )
// },
// modifier = Modifier
// .fillMaxWidth()
// .background(Color.Transparent)
// .border(
// width = 2.dp,
// color = colorResource(R.color.border_line),
// shape = RoundedCornerShape(10.dp)
// )
// .menuAnchor(PrimaryNotEditable, true)
// )
//
// ExposedDropdownMenu(
// expanded = expanded,
// onDismissRequest = { expanded = false }
// ) {
// dropdownItems.forEach { item ->
// DropdownMenuItem(
// text = { Text(text = item.value?:"", style = AppTypography.black141428TextStyle) },
// onClick = {
// onValueChange(item.value?:"")
// expanded = false
// }
// )
// }
// }
// }
//}
@@ -1,106 +1,106 @@
package com.sw.inbound.ui.weight
import androidx.compose.foundation.background
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.sw.inbound.R
import com.sw.inbound.model.response.DictType
/**
* 自定义顶部仓库下拉
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomSpinner(
items: List<DictType>,
selectedItem: String,
onItemSelected: (DictType) -> Unit,
modifier: Modifier = Modifier,
) {
// var expanded by remember { mutableStateOf(false) }
var expanded by remember { mutableStateOf(true) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = modifier.background(
color = Color(0x80FFFFFF),
shape = RoundedCornerShape(10.dp) // 圆角背景
)
) {
TextField(
value = selectedItem,
onValueChange = {},
readOnly = true,
textStyle = TextStyle(
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
),
shape = RoundedCornerShape(10.dp),
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
},
colors = ExposedDropdownMenuDefaults.textFieldColors(
focusedContainerColor = colorResource(R.color.blue),
unfocusedContainerColor = colorResource(R.color.blue),
disabledContainerColor = colorResource(R.color.blue),
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
cursorColor = Color.White,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.White.copy(alpha = 0.8f),
unfocusedLabelColor = Color.White.copy(alpha = 0.8f),
focusedTrailingIconColor = Color.White,
unfocusedTrailingIconColor = Color.White
),
modifier = Modifier.menuAnchor(PrimaryNotEditable, true)
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.background(colorResource(R.color.blue))
.exposedDropdownSize(matchTextFieldWidth = true)
) {
items.forEach { item ->
DropdownMenuItem(
text = {
Text(
text = item.value,
style = TextStyle(
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
),
)
},
onClick = {
onItemSelected(item)
expanded = false
}
)
}
}
}
}
//package com.sw.inbound.ui.weight
//
//import androidx.compose.foundation.background
//import androidx.compose.foundation.shape.RoundedCornerShape
//import androidx.compose.material3.DropdownMenuItem
//import androidx.compose.material3.ExperimentalMaterial3Api
//import androidx.compose.material3.ExposedDropdownMenuBox
//import androidx.compose.material3.ExposedDropdownMenuDefaults
//import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
//import androidx.compose.material3.Text
//import androidx.compose.material3.TextField
//import androidx.compose.runtime.Composable
//import androidx.compose.runtime.getValue
//import androidx.compose.runtime.mutableStateOf
//import androidx.compose.runtime.remember
//import androidx.compose.runtime.setValue
//import androidx.compose.ui.Modifier
//import androidx.compose.ui.graphics.Color
//import androidx.compose.ui.res.colorResource
//import androidx.compose.ui.text.TextStyle
//import androidx.compose.ui.text.font.FontWeight
//import androidx.compose.ui.unit.dp
//import androidx.compose.ui.unit.sp
//import com.sw.inbound.R
//import com.sw.inbound.model.response.DictType
//
///**
// * 自定义顶部仓库下拉
// */
//@OptIn(ExperimentalMaterial3Api::class)
//@Composable
//fun CustomSpinner(
// items: List<DictType>,
// selectedItem: String,
// onItemSelected: (DictType) -> Unit,
// modifier: Modifier = Modifier,
//) {
//// var expanded by remember { mutableStateOf(false) }
// var expanded by remember { mutableStateOf(true) }
//
// ExposedDropdownMenuBox(
// expanded = expanded,
// onExpandedChange = { expanded = !expanded },
// modifier = modifier.background(
// color = Color(0x80FFFFFF),
// shape = RoundedCornerShape(10.dp) // 圆角背景
// )
// ) {
// TextField(
// value = selectedItem,
// onValueChange = {},
// readOnly = true,
// textStyle = TextStyle(
// color = Color.White,
// fontSize = 24.sp,
// fontWeight = FontWeight.Bold
// ),
// shape = RoundedCornerShape(10.dp),
// trailingIcon = {
// ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
// },
// colors = ExposedDropdownMenuDefaults.textFieldColors(
// focusedContainerColor = colorResource(R.color.blue),
// unfocusedContainerColor = colorResource(R.color.blue),
// disabledContainerColor = colorResource(R.color.blue),
// focusedTextColor = Color.White,
// unfocusedTextColor = Color.White,
// cursorColor = Color.White,
// focusedIndicatorColor = Color.Transparent,
// unfocusedIndicatorColor = Color.Transparent,
// focusedLabelColor = Color.White.copy(alpha = 0.8f),
// unfocusedLabelColor = Color.White.copy(alpha = 0.8f),
// focusedTrailingIconColor = Color.White,
// unfocusedTrailingIconColor = Color.White
// ),
// modifier = Modifier.menuAnchor(PrimaryNotEditable, true)
// )
//
// ExposedDropdownMenu(
// expanded = expanded,
// onDismissRequest = { expanded = false },
// modifier = Modifier
// .background(colorResource(R.color.blue))
// .exposedDropdownSize(matchTextFieldWidth = true)
// ) {
// items.forEach { item ->
// DropdownMenuItem(
// text = {
// Text(
// text = item.value?:"",
// style = TextStyle(
// color = Color.White,
// fontSize = 24.sp,
// fontWeight = FontWeight.Bold
// ),
// )
// },
// onClick = {
// onItemSelected(item)
// expanded = false
// }
// )
// }
// }
// }
//}
@@ -1,216 +1,216 @@
package com.sw.inbound.ui.weight
import android.widget.Toast
import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.sw.inbound.ext.medium
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.utils.InteractionUtils.Debouncer
import com.sw.inbound.utils.rememberPhotoCapture
import com.sw.inbound.viewmodel.BaseViewModel
import com.sw.inbound.viewmodel.ReceiptViewModel
import com.sw.inbound.viewmodel.SelfProcurementViewModel
import timber.log.Timber
enum class PageType {
/**
* 自采
*/
SELF_PROCUREMENT,
/**
* 收货
*/
RECEIPT_PRODUCT
}
/**
* 菜品识别组件
*/
@Composable
fun IdentityView(
showSearchView: Boolean = false,
onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {},
checkedItem: PurchaseWarehouseParam? = null,
baseViewModel: BaseViewModel,
pageType: PageType
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val weightInfo by baseViewModel.weightInfo.collectAsState()
val identityList by baseViewModel.identityListItems.collectAsState()
val receiptList by baseViewModel.receiptList.collectAsState()
val searchList by baseViewModel.searchListItems.collectAsState()
// var lastWeight by remember { mutableStateOf<Double?>(null) }
var lastWeight by remember { mutableDoubleStateOf(0.0) }
val lastPhotoUri by baseViewModel.lastPhotoUri.collectAsState()
var pageNum by remember { mutableIntStateOf(1) }
val isMoreLoading by baseViewModel.isMoreLoading.collectAsState()
val canLoadMore by baseViewModel.canLoadMore.collectAsState()
var list = if (identityList.isNotEmpty()) {
identityList
} else {
searchList
}
val debouncer = remember { Debouncer(2000) }
var isCameraReady by remember { mutableStateOf(false) }
// CameraX 控制器
val cameraController = remember {
LifecycleCameraController(context).apply {
// 必须设置有效的用例
setEnabledUseCases(
CameraController.IMAGE_CAPTURE or
CameraController.VIDEO_CAPTURE
)
}
}
// 需要搜索的信息
var searchInfo by remember { mutableStateOf("") }
// 创建拍照工具实例
val (photoCaptureHelper, takePhoto) = rememberPhotoCapture(
cameraController = cameraController,
onSuccess = { savedUri ->
// 处理拍照成功的逻辑
baseViewModel.updateLastPhotoUri(savedUri)
Timber.d("photoUri = $savedUri")
if (pageType == PageType.SELF_PROCUREMENT) {
(baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
} else if (pageType == PageType.RECEIPT_PRODUCT) {
(baseViewModel as ReceiptViewModel).updateSelectedItem(null)
}
baseViewModel.getIdentityList(savedUri)
},
onError = { error ->
// 处理拍照失败的逻辑
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
baseViewModel.updateLastPhotoUri(null)
}
)
// 绑定生命周期
DisposableEffect(lifecycleOwner) {
cameraController.bindToLifecycle(lifecycleOwner)
onDispose {
cameraController.unbind()
isCameraReady = false
}
}
LaunchedEffect(weightInfo) {
Timber.d("LaunchedEffect weightInfo1 = $weightInfo, lastWeight = $lastWeight")
if (weightInfo - lastWeight > 1.0) {
Timber.d("LaunchedEffect pageType = $pageType, receiptList = ${receiptList.size}")
var canIdentity = false
if (pageType == PageType.RECEIPT_PRODUCT) {
val selectItem = (baseViewModel as ReceiptViewModel).selectedItem.value
canIdentity =
receiptList.isNotEmpty() && (selectItem == null || selectItem.goodId == 0)
} else if (pageType == PageType.SELF_PROCUREMENT) {
val selectItem = (baseViewModel as SelfProcurementViewModel).selectedItem.value
canIdentity = selectItem == null || selectItem.goodsId == 0
}
Timber.d("LaunchedEffect canIdentity = $canIdentity")
if (canIdentity) {
debouncer.debounce {
Timber.d("LaunchedEffect isCameraReady = $isCameraReady")
if (isCameraReady) {
takePhoto()
}
}
}
}
lastWeight = weightInfo
}
// 监听相机初始化
LaunchedEffect(Unit) {
try {
cameraController.initializationFuture.addListener({
isCameraReady = true
Timber.d("Camera initialized successfully")
}, ContextCompat.getMainExecutor(context))
} catch (e: Exception) {
Timber.d("Camera initialized error = ${e.message}")
}
}
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
CameraPreview(
modifier = Modifier
.width(397.dp)
.height(298.dp),
controller = cameraController,
photoUri = lastPhotoUri
)
if (showSearchView) {
Spacer(modifier = Modifier.height(30.dp))
CustomSearchView(onSearchClick = {
if (pageType == PageType.SELF_PROCUREMENT) {
(baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
}
searchInfo = it
baseViewModel.searchGoodsInfoList(it)
})
}
Spacer(modifier = Modifier.height(30.dp))
if (showSearchView) {
SingleSelectButtonGroup(
modifier = Modifier
.height(64.dp)
.width(192.dp), options = list,
onOptionSelected = onOptionSelected,
onLoadMore = {
Timber.d("加载更多 canLoadMore = $canLoadMore")
if (!canLoadMore) {
return@SingleSelectButtonGroup
}
pageNum++
baseViewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum)
},
checkedItem = list.find { it.goodsId == checkedItem?.goodsId },
isMoreLoading = isMoreLoading,
canLoadMore = canLoadMore
)
} else {
SingleSelectButtonGroup(
modifier = Modifier
.height(70.dp)
.width(215.dp),
options = list,
horizontalSpacing = 30.dp,
verticalSpacing = 20.dp,
onOptionSelected = onOptionSelected,
unSelectedTextStyle = AppTypography.blackTextStyle.medium()
)
}
}
}
//package com.sw.inbound.ui.weight
//
//import android.widget.Toast
//import androidx.camera.view.CameraController
//import androidx.camera.view.LifecycleCameraController
//import androidx.compose.foundation.layout.Column
//import androidx.compose.foundation.layout.Spacer
//import androidx.compose.foundation.layout.fillMaxSize
//import androidx.compose.foundation.layout.height
//import androidx.compose.foundation.layout.width
//import androidx.compose.runtime.Composable
//import androidx.compose.runtime.DisposableEffect
//import androidx.compose.runtime.LaunchedEffect
//import androidx.compose.runtime.collectAsState
//import androidx.compose.runtime.getValue
//import androidx.compose.runtime.mutableDoubleStateOf
//import androidx.compose.runtime.mutableIntStateOf
//import androidx.compose.runtime.mutableStateOf
//import androidx.compose.runtime.remember
//import androidx.compose.runtime.setValue
//import androidx.compose.ui.Alignment
//import androidx.compose.ui.Modifier
//import androidx.compose.ui.platform.LocalContext
//import androidx.compose.ui.unit.dp
//import androidx.core.content.ContextCompat
//import androidx.lifecycle.compose.LocalLifecycleOwner
//import com.sw.inbound.ext.medium
//import com.sw.inbound.model.request.PurchaseWarehouseParam
//import com.sw.inbound.model.response.SearchGoodsInfo
//import com.sw.inbound.ui.theme.AppTypography
//import com.sw.inbound.utils.InteractionUtils.Debouncer
//import com.sw.inbound.utils.rememberPhotoCapture
//import com.sw.inbound.viewmodel.BaseViewModel
//import com.sw.inbound.viewmodel.ReceiptViewModel
//import com.sw.inbound.viewmodel.SelfProcurementViewModel
//import timber.log.Timber
//
//enum class PageType {
// /**
// * 自采
// */
// SELF_PROCUREMENT,
//
// /**
// * 收货
// */
// RECEIPT_PRODUCT
//}
//
///**
// * 菜品识别组件
// */
//@Composable
//fun IdentityView(
// showSearchView: Boolean = false,
// onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {},
// checkedItem: PurchaseWarehouseParam? = null,
// baseViewModel: BaseViewModel,
// pageType: PageType
//) {
// val context = LocalContext.current
// val lifecycleOwner = LocalLifecycleOwner.current
// val weightInfo by baseViewModel.weightInfo.collectAsState()
// val identityList by baseViewModel.identityListItems.collectAsState()
// val receiptList by baseViewModel.receiptList.collectAsState()
// val searchList by baseViewModel.searchListItems.collectAsState()
//// var lastWeight by remember { mutableStateOf<Double?>(null) }
// var lastWeight by remember { mutableDoubleStateOf(0.0) }
// val lastPhotoUri by baseViewModel.lastPhotoUri.collectAsState()
// var pageNum by remember { mutableIntStateOf(1) }
// val isMoreLoading by baseViewModel.isMoreLoading.collectAsState()
// val canLoadMore by baseViewModel.canLoadMore.collectAsState()
// var list = if (identityList.isNotEmpty()) {
// identityList
// } else {
// searchList
// }
// val debouncer = remember { Debouncer(2000) }
// var isCameraReady by remember { mutableStateOf(false) }
//
// // CameraX 控制器
// val cameraController = remember {
// LifecycleCameraController(context).apply {
// // 必须设置有效的用例
// setEnabledUseCases(
// CameraController.IMAGE_CAPTURE or
// CameraController.VIDEO_CAPTURE
// )
// }
// }
//
// // 需要搜索的信息
// var searchInfo by remember { mutableStateOf("") }
// // 创建拍照工具实例
// val (photoCaptureHelper, takePhoto) = rememberPhotoCapture(
// cameraController = cameraController,
// onSuccess = { savedUri ->
// // 处理拍照成功的逻辑
// baseViewModel.updateLastPhotoUri(savedUri)
// Timber.d("photoUri = $savedUri")
// if (pageType == PageType.SELF_PROCUREMENT) {
// (baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
// } else if (pageType == PageType.RECEIPT_PRODUCT) {
// (baseViewModel as ReceiptViewModel).updateSelectedItem(null)
// }
// baseViewModel.getIdentityList(savedUri)
// },
// onError = { error ->
// // 处理拍照失败的逻辑
// Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
// baseViewModel.updateLastPhotoUri(null)
// }
// )
//
// // 绑定生命周期
// DisposableEffect(lifecycleOwner) {
// cameraController.bindToLifecycle(lifecycleOwner)
// onDispose {
// cameraController.unbind()
// isCameraReady = false
// }
// }
//
// LaunchedEffect(weightInfo) {
// Timber.d("LaunchedEffect weightInfo1 = $weightInfo, lastWeight = $lastWeight")
// if (weightInfo - lastWeight > 1.0) {
// Timber.d("LaunchedEffect pageType = $pageType, receiptList = ${receiptList.size}")
// var canIdentity = false
// if (pageType == PageType.RECEIPT_PRODUCT) {
// val selectItem = (baseViewModel as ReceiptViewModel).selectedItem.value
// canIdentity =
// receiptList.isNotEmpty() && (selectItem == null || selectItem.goodId.isNullOrBlank())
// } else if (pageType == PageType.SELF_PROCUREMENT) {
// val selectItem = (baseViewModel as SelfProcurementViewModel).selectedItem.value
// canIdentity = selectItem == null || selectItem.goodsId.isNullOrBlank()
// }
// Timber.d("LaunchedEffect canIdentity = $canIdentity")
// if (canIdentity) {
// debouncer.debounce {
// Timber.d("LaunchedEffect isCameraReady = $isCameraReady")
// if (isCameraReady) {
// takePhoto()
// }
// }
// }
// }
// lastWeight = weightInfo
// }
//
// // 监听相机初始化
// LaunchedEffect(Unit) {
// try {
// cameraController.initializationFuture.addListener({
// isCameraReady = true
// Timber.d("Camera initialized successfully")
// }, ContextCompat.getMainExecutor(context))
// } catch (e: Exception) {
// Timber.d("Camera initialized error = ${e.message}")
// }
// }
//
// Column(
// modifier = Modifier
// .fillMaxSize(),
// horizontalAlignment = Alignment.CenterHorizontally
// ) {
// CameraPreview(
// modifier = Modifier
// .width(397.dp)
// .height(298.dp),
// controller = cameraController,
// photoUri = lastPhotoUri
// )
// if (showSearchView) {
// Spacer(modifier = Modifier.height(30.dp))
// CustomSearchView(onSearchClick = {
// if (pageType == PageType.SELF_PROCUREMENT) {
// (baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
// }
// searchInfo = it
// baseViewModel.searchGoodsInfoList(it)
// })
// }
// Spacer(modifier = Modifier.height(30.dp))
// if (showSearchView) {
// SingleSelectButtonGroup(
// modifier = Modifier
// .height(64.dp)
// .width(192.dp), options = list,
// onOptionSelected = onOptionSelected,
// onLoadMore = {
// Timber.d("加载更多 canLoadMore = $canLoadMore")
// if (!canLoadMore) {
// return@SingleSelectButtonGroup
// }
// pageNum++
// baseViewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum)
// },
// checkedItem = list.find { it.goodsId == checkedItem?.goodsId },
// isMoreLoading = isMoreLoading,
// canLoadMore = canLoadMore
// )
// } else {
// SingleSelectButtonGroup(
// modifier = Modifier
// .height(70.dp)
// .width(215.dp),
// options = list,
// horizontalSpacing = 30.dp,
// verticalSpacing = 20.dp,
// onOptionSelected = onOptionSelected,
// unSelectedTextStyle = AppTypography.blackTextStyle.medium()
// )
// }
// }
//}
@@ -1,83 +1,83 @@
package com.sw.inbound.ui.weight
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.sw.inbound.R
import com.sw.inbound.model.response.DictType
import com.sw.inbound.ui.theme.AppTypography
/**
* 横向输入框 包含左侧文件+右侧输入框
*/
@Composable
fun RowInputLayout(
label: String, // 左侧文字
value: String,
onValueChange: (String) -> Unit,
dropdownItems: List<DictType>? = null, // 下拉列表
hasNext: Boolean = true, // 键盘显示下一步
inputType: InputType = InputType.Text,
trailingLabel: String? = null, // 尾部文字
keyboardOptions: KeyboardOptions? = null,
keyboardActions: KeyboardActions? = null,
isInitUpdate: Boolean = false, // 是否根据原始数据更新
showRightButton: Boolean = false,
onRightButtonClick: () -> Unit = {},
) {
val textWidth = if (showRightButton) 218.dp else 290.dp
Row(
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
.padding(horizontal = 30.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(label, style = AppTypography.black141428TextStyle)
// Spacer(modifier = Modifier.width(67.dp))
Spacer(modifier = Modifier.weight(1f))
if (dropdownItems == null) {
CustomTextField(
modifier = Modifier.width(textWidth),
value = value, onValueChange = onValueChange,
textAlign = TextAlign.End,
trailingLabel = trailingLabel,
hasNext = hasNext,
inputType = inputType,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
isInitUpdate = isInitUpdate
)
} else {
CustomDropdownTextField(
modifier = Modifier.width(textWidth),
value = value,
dropdownItems = dropdownItems,
onValueChange = onValueChange,
textAlign = TextAlign.End
)
}
if (showRightButton) {
Spacer(modifier = Modifier.width(12.dp))
Image(modifier = Modifier.clickable {
onRightButtonClick()
}, painter = painterResource(R.drawable.ic_add), contentDescription = "添加")
}
}
}
//package com.sw.inbound.ui.weight
//
//import androidx.compose.foundation.Image
//import androidx.compose.foundation.clickable
//import androidx.compose.foundation.layout.Arrangement
//import androidx.compose.foundation.layout.Row
//import androidx.compose.foundation.layout.Spacer
//import androidx.compose.foundation.layout.fillMaxWidth
//import androidx.compose.foundation.layout.height
//import androidx.compose.foundation.layout.padding
//import androidx.compose.foundation.layout.width
//import androidx.compose.foundation.text.KeyboardActions
//import androidx.compose.foundation.text.KeyboardOptions
//import androidx.compose.material3.Text
//import androidx.compose.runtime.Composable
//import androidx.compose.ui.Alignment
//import androidx.compose.ui.Modifier
//import androidx.compose.ui.res.painterResource
//import androidx.compose.ui.text.style.TextAlign
//import androidx.compose.ui.unit.dp
//import com.sw.inbound.R
//import com.sw.inbound.model.response.DictType
//import com.sw.inbound.ui.theme.AppTypography
//
///**
// * 横向输入框 包含左侧文件+右侧输入框
// */
//@Composable
//fun RowInputLayout(
// label: String, // 左侧文字
// value: String,
// onValueChange: (String) -> Unit,
// dropdownItems: List<DictType>? = null, // 下拉列表
// hasNext: Boolean = true, // 键盘显示下一步
// inputType: InputType = InputType.Text,
// trailingLabel: String? = null, // 尾部文字
// keyboardOptions: KeyboardOptions? = null,
// keyboardActions: KeyboardActions? = null,
// isInitUpdate: Boolean = false, // 是否根据原始数据更新
// showRightButton: Boolean = false,
// onRightButtonClick: () -> Unit = {},
//) {
// val textWidth = if (showRightButton) 218.dp else 290.dp
// Row(
// modifier = Modifier
// .height(60.dp)
// .fillMaxWidth()
// .padding(horizontal = 30.dp),
// horizontalArrangement = Arrangement.SpaceBetween,
// verticalAlignment = Alignment.CenterVertically
// ) {
// Text(label, style = AppTypography.black141428TextStyle)
//// Spacer(modifier = Modifier.width(67.dp))
// Spacer(modifier = Modifier.weight(1f))
// if (dropdownItems == null) {
// CustomTextField(
// modifier = Modifier.width(textWidth),
// value = value, onValueChange = onValueChange,
// textAlign = TextAlign.End,
// trailingLabel = trailingLabel,
// hasNext = hasNext,
// inputType = inputType,
// keyboardOptions = keyboardOptions,
// keyboardActions = keyboardActions,
// isInitUpdate = isInitUpdate
// )
// } else {
// CustomDropdownTextField(
// modifier = Modifier.width(textWidth),
// value = value,
// dropdownItems = dropdownItems,
// onValueChange = onValueChange,
// textAlign = TextAlign.End
// )
// }
// if (showRightButton) {
// Spacer(modifier = Modifier.width(12.dp))
// Image(modifier = Modifier.clickable {
// onRightButtonClick()
// }, painter = painterResource(R.drawable.ic_add), contentDescription = "添加")
// }
// }
//}
@@ -48,7 +48,8 @@ import kotlinx.coroutines.delay
@Composable
fun TopTitleBar(
modifier: Modifier = Modifier,
title: String = "采购单入库",
// title: String = "采购单入库",
title: String = "出入库管理",
user: User? = null,
onLogoutClick: () -> Unit = {}
) {
@@ -0,0 +1,76 @@
package com.sw.inbound.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
object AssetsTool {
// fun readJson(context: Context, fileName: String): List<String> {
// val json = readAssetsFile(context, fileName)
// val json2 = json.replace("[[", "[").replaceAfterLast("]]", "]")
// val list = json2.split("],")
// val resultList = mutableListOf<String>()
// var count = 0
// val tempList = mutableListOf<String>()
// list.forEachIndexed { index, text ->
// if (count >= 500) {
// val tempJson = "[${tempList.joinToString (",")}]"
// resultList.add(tempJson)
// tempList.clear()
// count = 0
// }
// val newText = if (index == list.size - 1) text else "${text}]"
// tempList.add(newText)
// count++
// }
// if (count < 500) {
// val tempJson = "[${tempList.joinToString(",")}]"
// resultList.add(tempJson)
// }
// return resultList
// }
fun readAssetsFile(context: Context, fileName: String): String {
val stringBuilder = StringBuilder()
try {
val bf = BufferedReader(InputStreamReader(context.assets.open(fileName)))
bf.useLines { lines -> lines.forEach { stringBuilder.append(it) } }
} catch (e: IOException) {
e.printStackTrace()
}
return stringBuilder.toString()
}
fun loadImagesFromAssets(context: Context, subPath: String): MutableList<Bitmap> {
val bitmaps: MutableList<Bitmap> = mutableListOf()
val assetManager = context.assets
try {
val files = assetManager.list(subPath)
files?.forEach { file ->
assetManager.open("$subPath/$file").use { `is` ->
val bitmap = BitmapFactory.decodeStream(`is`)
if (bitmap != null) {
bitmaps.add(bitmap)
}
}
}
} catch (e: IOException) {
e.printStackTrace()
}
return bitmaps
}
fun loadImageBitmapFromAssets(context: Context, imagePath:String, action:(bmp: Bitmap)-> Unit) {
context.assets.open(imagePath).use { `is` ->
val bitmap = BitmapFactory.decodeStream(`is`)
action(bitmap)
}
}
}
@@ -0,0 +1,38 @@
package com.sw.inbound.utils
import android.graphics.Bitmap
object BitmapCropper {
/**
* 裁剪Bitmap中心区域为指定尺寸
* @param original 原始Bitmap
* @param targetWidth 目标宽度
* @param targetHeight 目标高度
* @return 裁剪后的Bitmap
*/
fun cropCenter(original: Bitmap, targetWidth: Int, targetHeight: Int, offsetX:Int = 0, offsetY:Int = 0): Bitmap {
val originalWidth = original.width
val originalHeight = original.height
// 计算中心点坐标
var startX = (originalWidth - targetWidth) / 2 + offsetX
var startY = (originalHeight - targetHeight) / 2 + offsetY
// 边界检查
startX = startX.coerceAtLeast(0)
startY = startY.coerceAtLeast(0)
val actualWidth = minOf(targetWidth, originalWidth - startX)
val actualHeight = minOf(targetHeight, originalHeight - startY)
return Bitmap.createBitmap(original, startX, startY, actualWidth, actualHeight)
}
}
// 使用示例
//fun main() {
// // 假设这是从资源加载的Bitmap
// val originalBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888)
// // 裁剪中心500x500区域
// val croppedBitmap = BitmapCropper.cropCenter(originalBitmap, 500, 500)
// println("裁剪后尺寸:${croppedBitmap.width}x${croppedBitmap.height}")
//}
@@ -0,0 +1,58 @@
package com.sw.inbound.utils
import android.content.Context
import android.graphics.Bitmap
import android.os.Environment
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
object BitmapSaver {
// 保存到公共目录(需WRITE_EXTERNAL_STORAGE权限)
fun saveToPublicDirectory(
bitmap: Bitmap,
folderName: String = Environment.DIRECTORY_PICTURES,
fileName: String,
format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG,
quality: Int = 100
): File? {
val dir = Environment.getExternalStoragePublicDirectory(folderName)
if (!dir.exists()) dir.mkdirs()
return saveBitmap(bitmap, File(dir, fileName), format, quality)
}
// 保存到应用私有目录(无需权限)
fun saveToAppFilesDir(
bitmap: Bitmap,
context: Context,
fileName: String,
format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG,
quality: Int = 100
): File? {
//val dir = context.getExternalFilesDir(null)
val dir = context.cacheDir
val cropFile = File(dir, "crop")
if (cropFile.exists().not()) {
cropFile.mkdirs()
}
return saveBitmap(bitmap, File(cropFile, fileName), format, quality)
}
private fun saveBitmap(
bitmap: Bitmap,
outputFile: File,
format: Bitmap.CompressFormat,
quality: Int
): File? {
return try {
FileOutputStream(outputFile).use { fos ->
bitmap.compress(format, quality, fos)
fos.flush()
}
outputFile
} catch (e: IOException) {
e.printStackTrace()
null
}
}
}
@@ -0,0 +1,21 @@
package com.sw.inbound.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
object ImageUtil {
fun uriToBitmap(context: Context, uri: Uri): Bitmap? {
return try {
context.contentResolver.openInputStream(uri)?.use { stream ->
BitmapFactory.decodeStream(stream)
}
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}
@@ -0,0 +1,225 @@
package com.sw.inbound.utils.ext
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.TypedValue
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat
import androidx.core.graphics.toColorInt
import androidx.fragment.app.Fragment
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.math.RoundingMode
fun Context.toast(
message: String?,
duration: Int = Toast.LENGTH_SHORT,
) {
if (message.isNullOrBlank()) {
return
}
Handler(Looper.getMainLooper()).post {
Toast.makeText(this, message, duration).show()
}
}
fun Fragment.toast(
message: String?,
duration: Int = 2000
) {
activity?.toast(message, duration)
}
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE
}
fun View.gone() {
visibility = View.GONE
}
inline fun <reified T : Activity> Context.startActivity(
bundle: Bundle? = null,
options: ActivityOptionsCompat? = null
) {
Intent(this, T::class.java).apply {
bundle?.let { putExtras(it) }
if (options != null && this@startActivity is Activity) {
startActivity(this, options.toBundle())
} else {
startActivity(this)
}
}
}
inline fun <reified T> Context.startActivity(
block: Intent.() -> Unit = {}
) {
Intent(this, T::class.java).apply {
block()
startActivity(this)
}
}
//inline fun <reified T : Activity> Context.startActivity(action:(bundle: Bundle)-> Unit) {
// Intent(this, T::class.java).apply {
// action(Bundle())
// startActivity(this)
// }
//}
inline fun <reified T> String.toType(gson: Gson? = null, typeToken: TypeToken<T>): T {
return (gson ?: Gson()).fromJson(this, typeToken.type)
}
inline fun <reified T> String.toObject(gson: Gson? = null): T {
return (gson ?: Gson()).fromJson(this, T::class.java)
}
fun Any?.toJsonString(gson: Gson? = null): String {
return (gson ?: Gson()).toJson(this) ?: ""
}
@SuppressLint("ApplySharedPref")
inline fun SharedPreferences.edit(
commit: Boolean = false,
action: SharedPreferences.Editor.() -> Unit
) {
val editor = edit()
action(editor)
if (commit) editor.commit() else editor.apply()
}
fun SharedPreferences.put(vararg pairs: Pair<String, Any>) {
edit {
pairs.forEach { (key, value) ->
when (value) {
is Int -> putInt(key, value)
is String -> putString(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
is Long -> putLong(key, value)
}
}
}
}
val Float.dp: Float
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this,
Resources.getSystem().displayMetrics
)
val Int.dp: Int
get() = this.toFloat().dp.toInt()
fun EditText.addOnActionSearchListener(searchCallback: () -> Unit) {
setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
// 处理搜索逻辑
searchCallback()
return@setOnEditorActionListener true // 阻止事件继续传递
}
return@setOnEditorActionListener false
}
}
fun View.clickWithDebounce(delay: Long = 300, action: () -> Unit) {
var job: Job? = null
setOnClickListener {
job?.cancel()
job = CoroutineScope(Dispatchers.Main).launch {
delay(delay)
action()
}
}
}
fun Double.roundedDecimalPlace(num: Int): Double {
return BigDecimal(this).setScale(num, RoundingMode.HALF_UP).toDouble()
}
fun Double.roundedOneDecimalPlace(): Double {
return this.roundedDecimalPlace(1)
}
fun View.setShapeDrawable(
solidColor: String = "#FFFFFF",
strokeWidth: Int = 0,
strokeColor: String = "#FFFFFF",
radius: Int = 0
) {
background = GradientDrawable().apply {
setColor(solidColor.toColorInt())
setStroke(strokeWidth, strokeColor.toColorInt())
cornerRadius = radius.toFloat()
}
}
fun View.setShapeDrawable2(
solidColor: String = "#FFFFFF",
strokeWidth: Int = 0,
strokeColor: String = "#FFFFFF",
topLeftRadius: Int = 0,
topRightRadius: Int = 0,
bottomRightRadius: Int = 0,
bottomLeftRadius: Int = 0
) {
background = GradientDrawable().apply {
setColor(solidColor.toColorInt())
setStroke(strokeWidth, strokeColor.toColorInt())
setCornerRadii(
floatArrayOf(
topLeftRadius.toFloat(), topLeftRadius.toFloat(),
topRightRadius.toFloat(), topRightRadius.toFloat(),
bottomRightRadius.toFloat(), bottomRightRadius.toFloat(),
bottomLeftRadius.toFloat(), bottomLeftRadius.toFloat()
)
)
}
}
fun String?.ifNullOrBlank(defaultValue: String): String {
return if (this.isNullOrBlank()) defaultValue else this
}
fun Int?.ifNullOrZero(defaultValue: String): String {
return if (this == null || this == 0) defaultValue else this.toString()
}
fun Double?.ifNullOrZero(defaultValue: String): String {
return if (this == null || this == 0.toDouble()) defaultValue else this.toString()
}
fun View.hideKeyboard() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(this.windowToken, 0)
this.clearFocus() // 清除焦点避免键盘再次弹出
}
@@ -0,0 +1,24 @@
package com.shuwei.intelligent.shelves.utils.ext
import android.text.SpannableStringBuilder
import android.text.Spanned
inline fun buildSpannableString(builderAction: SpannableStringBuilder.() -> Unit): SpannableStringBuilder {
return SpannableStringBuilder().apply(builderAction)
}
fun SpannableStringBuilder.appendText(text: String, vararg spans: Any): SpannableStringBuilder {
val start = length
append(text)
spans.forEach { span ->
setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
}
return this
}
fun SpannableStringBuilder.withSpan(span: Any, block: SpannableStringBuilder.() -> Unit) {
val start = length
block()
setSpan(span, start, length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
}
@@ -0,0 +1,65 @@
package com.sw.inbound.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
class NestedRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
private var lastY = 0f
private var isDragging = false
private var touchSlop = ViewConfiguration.get(context).scaledTouchSlop
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_DOWN -> {
lastY = e.y
parent.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_MOVE -> {
val dy = e.y - lastY
if (!canScrollVertically(-1) && dy > 0) {
parent.requestDisallowInterceptTouchEvent(false)
return false
} else if (!canScrollVertically(1) && dy < 0) {
parent.requestDisallowInterceptTouchEvent(false)
return false
}
}
}
return super.onInterceptTouchEvent(e)
}
override fun onTouchEvent(e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_MOVE -> {
if (!isDragging && abs(e.y - lastY) > touchSlop) {
isDragging = true
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
isDragging = false
}
}
return super.onTouchEvent(e)
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
stopNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
}
}
return super.dispatchTouchEvent(ev)
}
}
@@ -0,0 +1,27 @@
package com.sw.inbound.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
public class NonScrollRecyclerView extends RecyclerView {
public NonScrollRecyclerView(Context context) {
super(context);
}
public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 请求父View不拦截事件,确保子View能接收到事件
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
}
@@ -0,0 +1,54 @@
package com.sw.inbound.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.recyclerview.widget.RecyclerView;
public class ParentRecyclerView extends RecyclerView {
private float downX, downY;
private boolean isIntercept = false;
public ParentRecyclerView(Context context) {
super(context);
}
public ParentRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
downY = ev.getY();
isIntercept = false;
break;
case MotionEvent.ACTION_MOVE:
float deltaX = Math.abs(ev.getX() - downX);
float deltaY = Math.abs(ev.getY() - downY);
// 判断滑动方向,如果是垂直滑动则让父RecyclerView处理
if (deltaY > deltaX && deltaY > getTouchSlop()) {
isIntercept = true;
} else {
isIntercept = false; // 水平滑动不拦截
}
break;
case MotionEvent.ACTION_UP:
isIntercept = false;
break;
}
return isIntercept;
}
private int getTouchSlop() {
return ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
}
@@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
import kotlin.collections.List
abstract class BaseViewModel(
private val repository: RemoteRepository
@@ -94,8 +95,8 @@ abstract class BaseViewModel(
if (response.isSuccess()) {
return true
}
Timber.d("msg = ${response.message}, code = ${response.code}")
ToastUtils.showToast("${response.message}(${response.code})")
Timber.d("msg = ${response.msg}, code = ${response.code}")
//ToastUtils.showToast("${response.msg}(${response.code})")
return false
}
@@ -182,10 +183,25 @@ abstract class BaseViewModel(
/**
* 搜索物品
*/
fun searchGoodsInfoList(
suspend fun searchGoodsInfoList2(
goodsName: String,
pageNo: Int = 1,
pageSize: Int = 10
): List<SearchGoodsInfo.Record> {
val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize)
return if (parseResponse(response)) {
response.result?.records ?: mutableListOf()
} else {
mutableListOf()
}
}
fun searchGoodsInfoList(
goodsName: String,
pageNo: Int = 1,
pageSize: Int = 10,
searchCallback: ((pageNo: Int, List<SearchGoodsInfo.Record>) -> Unit)? = null
) {
launch {
if (pageNo > 1) {
@@ -203,9 +219,11 @@ abstract class BaseViewModel(
} else {
_searchListItems.value = data.records
}
searchCallback?.invoke(pageNo, _searchListItems.value)
}
} else {
_searchListItems.value = emptyList<SearchGoodsInfo.Record>()
searchCallback?.invoke(pageNo, _searchListItems.value)
}
}
}
@@ -217,10 +235,11 @@ abstract class BaseViewModel(
if (parseResponse(response)) {
Timber.d("getGoodsStorageType data = ${response.result}")
response.result?.let {
// val dictType = DictType(response.data)
val list = mutableListOf<DictType>()
for (type in response.result) {
list.add(DictType(type.itemValue!!.toInt(), type.itemText!!))
val list: MutableList<DictType> = mutableListOf()
response.result
?.filter { it.id.isNullOrBlank().not() && it.title.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.title))
}
GlobalData.storageTypeList = list
}
@@ -230,42 +249,53 @@ abstract class BaseViewModel(
val response1 = repository.getGoodsType()
if (parseResponse(response1)) {
Timber.d("getGoodsType data = ${response1.result?.allType}")
response1.result?.let {
if (response1.result.allType != null) {
val list = mutableListOf<DictType>()
for (type in response1.result.allType) {
list.add(DictType(type!!.id!!, type.typeName!!))
}
GlobalData.goodsTypeList = list
}
response1.result
?.allType
?.filter { it?.id.isNullOrBlank().not() && it.typeName.isNullOrBlank().not() }
?.forEach {
list.add(DictType(it!!.id, it.typeName!!))
}
GlobalData.goodsTypeList = list.toList()
} else {
Timber.e("getGoodsType msg = ${response1.message}, code = ${response1.code}")
}
val response2 = repository.getDictType(RemoteRepository.TypeEnum.WAREHOUSE)
if (parseResponse(response2)) {
Timber.d("getDictType WAREHOUSE data = ${response2.result}")
response2.result?.let {
GlobalData.warehouseTypeList = response2.result
val list: MutableList<DictType> = mutableListOf()
response2.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.warehouseTypeList = list.toList()
} else {
Timber.e("getDictType WAREHOUSE msg = ${response2.message}, code = ${response2.code}")
}
val response3 = repository.getDictType(RemoteRepository.TypeEnum.SUPPLIER)
if (parseResponse(response3)) {
Timber.d("getDictType SUPPLIER data = ${response3.result}")
response3.result?.let {
GlobalData.supplierTypeList = response3.result
val list: MutableList<DictType> = mutableListOf()
response3.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.supplierTypeList = list.toList()
} else {
Timber.e("getDictType SUPPLIER msg = ${response3.message}, code = ${response3.code}")
}
val response4 = repository.getDictType(RemoteRepository.TypeEnum.UNIT)
if (parseResponse(response4)) {
Timber.d("getDictType UNIT data = ${response4.result}")
response4.result?.let {
GlobalData.unitTypeList = response4.result
val list: MutableList<DictType> = mutableListOf()
response4.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.unitTypeList = list.toList()
} else {
Timber.e("getDictType UNIT msg = ${response4.message}, code = ${response4.code}")
}
@@ -31,7 +31,7 @@ class PurchaseOrderViewModel @Inject constructor(
val response = repository.getReceiveList(pageNum, pageSize)
updateMoreLoading(false)
if (parseResponse(response)) {
response.result?.records?.let {
response.result?.let {
updateCanLoadMore(it.size >= pageSize)
Timber.d("加载更多 canLoadMore =${it.size >= pageSize}")
_supplierList.value = _supplierList.value + it
@@ -42,7 +42,7 @@ class PurchaseOrderViewModel @Inject constructor(
launchWithLoading {
val response = repository.getReceiveList(pageNum, pageSize)
if (parseResponse(response)) {
response.result?.records?.let {
response.result?.let {
_supplierList.value = it
}
}
@@ -5,6 +5,7 @@ import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.ext.toSafeFloat
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo
@@ -99,11 +100,11 @@ class ReceiptViewModel @Inject constructor(
_showReceiptDialog.value = showDialog
}
fun updateSelectedItemWithSwitch(purchaseOrder: GoodsInfo?) {
viewModelScope.launch {
updateSelectedItem(purchaseOrder)
}
}
// fun updateSelectedItemWithSwitch(purchaseOrder: GoodsInfo?) {
// viewModelScope.launch {
// updateSelectedItem(purchaseOrder)
// }
// }
override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
val firstItem = unadjustedOrders.value.find { order ->
@@ -118,41 +119,42 @@ class ReceiptViewModel @Inject constructor(
/**
* 更新选中的item
*/
fun updateSelectedItem(purchaseOrder: GoodsInfo?) {
if (purchaseOrder != null) {
if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) {
if (purchaseOrder.newRecUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
val result =
purchaseOrder.receivedNum!!.times(purchaseOrder.newRecUnitPriceTaxIn!!)
purchaseOrder.recPriceExItem = result.toSafeFloat()
purchaseOrder.recPriceExItemTemp = result.toFormattedString()
} else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
val result =
purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!)
purchaseOrder.newRecUnitPriceTaxIn = result.toSafeFloat()
purchaseOrder.newRecUnitPriceTaxInTemp = result.toFormattedString()
}
} else {
if (_priceUserInput.value) {
purchaseOrder.recPriceExItem = 0f
purchaseOrder.recPriceExItemTemp = ""
} else if (_amountUserInput.value) {
purchaseOrder.newRecUnitPriceTaxIn = 0f
purchaseOrder.newRecUnitPriceTaxInTemp = ""
}
}
} else {
_countUserInput.value = false
_priceUserInput.value = false
_amountUserInput.value = false
}
_selectedItem.value = purchaseOrder
}
// fun updateSelectedItem(purchaseOrder: GoodsInfo?) {
// if (purchaseOrder != null) {
// if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) {
// if (purchaseOrder.newRecUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
// val result =
// purchaseOrder.receivedNum!!.times(purchaseOrder.newRecUnitPriceTaxIn!!)
// purchaseOrder.recPriceExItem = result.toSafeFloat()
// purchaseOrder.recPriceExItemTemp = result.toFormattedString()
// } else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
// val result =
// purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!)
// purchaseOrder.newRecUnitPriceTaxIn = result.toSafeFloat()
// purchaseOrder.newRecUnitPriceTaxInTemp = result.toFormattedString()
// }
// } else {
// if (_priceUserInput.value) {
// purchaseOrder.recPriceExItem = 0f
// purchaseOrder.recPriceExItemTemp = ""
// } else if (_amountUserInput.value) {
// purchaseOrder.newRecUnitPriceTaxIn = 0f
// purchaseOrder.newRecUnitPriceTaxInTemp = ""
// }
// }
// } else {
// _countUserInput.value = false
// _priceUserInput.value = false
// _amountUserInput.value = false
// }
// _selectedItem.value = purchaseOrder
// }
fun getReceiveDetail(id: Int) {
fun getReceiveDetail(id: String, action:(PurchaseInfo?)->Unit = {}) {
launchWithLoading {
val response = repository.getReceiveDetail(id)
if (parseResponse(response)) {
action(response.result)
_currentPurchaseInfo.value = response.result
initOrders()
}
@@ -199,23 +201,23 @@ class ReceiptViewModel @Inject constructor(
/**
* 更新所有商品仓库
*/
fun updateAllPurchaseStore(warehouse: DictType, predicate: (GoodsInfo) -> Boolean = { true }) {
_orders.update { currentList ->
currentList.map { order ->
if (predicate(order)) order.copy(
warehouseId = warehouse.id,
warehouseName = warehouse.value
) else order
}
}
}
// fun updateAllPurchaseStore(warehouse: DictType, predicate: (GoodsInfo) -> Boolean = { true }) {
// _orders.update { currentList ->
// currentList.map { order ->
// if (predicate(order)) order.copy(
// warehouseId = warehouse.id,
// warehouseName = warehouse.value
// ) else order
// }
// }
// }
// 删除订单
fun removePurchaseOrder(orderId: Int) {
_orders.update { current ->
current.filterNot { it.goodId == orderId }
}
}
// fun removePurchaseOrder(orderId: Int) {
// _orders.update { current ->
// current.filterNot { it.goodId == orderId }
// }
// }
// 清空列表
fun clearPurchaseOrders() {
@@ -243,67 +245,72 @@ class ReceiptViewModel @Inject constructor(
_amountUserInput.value = boolean
}
private var weightCallback:((Int)->Unit)?=null
fun readWeight(callback:(Int)->Unit) {
weightCallback = callback
}
override fun handleSensorScale(weight: Double) {
val currentItem = _selectedItem.value
currentItem?.let { info ->
// 用户输入数量后不再通过重量反算
if (_countUserInput.value) {
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
)
return
}
var consumeValue = currentItem.consumeValue?.toSafeDouble() ?: 1.0
var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0
if (consumeValue == 0.0) {
consumeValue = 1.0
}
if (purchaseValue == 0.0) {
purchaseValue = 1.0
}
val count =
weight * 1000 / consumeValue / purchaseValue
val finalCount = count.toSafeFloat(currentItem.unitName)
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
// 计算单价
val finalPrice = when {
finalCount == 0f -> {
0f
}
_amountUserInput.value && !_priceUserInput.value -> {
info.recPriceExItem!!.div(finalCount).toSafeFloat()
}
else -> 0f
}
// 计算金额
val finalAmount = when {
finalCount == 0f -> {
0f
}
_priceUserInput.value && !_amountUserInput.value -> {
finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat()
}
else -> 0f
}
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
// 收货数量
receivedNumTemp = finalCount.toFormattedString(),
receivedNum = finalCount,
// 单价
newRecUnitPriceTaxIn = if (_priceUserInput.value) info.newRecUnitPriceTaxIn else finalPrice,
newRecUnitPriceTaxInTemp = if (_priceUserInput.value) info.newRecUnitPriceTaxInTemp else finalPrice.toFormattedString(),
// 金额
recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount,
recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(),
)
}
weightCallback?.invoke((weight*1000).toInt())
// val currentItem = _selectedItem.value
//
// currentItem?.let { info ->
// // 用户输入数量后不再通过重量反算
// if (_countUserInput.value) {
// _selectedItem.value = info.copy(
// goodsWeight = weight.toSafeBigDecimal(),
// )
// return
// }
// var consumeValue = currentItem.consumeValue?.toSafeDouble() ?: 1.0
// var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0
// if (consumeValue == 0.0) {
// consumeValue = 1.0
// }
// if (purchaseValue == 0.0) {
// purchaseValue = 1.0
// }
// val count =
// weight * 1000 / consumeValue / purchaseValue
// val finalCount = count.toSafeFloat(currentItem.unitName)
// Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
// // 计算单价
// val finalPrice = when {
// finalCount == 0f -> {
// 0f
// }
//
// _amountUserInput.value && !_priceUserInput.value -> {
// info.recPriceExItem!!.div(finalCount).toSafeFloat()
// }
//
// else -> 0f
// }
// // 计算金额
// val finalAmount = when {
// finalCount == 0f -> {
// 0f
// }
//
// _priceUserInput.value && !_amountUserInput.value -> {
// finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat()
// }
//
// else -> 0f
// }
//
// _selectedItem.value = info.copy(
// goodsWeight = weight.toSafeBigDecimal(),
// // 收货数量
// receivedNumTemp = finalCount.toFormattedString(),
// receivedNum = finalCount,
// // 单价
// newRecUnitPriceTaxIn = if (_priceUserInput.value) info.newRecUnitPriceTaxIn else finalPrice,
// newRecUnitPriceTaxInTemp = if (_priceUserInput.value) info.newRecUnitPriceTaxInTemp else finalPrice.toFormattedString(),
// // 金额
// recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount,
// recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(),
// )
// }
}
fun partialReceipt(uploadInfo: UploadInfo) {
@@ -325,4 +332,18 @@ class ReceiptViewModel @Inject constructor(
}
}
}
fun confirmReceipt(uploadInfo: UploadInfo, callback: (Boolean) -> Unit) {
launchWithLoading {
val resp = repository.confirmReceipt(uploadInfo)
callback(resp.data == true)
}
}
fun addToWarehouse(list: List<PurchaseWarehouseParam>, callback: (Boolean) -> Unit) {
launchWithLoading {
val resp = repository.selfPurchaseWarehousing(list)
callback(resp.data == true)
}
}
}
@@ -1,410 +1,411 @@
package com.sw.inbound.viewmodel
import androidx.lifecycle.viewModelScope
import com.sw.inbound.GlobalData
import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.model.request.GoodsAddParam
import com.sw.inbound.model.request.GoodsPurchaseUnitParam
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.FileUtils
import com.sw.inbound.utils.ToastUtils
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
/**
* 自采购
*/
@HiltViewModel
class SelfProcurementViewModel @Inject constructor(
private val repository: RemoteRepository
) : BaseViewModel(repository) {
private val _addGoodsResult = MutableStateFlow<Boolean>(false)
val addGoodsResult: StateFlow<Boolean> = _addGoodsResult
private val _addGoodsPurchaseUnitResult = MutableStateFlow<Boolean>(false)
val addGoodsPurchaseUnitResult: StateFlow<Boolean> = _addGoodsPurchaseUnitResult
private val _addToWarehouseResult = MutableStateFlow<Boolean>(false)
val addToWarehouseResult: StateFlow<Boolean> = _addToWarehouseResult
private val _selectedItem = MutableStateFlow<PurchaseWarehouseParam?>(null)
val selectedItem: StateFlow<PurchaseWarehouseParam?> = _selectedItem
// 全局仓库信息
private val _globalWarehouse = MutableStateFlow<DictType>(DictType(-1, "选择仓库"))
val globalWarehouse: StateFlow<DictType> = _globalWarehouse
// 采购列表
private val _purchaseList = MutableStateFlow<List<PurchaseWarehouseParam>>(emptyList())
val purchaseList: StateFlow<List<PurchaseWarehouseParam>> = _purchaseList
// 表单状态
private val _goodsAddParam = MutableStateFlow<GoodsAddParam>(GoodsAddParam())
val goodsAddParam: StateFlow<GoodsAddParam> = _goodsAddParam
private val _goodsAddUnitParam =
MutableStateFlow<GoodsPurchaseUnitParam>(GoodsPurchaseUnitParam())
val goodsAddUnitParam: StateFlow<GoodsPurchaseUnitParam> = _goodsAddUnitParam
// 快速添加弹窗状态
private val _showAddProductDialog = MutableStateFlow<Boolean>(false)
val showAddProductDialog: StateFlow<Boolean> = _showAddProductDialog
// 添加采购单位弹窗状态
private val _showAddPurchaseUnitDialog = MutableStateFlow<Boolean>(false)
val showAddPurchaseUnitDialog: StateFlow<Boolean> = _showAddPurchaseUnitDialog
// 是否可以修改库存单位
private val _canChangeKcUnit = MutableStateFlow<Boolean>(false)
val canChangeKcUnit: StateFlow<Boolean> = _canChangeKcUnit
// 是否可以修改消耗值
private val _canChangeConsumeValue = MutableStateFlow<Boolean>(false)
val canChangeConsumeValue: StateFlow<Boolean> = _canChangeConsumeValue
/**
* 数量是否是用户输入的值
*/
private val _countUserInput = MutableStateFlow<Boolean>(false)
/**
* 单价是否是用户输入的值
*/
private val _priceUserInput = MutableStateFlow<Boolean>(false)
/**
* 金额输入状态
*/
private val _amountUserInput = MutableStateFlow<Boolean>(false)
// private val _storeSelectState = MutableStateFlow<String>("")
// val storeSelectState = _storeSelectState
// fun updateStoreState(store:String) {
// _storeSelectState.value = store
//package com.sw.inbound.viewmodel
//
//import androidx.lifecycle.viewModelScope
//import com.sw.inbound.GlobalData
//import com.sw.inbound.ext.toFormattedString
//import com.sw.inbound.ext.toSafeBigDecimal
//import com.sw.inbound.ext.toSafeDouble
//import com.sw.inbound.model.request.GoodsAddParam
//import com.sw.inbound.model.request.GoodsPurchaseUnitParam
//import com.sw.inbound.model.request.PurchaseWarehouseParam
//import com.sw.inbound.model.response.DictType
//import com.sw.inbound.model.response.SearchGoodsInfo
//import com.sw.inbound.repository.RemoteRepository
//import com.sw.inbound.utils.ContextUtils
//import com.sw.inbound.utils.FileUtils
//import com.sw.inbound.utils.ToastUtils
//import dagger.hilt.android.lifecycle.HiltViewModel
//import kotlinx.coroutines.delay
//import kotlinx.coroutines.flow.MutableStateFlow
//import kotlinx.coroutines.flow.StateFlow
//import kotlinx.coroutines.flow.update
//import kotlinx.coroutines.launch
//import timber.log.Timber
//import javax.inject.Inject
//
///**
// * 自采购
// */
//@HiltViewModel
//class SelfProcurementViewModel @Inject constructor(
// private val repository: RemoteRepository
//) : BaseViewModel(repository) {
//
// private val _addGoodsResult = MutableStateFlow<Boolean>(false)
// val addGoodsResult: StateFlow<Boolean> = _addGoodsResult
//
// private val _addGoodsPurchaseUnitResult = MutableStateFlow<Boolean>(false)
// val addGoodsPurchaseUnitResult: StateFlow<Boolean> = _addGoodsPurchaseUnitResult
//
// private val _addToWarehouseResult = MutableStateFlow<Boolean>(false)
// val addToWarehouseResult: StateFlow<Boolean> = _addToWarehouseResult
//
// private val _selectedItem = MutableStateFlow<PurchaseWarehouseParam?>(null)
// val selectedItem: StateFlow<PurchaseWarehouseParam?> = _selectedItem
//
// // 全局仓库信息
// private val _globalWarehouse = MutableStateFlow<DictType>(DictType("", "选择仓库"))
// val globalWarehouse: StateFlow<DictType> = _globalWarehouse
//
// // 采购列表
// private val _purchaseList = MutableStateFlow<List<PurchaseWarehouseParam>>(emptyList())
// val purchaseList: StateFlow<List<PurchaseWarehouseParam>> = _purchaseList
//
// // 表单状态
// private val _goodsAddParam = MutableStateFlow<GoodsAddParam>(GoodsAddParam())
// val goodsAddParam: StateFlow<GoodsAddParam> = _goodsAddParam
//
// private val _goodsAddUnitParam =
// MutableStateFlow<GoodsPurchaseUnitParam>(GoodsPurchaseUnitParam())
// val goodsAddUnitParam: StateFlow<GoodsPurchaseUnitParam> = _goodsAddUnitParam
//
// // 快速添加弹窗状态
// private val _showAddProductDialog = MutableStateFlow<Boolean>(false)
// val showAddProductDialog: StateFlow<Boolean> = _showAddProductDialog
//
// // 添加采购单位弹窗状态
// private val _showAddPurchaseUnitDialog = MutableStateFlow<Boolean>(false)
// val showAddPurchaseUnitDialog: StateFlow<Boolean> = _showAddPurchaseUnitDialog
//
//
// // 是否可以修改库存单位
// private val _canChangeKcUnit = MutableStateFlow<Boolean>(false)
// val canChangeKcUnit: StateFlow<Boolean> = _canChangeKcUnit
//
// // 是否可以修改消耗值
// private val _canChangeConsumeValue = MutableStateFlow<Boolean>(false)
// val canChangeConsumeValue: StateFlow<Boolean> = _canChangeConsumeValue
//
// /**
// * 数量是否是用户输入的值
// */
// private val _countUserInput = MutableStateFlow<Boolean>(false)
//
// /**
// * 单价是否是用户输入的值
// */
// private val _priceUserInput = MutableStateFlow<Boolean>(false)
//
// /**
// * 金额输入状态
// */
// private val _amountUserInput = MutableStateFlow<Boolean>(false)
//
//// private val _storeSelectState = MutableStateFlow<String>("")
//// val storeSelectState = _storeSelectState
//// fun updateStoreState(store:String) {
//// _storeSelectState.value = store
//// }
// /**
// * 更新全局仓库
// */
// fun updateGlobalWarehouse(dictType: DictType) {
// _globalWarehouse.value = dictType
// }
/**
* 更新全局仓库
*/
fun updateGlobalWarehouse(dictType: DictType) {
_globalWarehouse.value = dictType
}
override fun handleSensorScale(weight: Double) {
val currentItem = _selectedItem.value
currentItem?.let { info ->
val selectUnitType = currentItem.selectUnitType
// 用户输入数量后不再通过重量反算
if (_countUserInput.value || selectUnitType == null) {
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
)
return
}
//
// override fun handleSensorScale(weight: Double) {
// val currentItem = _selectedItem.value
//
// currentItem?.let { info ->
// val selectUnitType = currentItem.selectUnitType
// if (selectUnitType == null) return@startScale
var consumeValue = selectUnitType.consumeValue?.toSafeDouble() ?: 1.0
var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0
if (consumeValue == 0.0) {
consumeValue = 1.0
}
if (purchaseValue == 0.0) {
purchaseValue = 1.0
}
val count =
weight * 1000 / consumeValue / purchaseValue
val finalCount = count.toSafeDouble(currentItem.unitName)
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ")
// 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入
val finalPrice =
if (finalCount == 0.0) {
0.0
} else if (_amountUserInput.value && !_priceUserInput.value) {
info.goodsPrice.div(finalCount).toSafeDouble()
} else 0.0
// 计算金额 单价不为空,不是数量输入 也不是金额输入
val finalAmount =
if (finalCount == 0.0) {
0.0
} else if (_priceUserInput.value && !_amountUserInput.value) {
finalCount.times(info.goodsUnitPrice).toSafeDouble()
} else 0.0
Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ")
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
// 数量
goodsCountTemp = finalCount.toFormattedString(),
goodsCount = finalCount,
// 单价
goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice,
goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(),
// 金额
goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount,
goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString()
)
}
}
fun updateAddProductDialog(show: Boolean) {
_showAddProductDialog.value = show
if (!show) {
_goodsAddParam.value = GoodsAddParam()
}
}
fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) {
// updateLastPhotoUri(null)
if (purchaseOrder != null) {
if (purchaseOrder.goodsCount != 0.0) {
if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
Timber.d("updateSelectedItem 计算金额")
val result =
purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice)
purchaseOrder.goodsPrice = result.toSafeDouble()
purchaseOrder.goodsPriceTemp = result.toFormattedString()
} else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
Timber.d("updateSelectedItem 计算单价")
val result =
purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount)
purchaseOrder.goodsUnitPrice = result.toSafeDouble()
purchaseOrder.goodsUnitPriceTemp = result.toFormattedString()
}
} else {
if (_priceUserInput.value) {
purchaseOrder.goodsPrice = 0.0
purchaseOrder.goodsPriceTemp = ""
} else if (_amountUserInput.value) {
purchaseOrder.goodsUnitPrice = 0.0
purchaseOrder.goodsUnitPriceTemp = ""
}
}
} else {
// 重置输入状态
Timber.d("重置输入状态")
_countUserInput.value = false
_priceUserInput.value = false
_amountUserInput.value = false
}
_selectedItem.value = purchaseOrder
Timber.d("updateSelectedItem 更新,goodsUnitPrice = ${_selectedItem.value?.goodsUnitPrice}, ${_selectedItem.value?.goodsUnitPriceTemp}")
}
fun updateGoodsAddParam(newState: GoodsAddParam) {
_goodsAddParam.value = newState
}
fun cleanGoodsAddParam() {
_goodsAddParam.value = GoodsAddParam()
}
// 添加订单
fun addPurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
_purchaseList.update { currentList ->
currentList + purchaseOrder
}
updateSelectedItem(null)
}
// 更新订单
fun updatePurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
_purchaseList.update { currentList ->
currentList.map { order ->
if (order.goodsId == purchaseOrder.goodsId) purchaseOrder else order
}
}
}
// 删除订单
fun removePurchaseOrder(orderId: Int) {
_purchaseList.update { currentList ->
currentList.filterNot { it.goodsId == orderId }
}
}
/**
* 根据位置删除物品
*/
fun removePurchaseOrderByIndex(index: Int) {
_purchaseList.update { currentList ->
currentList.toMutableList().apply {
removeAt(index)
}
}
}
// 清空列表
fun clearPurchaseOrders() {
_purchaseList.value = emptyList()
}
override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
updateSelectedItemWithSearch(goodsInfo)
}
fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) {
val warehouse = _globalWarehouse.value
viewModelScope.launch {
updateSelectedItem(null)
delay(50)
_selectedItem.value = PurchaseWarehouseParam(
warehouseId = warehouse.id,
goodsId = searchFirst.goodsId ?: 0,
goodsName = searchFirst.goodsName,
kcUnitId = searchFirst.kcUnitId ?: 0,
unitList = searchFirst.unitVoList,
consumeValue = searchFirst.consumeValue ?: ""
)
}
}
/**
* 数量输入状态
*/
fun updateCountInputState(boolean: Boolean) {
_countUserInput.value = boolean
}
/**
* 单价输入状态
*/
fun updatePriceInputState(boolean: Boolean) {
_priceUserInput.value = boolean
}
/**
* 金额输入状态
*/
fun updateAmountInputState(boolean: Boolean) {
_amountUserInput.value = boolean
}
/**
* 添加商品
*/
fun addGoodsInfo() {
val imageUri = GlobalData.imageUri
if (imageUri == null) {
ToastUtils.showToast("请先进行图片采集")
return
}
val errInfo = _goodsAddParam.value.hasNullField()
if (errInfo != null) {
ToastUtils.showToast(errInfo)
return
}
launchWithLoading {
val uploadResponse = repository.uploadImage(imageUri)
if (!parseResponse(uploadResponse)) {
return@launchWithLoading
}
// ToastUtils.showToast("图片上传成功,${uploadResponse.data}")
GlobalData.imageUri = null
_goodsAddParam.value.relativeUrl = uploadResponse.result
val response = repository.selfPurchaseGoodsAdd(_goodsAddParam.value)
if (!parseResponse(response)) {
return@launchWithLoading
}
FileUtils.deleteFileWithUri(context = ContextUtils.getAppContext(), uri = imageUri)
_showAddProductDialog.value = false
_goodsAddParam.value = GoodsAddParam()
val searchFirst = response.result!!.records?.get(0)
searchFirst?.let {
updateSelectedItemWithSearch(searchFirst)
}
_addGoodsResult.value = true
}
}
fun updateAddPurchaseUnitDialog(show: Boolean) {
if (_selectedItem.value == null) return
_showAddPurchaseUnitDialog.value = show
if (show) {
val hasUnitId = GlobalData.unitTypeList.any { it.id == _selectedItem.value!!.kcUnitId }
_canChangeKcUnit.value = !hasUnitId
_canChangeConsumeValue.value =
_selectedItem.value!!.consumeValue.trim().isEmpty() == true
} else {
_goodsAddUnitParam.value = GoodsPurchaseUnitParam()
}
}
fun updateGoodsPurchaseUnit(goodsPurchaseUnitParam: GoodsPurchaseUnitParam?) {
if (goodsPurchaseUnitParam == null) {
_goodsAddUnitParam.value = GoodsPurchaseUnitParam()
} else {
_goodsAddUnitParam.value = goodsPurchaseUnitParam
}
}
fun updateDropdownTextChange(canChange: Boolean) {
_canChangeKcUnit.value == canChange
}
fun addGoodsPurchaseUnit() {
val errorInfo = _goodsAddUnitParam.value.hasNullField()
if (errorInfo != null) {
ToastUtils.showToast(errorInfo)
return
}
launchWithLoading {
val response = repository.selfPurchaseGoodsAddUnit(_goodsAddUnitParam.value)
if (parseResponse(response)) {
_showAddPurchaseUnitDialog.value = false
_goodsAddUnitParam.value = GoodsPurchaseUnitParam()
// _addGoodsPurchaseUnitResult.value = true
ToastUtils.showToast("采购单位添加成功")
// 通过id搜索物品,补充采购单位
val response = repository.searchGoodsInfoList(
goodsName = "${_selectedItem.value?.goodsId}"
)
if (parseResponse(response)) {
val searchList: List<SearchGoodsInfo.Record> =
response.result?.records ?: emptyList()
if (searchList.isNotEmpty()) {
val searchItem = searchList[0]
_selectedItem.value = _selectedItem.value?.copy(
unitList = searchItem.unitVoList,
kcUnitId = searchItem.kcUnitId ?: 0,
consumeValue = searchItem.consumeValue ?: ""
)
}
}
}
}
}
/**
* 物品提交入库
*/
fun addToWarehouse() {
if (_purchaseList.value.isEmpty()) {
ToastUtils.showToast("采购列表为空")
return
}
launchWithLoading {
val response = repository.selfPurchaseWarehousing(_purchaseList.value)
_addToWarehouseResult.value = parseResponse(response)
}
}
}
// // 用户输入数量后不再通过重量反算
// if (_countUserInput.value || selectUnitType == null) {
// _selectedItem.value = info.copy(
// goodsWeight = weight.toSafeBigDecimal(),
// )
// return
// }
//
//// val selectUnitType = currentItem.selectUnitType
//// if (selectUnitType == null) return@startScale
//
// var consumeValue = selectUnitType.consumeValue?.toSafeDouble() ?: 1.0
// var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0
// if (consumeValue == 0.0) {
// consumeValue = 1.0
// }
// if (purchaseValue == 0.0) {
// purchaseValue = 1.0
// }
// val count =
// weight * 1000 / consumeValue / purchaseValue
// val finalCount = count.toSafeDouble(currentItem.unitName)
// Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
//
// Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ")
// // 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入
// val finalPrice =
// if (finalCount == 0.0) {
// 0.0
// } else if (_amountUserInput.value && !_priceUserInput.value) {
// info.goodsPrice.div(finalCount).toSafeDouble()
// } else 0.0
//
// // 计算金额 单价不为空,不是数量输入 也不是金额输入
// val finalAmount =
// if (finalCount == 0.0) {
// 0.0
// } else if (_priceUserInput.value && !_amountUserInput.value) {
// finalCount.times(info.goodsUnitPrice).toSafeDouble()
// } else 0.0
// Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ")
// _selectedItem.value = info.copy(
// goodsWeight = weight.toSafeBigDecimal(),
// // 数量
// goodsCountTemp = finalCount.toFormattedString(),
// goodsCount = finalCount,
// // 单价
// goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice,
// goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(),
// // 金额
// goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount,
// goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString()
// )
// }
// }
//
// fun updateAddProductDialog(show: Boolean) {
// _showAddProductDialog.value = show
// if (!show) {
// _goodsAddParam.value = GoodsAddParam()
// }
// }
//
// fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) {
//// updateLastPhotoUri(null)
// if (purchaseOrder != null) {
// if (purchaseOrder.goodsCount != 0.0) {
// if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
// Timber.d("updateSelectedItem 计算金额")
// val result =
// purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice)
// purchaseOrder.goodsPrice = result.toSafeDouble()
// purchaseOrder.goodsPriceTemp = result.toFormattedString()
// } else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
// Timber.d("updateSelectedItem 计算单价")
// val result =
// purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount)
// purchaseOrder.goodsUnitPrice = result.toSafeDouble()
// purchaseOrder.goodsUnitPriceTemp = result.toFormattedString()
// }
// } else {
// if (_priceUserInput.value) {
// purchaseOrder.goodsPrice = 0.0
// purchaseOrder.goodsPriceTemp = ""
// } else if (_amountUserInput.value) {
// purchaseOrder.goodsUnitPrice = 0.0
// purchaseOrder.goodsUnitPriceTemp = ""
// }
// }
// } else {
// // 重置输入状态
// Timber.d("重置输入状态")
// _countUserInput.value = false
// _priceUserInput.value = false
// _amountUserInput.value = false
// }
// _selectedItem.value = purchaseOrder
// Timber.d("updateSelectedItem 更新,goodsUnitPrice = ${_selectedItem.value?.goodsUnitPrice}, ${_selectedItem.value?.goodsUnitPriceTemp}")
// }
//
// fun updateGoodsAddParam(newState: GoodsAddParam) {
// _goodsAddParam.value = newState
// }
//
// fun cleanGoodsAddParam() {
// _goodsAddParam.value = GoodsAddParam()
// }
//
// // 添加订单
// fun addPurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
// _purchaseList.update { currentList ->
// currentList + purchaseOrder
// }
// updateSelectedItem(null)
// }
//
// // 更新订单
// fun updatePurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
// _purchaseList.update { currentList ->
// currentList.map { order ->
// if (order.goodsId == purchaseOrder.goodsId) purchaseOrder else order
// }
// }
// }
//
// // 删除订单
//// fun removePurchaseOrder(orderId: Int) {
//// _purchaseList.update { currentList ->
//// currentList.filterNot { it.goodsId == orderId }
//// }
//// }
//
// /**
// * 根据位置删除物品
// */
// fun removePurchaseOrderByIndex(index: Int) {
// _purchaseList.update { currentList ->
// currentList.toMutableList().apply {
// removeAt(index)
// }
// }
// }
//
// // 清空列表
// fun clearPurchaseOrders() {
// _purchaseList.value = emptyList()
// }
//
// override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
//// updateSelectedItemWithSearch(goodsInfo)
// }
//
//// fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) {
//// val warehouse = _globalWarehouse.value
//// viewModelScope.launch {
//// updateSelectedItem(null)
//// delay(50)
//// _selectedItem.value = PurchaseWarehouseParam(
//// warehouseId = warehouse.id,
//// goodsId = searchFirst.goodsId ?: 0,
//// goodsName = searchFirst.goodsName,
//// kcUnitId = searchFirst.kcUnitId ?: 0,
//// unitList = searchFirst.unitVoList,
//// consumeValue = searchFirst.consumeValue ?: ""
//// )
//// }
//// }
//
// /**
// * 数量输入状态
// */
// fun updateCountInputState(boolean: Boolean) {
// _countUserInput.value = boolean
// }
//
// /**
// * 单价输入状态
// */
// fun updatePriceInputState(boolean: Boolean) {
// _priceUserInput.value = boolean
// }
//
// /**
// * 金额输入状态
// */
// fun updateAmountInputState(boolean: Boolean) {
// _amountUserInput.value = boolean
// }
//
// /**
// * 添加商品
// */
//// fun addGoodsInfo() {
//// val imageUri = GlobalData.imageUri
//// if (imageUri == null) {
//// ToastUtils.showToast("请先进行图片采集")
//// return
//// }
//// val errInfo = _goodsAddParam.value.hasNullField()
//// if (errInfo != null) {
//// ToastUtils.showToast(errInfo)
//// return
//// }
////
//// launchWithLoading {
//// val uploadResponse = repository.uploadImage(imageUri)
//// if (!parseResponse(uploadResponse)) {
//// return@launchWithLoading
//// }
////// ToastUtils.showToast("图片上传成功,${uploadResponse.data}")
//// GlobalData.imageUri = null
//// _goodsAddParam.value.relativeUrl = uploadResponse.result
//// val response = repository.selfPurchaseGoodsAdd(_goodsAddParam.value)
//// if (!parseResponse(response)) {
//// return@launchWithLoading
//// }
//// FileUtils.deleteFileWithUri(context = ContextUtils.getAppContext(), uri = imageUri)
//// _showAddProductDialog.value = false
//// _goodsAddParam.value = GoodsAddParam()
//// val searchFirst = response.result!!.records?.get(0)
//// searchFirst?.let {
//// updateSelectedItemWithSearch(searchFirst)
//// }
//// _addGoodsResult.value = true
//// }
//// }
//
// fun updateAddPurchaseUnitDialog(show: Boolean) {
// if (_selectedItem.value == null) return
// _showAddPurchaseUnitDialog.value = show
// if (show) {
// val hasUnitId =
// GlobalData.unitTypeList.any { it.id == _selectedItem.value!!.kcUnitId.toString() }
// _canChangeKcUnit.value = !hasUnitId
// _canChangeConsumeValue.value =
// _selectedItem.value!!.consumeValue.trim().isEmpty() == true
// } else {
// _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
// }
// }
//
// fun updateGoodsPurchaseUnit(goodsPurchaseUnitParam: GoodsPurchaseUnitParam?) {
// if (goodsPurchaseUnitParam == null) {
// _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
// } else {
// _goodsAddUnitParam.value = goodsPurchaseUnitParam
// }
// }
//
// fun updateDropdownTextChange(canChange: Boolean) {
// _canChangeKcUnit.value == canChange
// }
//
// fun addGoodsPurchaseUnit() {
// val errorInfo = _goodsAddUnitParam.value.hasNullField()
// if (errorInfo != null) {
// ToastUtils.showToast(errorInfo)
// return
// }
// launchWithLoading {
// val response = repository.selfPurchaseGoodsAddUnit(_goodsAddUnitParam.value)
// if (parseResponse(response)) {
// _showAddPurchaseUnitDialog.value = false
// _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
//// _addGoodsPurchaseUnitResult.value = true
// ToastUtils.showToast("采购单位添加成功")
//
// // 通过id搜索物品,补充采购单位
// val response = repository.searchGoodsInfoList(
// goodsName = "${_selectedItem.value?.goodsId}"
// )
// if (parseResponse(response)) {
// val searchList: List<SearchGoodsInfo.Record> =
// response.result?.records ?: emptyList()
// if (searchList.isNotEmpty()) {
// val searchItem = searchList[0]
// _selectedItem.value = _selectedItem.value?.copy(
// unitList = searchItem.unitVoList,
// kcUnitId = searchItem.kcUnitId ?: 0,
// consumeValue = searchItem.consumeValue ?: ""
// )
// }
// }
// }
// }
// }
//
// /**
// * 物品提交入库
// */
// fun addToWarehouse() {
// if (_purchaseList.value.isEmpty()) {
// ToastUtils.showToast("采购列表为空")
// return
// }
// launchWithLoading {
// val response = repository.selfPurchaseWarehousing(_purchaseList.value)
// _addToWarehouseResult.value = parseResponse(response)
// }
// }
//}
@@ -28,12 +28,12 @@ class UserViewModel @Inject constructor(
fun getInitInfo() {
Timber.d("getInitInfo isFirstLaunch = $isFirstLaunch")
if (isFirstLaunch) {
//if (isFirstLaunch) {
getUserInfo()
getDictType()
isFirstLaunch = false
}
//}
}
fun login(userName: String, password: String) = launchWithLoading {
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF0032C8"/>
<corners android:radius="10dp"/>
</shape>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item android:drawable="@drawable/bg_blue_radius10"/>
</ripple>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFEFDFC"/>
<corners android:radius="12dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFDCDCF0"/>
<corners android:radius="10dp"/>
</shape>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="#FF14CD71"/>
<corners android:radius="6dp"/>
</shape>
</item>
</ripple>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#99FFFFFF"/>
<corners android:radius="6dp"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="10dp"/>
<stroke android:color="#FFD5E1FF" android:width="2dp"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="10dp"/>
<stroke android:color="#FFDCDCF0" android:width="2dp"/>
</shape>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="10dp" />
<stroke
android:width="2dp"
android:color="#FFDCDCF0"
android:dashWidth="10dp"
android:dashGap="3dp" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="12dp"/>
</shape>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:color="#FF0032C8" android:width="2dp"/>
<corners android:radius="10dp"/>
</shape>
</item>
</ripple>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:color="#FF14CD71" android:width="2dp"/>
<corners android:radius="6dp"/>
</shape>
</item>
</ripple>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="#99FFFFFF"/>
</shape>
</item>
</ripple>
@@ -0,0 +1,206 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg"
android:orientation="vertical"
tools:ignore="HardcodedText">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="出入库管理"
android:textColor="#141428"
android:textSize="36sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="center_vertical"
android:textColor="#141428"
android:textSize="24sp"
android:textStyle="bold"
tools:text="冯厨子" />
<ImageView
android:id="@+id/ivLogout"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginEnd="40dp"
android:paddingHorizontal="20dp"
android:src="@mipmap/ic_logout"
tools:ignore="ContentDescription" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="20dp"
android:layout_weight="1"
android:background="@drawable/bg_white_alpha40_radius6"
android:orientation="vertical"
android:paddingHorizontal="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tvPurchaseNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff333333"
android:textSize="24sp"
android:textStyle="bold"
tools:text="采购单号:CG2506190526" />
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="2dp"
android:layout_height="2dp"
android:layout_marginStart="5dp" />
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/flWarehouseDropdown"
android:layout_width="280dp"
android:layout_height="70dp"
android:background="@drawable/bg_white_radius10_stroke"
android:paddingHorizontal="30dp">
<TextView
android:id="@+id/tvWareHouse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginEnd="32dp"
android:ellipsize="end"
android:maxLines="1"
android:text="选择仓库"
android:textColor="#000033"
android:textSize="24sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/ivDropdown"
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FFD5E1FF" />
<!-- <include layout="@layout/list_item_receipt_goods" />-->
<!-- <include layout="@layout/list_item_self_procurement" />-->
<FrameLayout
android:id="@+id/flContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvGoodsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="8" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="130dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/btnBack"
android:layout_width="270dp"
android:layout_height="90dp"
android:layout_marginStart="20dp"
android:background="@drawable/bg_blue_ripple">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableStart="@mipmap/ic_back_white2"
android:drawablePadding="32dp"
android:gravity="center"
android:text="返回"
android:textColor="@color/white"
android:textSize="36sp"
android:textStyle="bold"
tools:ignore="UseCompatTextViewDrawableXml" />
</FrameLayout>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<TextView
android:id="@+id/tvConfirmNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="60dp"
android:textColor="#ff141428"
android:textSize="30sp"
android:textStyle="bold"
tools:text="已确认 3"
android:visibility="gone"/>
<TextView
android:id="@+id/tvNotConfirmNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="60dp"
android:textColor="#ff141428"
android:textSize="30sp"
android:textStyle="bold"
tools:text="未确认 6"
android:visibility="gone"/>
<TextView
android:id="@+id/btnConfirmReceipt"
android:layout_width="270dp"
android:layout_height="90dp"
android:layout_gravity="center"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_blue_ripple"
android:gravity="center"
android:text="确认收货"
android:textColor="@color/white"
android:textSize="36sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,588 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1500dp"
android:layout_height="900dp"
android:background="@drawable/bg_white_radius12"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:layout_width="wrap_content"
android:layout_height="120dp"
android:gravity="center"
android:text="新增物品"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="40dp"
android:background="#FFDCDCF0" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingHorizontal="40dp">
<FrameLayout
android:id="@+id/flImageCollect"
android:layout_width="430dp"
android:layout_height="322dp"
android:layout_marginTop="40dp"
android:background="@drawable/bg_white_radius10_stroke2_dash"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/llGoodsInfo">
<LinearLayout
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>
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="428dp"
android:layout_height="320dp"
android:layout_gravity="center"
android:visibility="gone"/>
<ImageView
android:id="@+id/ivGoodsImage"
android:layout_width="428dp"
android:layout_height="320dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
</FrameLayout>
<Button
android:id="@+id/btnStartPreview"
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_constraintStart_toStartOf="@id/flImageCollect"
app:layout_constraintTop_toBottomOf="@id/flImageCollect" />
<LinearLayout
android:id="@+id/btnTakePhoto"
android:layout_width="210dp"
android:layout_height="70dp"
android:layout_marginStart="10dp"
android:background="@drawable/bg_green_ripple"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="@id/btnStartPreview"
app:layout_constraintEnd_toEndOf="@id/flImageCollect"
app:layout_constraintStart_toEndOf="@id/btnStartPreview"
app:layout_constraintTop_toTopOf="@id/btnStartPreview">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@mipmap/ic_camera_white"
android:drawablePadding="11dp"
android:gravity="center"
android:text="采集"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
tools:ignore="UseCompatTextViewDrawableXml" />
</LinearLayout>
<LinearLayout
android:id="@+id/llGoodsInfo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="80dp"
android:gravity="center_vertical"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/flImageCollect">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="432dp"
android:layout_height="wrap_content"
android:text="物品名称"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:text="净材率"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/etGoodsName"
android:layout_width="432dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:hint="请录入"
android:maxLines="1"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<FrameLayout
android:layout_width="432dp"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:background="@drawable/bg_white_radius10_stroke2">
<EditText
android:id="@+id/etNetMaterialRate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="请录入"
android:maxLines="1"
android:layout_marginEnd="60dp"
android:inputType="numberDecimal"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
android:background="#00000000"
tools:ignore="Autofill,TextFields" />
<TextView
android:layout_width="60dp"
android:layout_height="match_parent"
android:text="%"
android:gravity="center"
android:layout_gravity="end|center_vertical"
android:textColor="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<TextView
android:layout_width="432dp"
android:layout_height="wrap_content"
android:text="物品类型"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:text="存储方式"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/flGoodsType"
android:layout_width="432dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvGoodsType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<FrameLayout
android:id="@+id/flStorageType"
android:layout_width="432dp"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvStorageType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp">
<TextView
android:layout_width="432dp"
android:layout_height="wrap_content"
android:text="库存单位"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:text="消耗单位"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/flWarehouseUnit"
android:layout_width="432dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvWarehouseUnit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:gravity="center_vertical">
<EditText
android:id="@+id/etUseUnit"
android:layout_width="188dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="start|center_vertical"
android:hint="请输入"
android:inputType="number"
android:maxLines="1"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:textColor="#FF000000"
android:textColorHint="#FFC7C8DC"
android:textSize="24sp"
tools:ignore="Autofill" />
<TextView
android:layout_width="82dp"
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingStart="29dp"
android:text="克"
android:textColor="#ffa0a0b4"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="RtlSymmetry" />
<TextView
android:layout_width="42dp"
android:layout_height="60dp"
android:gravity="center_vertical"
android:text="="
android:textColor="#ff96a0aa"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvSelectUseUnit"
android:layout_width="120dp"
android:layout_height="60dp"
android:background="@drawable/bg_gray_radius10"
android:gravity="center"
android:textColor="#ff96a0aa"
android:textSize="24sp"
android:textStyle="bold"
tools:text="瓶" />
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="采购单位"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="92dp"
android:layout_marginTop="20dp"
android:background="@drawable/bg_white_radius10_stroke2_dash"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="61dp"
android:layout_height="60dp"
android:gravity="center"
android:text="1"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<FrameLayout
android:id="@+id/flProcurementUnit"
android:layout_width="180dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvProcurementUnit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:id="@+id/ivDropdown"
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:layout_width="72dp"
android:layout_height="60dp"
android:gravity="center"
android:text="="
android:textColor="#FF96A0AA"
android:textSize="24sp" />
<EditText
android:id="@+id/etGoodsCount"
android:layout_width="160dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="center"
android:hint="请录入"
android:inputType="number"
android:maxLines="1"
android:paddingStart="25dp"
android:paddingEnd="25dp"
android:textColor="#FF000000"
android:textColorHint="#FFC7C8DC"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill" />
<TextView
android:id="@+id/tvSelectProcurementUnit"
android:layout_width="112dp"
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingStart="30dp"
android:textColor="#FF141428"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="RtlSymmetry"
tools:text="瓶" />
<TextView
android:layout_width="78dp"
android:layout_height="60dp"
android:gravity="center_vertical"
android:textColor="#FF141428"
android:textSize="24sp"
android:textStyle="bold"
android:text="单价" />
<EditText
android:id="@+id/etGoodsPrice"
android:layout_width="160dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="center"
android:hint="请录入"
android:inputType="numberDecimal"
android:maxLines="1"
android:paddingStart="25dp"
android:paddingEnd="25dp"
android:textColor="#FF000000"
android:textColorHint="#FFC7C8DC"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill" />
<TextView
android:layout_width="82dp"
android:layout_height="60dp"
android:gravity="center"
android:textColor="#FFA0A0B4"
android:textSize="24sp"
android:textStyle="bold"
android:text="元" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="40dp"
android:background="#FFDCDCF0" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="160dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="50dp">
<Button
android:id="@+id/btnClose"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/bg_white_stroke_blue_ripple"
android:text="关闭"
android:textColor="#FF0033CC"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnConfirm"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:layout_marginStart="30dp"
android:background="@drawable/bg_blue_ripple"
android:text="确定"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1190dp"
android:layout_height="840dp"
android:background="@drawable/bg_white_radius12"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:layout_width="wrap_content"
android:layout_height="184dp"
android:gravity="center"
android:text="添加采购单位"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="30dp"
android:background="#FFDCDCF0" />
<LinearLayout
android:layout_width="802dp"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="370dp"
android:layout_height="wrap_content"
android:text="库存单位"
android:textColor="#ff141428"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="62dp"
android:text="消耗单位"
android:textColor="#ff141428"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/flWarehouseUnit"
android:layout_width="370dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvWarehouseUnit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<EditText
android:id="@+id/etUseUnit"
android:layout_width="158dp"
android:layout_height="60dp"
android:layout_marginStart="62dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="start|center_vertical"
android:hint="请输入"
android:inputType="number"
android:maxLines="1"
android:paddingStart="25dp"
android:paddingEnd="25dp"
android:textColor="#FF000000"
android:textColorHint="#FFC7C8DC"
android:textSize="24sp"
tools:ignore="Autofill" />
<TextView
android:layout_width="76dp"
android:layout_height="60dp"
android:text="克"
android:textStyle="bold"
android:paddingStart="24dp"
android:paddingEnd="30dp"
android:gravity="center_vertical"
android:textColor="#ffa0a0b4"
android:textSize="24sp" />
<TextView
android:layout_width="36dp"
android:layout_height="60dp"
android:text="="
android:gravity="center_vertical"
android:textStyle="bold"
android:textColor="#ff96a0aa"
android:textSize="24sp" />
<TextView
android:id="@+id/tvSelectUnit"
android:layout_width="100dp"
android:layout_height="60dp"
tools:text="瓶"
android:textStyle="bold"
android:gravity="center"
android:background="@drawable/bg_gray_radius10"
android:textColor="#ff96a0aa"
android:textSize="24sp" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="采购单位"
android:textColor="#ff141428"
android:layout_marginTop="30dp"
android:textSize="24sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="92dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="30dp"
android:background="@drawable/bg_white_radius10_stroke2_dash">
<TextView
android:layout_width="72dp"
android:layout_height="60dp"
android:text="1"
android:gravity="center"
android:textStyle="bold"
android:textColor="#ff141428"
android:textSize="24sp" />
<FrameLayout
android:id="@+id/flProcurementUnit"
android:layout_width="260dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvProcurementUnit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:id="@+id/ivDropdown"
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:layout_width="102dp"
android:layout_height="60dp"
android:text="="
android:gravity="center"
android:textColor="#FF96A0AA"
android:textSize="24sp" />
<EditText
android:id="@+id/etInputWeight"
android:layout_width="260dp"
android:layout_height="60dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="center"
android:hint="请录入"
android:maxLines="1"
android:inputType="numberDecimal"
android:paddingStart="25dp"
android:paddingEnd="25dp"
android:textColor="#FF000000"
android:textColorHint="#FFC7C8DC"
android:textStyle="bold"
android:textSize="24sp"
tools:ignore="Autofill" />
<TextView
android:layout_width="108dp"
android:layout_height="60dp"
android:text="千克"
android:gravity="center"
android:textColor="#FF96A0AA"
android:textSize="24sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="完善更多单位信息请登录后台维护,建议及时操作以确保信息准确"
android:textColor="#ff999999"
android:textSize="24sp"
android:layout_marginTop="50dp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="30dp"
android:background="#FFDCDCF0" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="160dp"
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="30dp">
<Button
android:id="@+id/btnCancel"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/bg_white_stroke_blue_ripple"
android:text="取消"
android:textColor="#FF0033CC"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnConfirm"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:layout_marginStart="20dp"
android:background="@drawable/bg_blue_ripple"
android:text="确定"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1500dp"
android:layout_height="900dp"
android:background="@drawable/bg_white_radius12"
tools:ignore="HardcodedText">
<ImageView
android:id="@+id/ivClose"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="30dp"
android:padding="10dp"
android:src="@mipmap/ic_close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tvDialogTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="物品识别结果"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/rvRecognize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvRecognize"
android:layout_width="wrap_content"
android:layout_height="340dp"
android:layout_marginTop="180dp"
tools:itemCount="5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:overScrollMode="never"
android:layout_marginHorizontal="30dp"
tools:listitem="@layout/list_item_recognize"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/dividerLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FFDCDCF0"
android:layout_marginBottom="160dp"
android:layout_marginHorizontal="40dp"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="@+id/btnManuallyFind"
android:layout_width="240dp"
android:layout_height="80dp"
android:text="手动查找"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/dividerLine"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@+id/btnAgainRecognize"
android:textColor="#FF0033CC"
android:textSize="30sp"
android:background="@drawable/bg_white_stroke_blue_ripple"/>
<Button
android:id="@+id/btnAgainRecognize"
android:layout_width="240dp"
android:layout_height="80dp"
android:text="重新识别"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/dividerLine"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btnManuallyFind"
android:textColor="@color/white"
android:layout_marginStart="30dp"
android:textSize="30sp"
android:background="@drawable/bg_blue_ripple"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="若以上识别结果都不是该物品,请点击“重新识别”或“手动查找”"
android:textColor="#ff999999"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/dividerLine"
android:layout_marginBottom="60dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1500dp"
android:layout_height="900dp"
android:background="@drawable/bg_white_radius12"
tools:ignore="HardcodedText">
<ImageView
android:id="@+id/ivClose"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="30dp"
android:padding="10dp"
android:src="@mipmap/ic_close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tvDialogTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="物品检索"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/flSearchBlock"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/flSearchBlock"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginHorizontal="150dp"
android:layout_marginTop="180dp"
android:background="@drawable/bg_white_radius10_stroke2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/etInputGoods"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
android:gravity="center"
android:hint="输入物品名称"
android:maxLines="1"
android:paddingStart="10dp"
android:paddingEnd="80dp"
android:textColor="#FF666666"
android:textColorHint="#FFC7C8DC"
android:textSize="30sp"
android:inputType="text"
android:imeOptions="actionSearch" />
<ImageView
android:id="@+id/ivGoodsSearch"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="16dp"
android:padding="14dp"
android:src="@mipmap/ic_goods_search" />
</FrameLayout>
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="130dp"
android:layout_marginTop="40dp"
android:layout_marginBottom="58dp"
app:layout_constraintBottom_toTopOf="@id/dividerLine"
app:layout_constraintTop_toBottomOf="@id/flSearchBlock">
<com.scwang.smart.refresh.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvSearch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="8"
tools:listitem="@layout/list_item_goods_search" />
<com.scwang.smart.refresh.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<View
android:id="@+id/dividerLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="40dp"
android:layout_marginBottom="160dp"
android:background="#FFDCDCF0"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- <Button-->
<!-- android:id="@+id/btnAddGoods"-->
<!-- android:layout_width="240dp"-->
<!-- android:layout_height="80dp"-->
<!-- android:background="@drawable/bg_white_stroke_blue_ripple"-->
<!-- android:text="添加物品"-->
<!-- android:textColor="#FF0033CC"-->
<!-- android:textSize="30sp"-->
<!-- android:textStyle="bold"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@+id/btnConfirm"-->
<!-- app:layout_constraintHorizontal_chainStyle="packed"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="@id/dividerLine"-->
<!-- android:visibility="gone"/>-->
<Button
android:id="@+id/btnConfirm"
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/bg_blue_ripple"
android:text="确定"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/dividerLine" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,388 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1500dp"
android:layout_height="900dp"
android:background="@drawable/bg_white_radius12"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:ignore="HardcodedText">
<TextView
android:layout_width="wrap_content"
android:layout_height="142dp"
android:gravity="center"
android:text="物品入库"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="40dp"
android:background="#FFDCDCF0" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="1dp"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="70dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="物品名称"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etGoodsName"
android:layout_width="428dp"
android:layout_height="70dp"
android:layout_marginStart="57dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:hint="请录入"
android:maxLines="1"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="70dp"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="入库单位"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<FrameLayout
android:id="@+id/flUnitDropdown"
android:layout_width="428dp"
android:layout_height="70dp"
android:layout_marginStart="57dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvProcurementUnit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="24dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:hint="请选择"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<ImageView
android:id="@+id/ivDropdown"
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_triangle_down"
tools:ignore="ContentDescription" />
</FrameLayout>
<ImageView
android:id="@+id/ivAddUnit"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginStart="10dp"
android:src="@mipmap/ic_add_unit"
tools:ignore="ContentDescription"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="70dp"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="入库数量"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<FrameLayout
android:layout_width="428dp"
android:layout_height="70dp"
android:layout_marginStart="57dp"
android:background="@drawable/bg_white_radius10_stroke2">
<EditText
android:id="@+id/etProcurementCount"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginEnd="70dp"
android:background="#00000000"
android:hint="请录入"
android:maxLines="1"
android:inputType="number"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<TextView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="end|center_vertical"
android:gravity="center"
android:text="-"
android:textColor="#ff96a0aa"
android:textSize="24sp"
android:textStyle="bold" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="70dp"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="入库单价"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<FrameLayout
android:layout_width="428dp"
android:layout_height="70dp"
android:layout_marginStart="57dp"
android:background="@drawable/bg_white_radius10_stroke2">
<TextView
android:id="@+id/tvProcurementPrice"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginEnd="70dp"
android:background="#00000000"
android:hint="由入库数量和金额计算生成"
android:gravity="center_vertical"
android:maxLines="1"
android:ellipsize="end"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<TextView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="end|center_vertical"
android:gravity="center"
android:text="元"
android:textColor="#ff96a0aa"
android:textSize="24sp"
android:textStyle="bold" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="70dp"
android:layout_marginTop="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="入库金额"
android:textColor="#ff141428"
android:textSize="24sp"
android:textStyle="bold" />
<FrameLayout
android:layout_width="428dp"
android:layout_height="70dp"
android:layout_marginStart="57dp"
android:background="@drawable/bg_white_radius10_stroke2">
<EditText
android:id="@+id/etProcurementAmount"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginEnd="70dp"
android:background="#00000000"
android:hint="请录入"
android:maxLines="1"
android:inputType="numberDecimal"
android:paddingHorizontal="24dp"
android:textColor="#ff141428"
android:textColorHint="#FF96A0AA"
android:textSize="24sp"
android:textStyle="bold"
tools:ignore="Autofill,TextFields" />
<TextView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="end|center_vertical"
android:gravity="center"
android:text="元"
android:textColor="#ff96a0aa"
android:textSize="24sp"
android:textStyle="bold" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/guideline">
<FrameLayout
android:layout_width="488dp"
android:layout_height="356dp"
android:background="@drawable/bg_white_radius10_stroke2"
android:padding="2dp">
<ImageView
android:id="@+id/ivGoodsImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher"/>
</FrameLayout>
<FrameLayout
android:layout_width="488dp"
android:layout_height="70dp"
android:layout_marginTop="37dp"
android:background="@drawable/bg_gray_radius10">
<TextView
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="center"
android:text="累计"
android:textColor="#FF141428"
android:textSize="24sp" />
<TextView
android:id="@+id/tvTotalWeight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginHorizontal="120dp"
android:gravity="center"
android:textColor="#FF141428"
android:textSize="24sp"
tools:text="6300 克" />
<TextView
android:id="@+id/btnClearZero"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="@drawable/bg_white_radius10_stroke2"
android:gravity="center"
android:text="清零"
android:textColor="#FF141428"
android:textSize="24sp" />
</FrameLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginHorizontal="40dp"
android:background="#FFDCDCF0" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="160dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="50dp">
<Button
android:id="@+id/btnCancel"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/bg_white_stroke_blue_ripple"
android:text="取消"
android:textColor="#FF0033CC"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnConfirm"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:layout_marginStart="30dp"
android:background="@drawable/bg_blue_ripple"
android:text="确定"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="960dp"
android:layout_height="540dp"
android:gravity="center"
android:orientation="vertical"
android:background="@drawable/bg_white_radius12"
tools:ignore="HardcodedText">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_tip_warn"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="80dp"
android:layout_marginVertical="50dp"
android:gravity="center"
android:text="存在未收货的物品,请确认是否放弃收货,若放弃则数据不会保存?"
android:textColor="#ff141428"
android:textSize="36sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击“取消”按钮返回页面,去收货;点击“确认”按钮关闭页面,放弃收货。"
android:textColor="#ff999999"
android:textSize="24sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<Button
android:id="@+id/btnCancel"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:background="@drawable/bg_white_stroke_blue_ripple"
android:text="取消"
android:textColor="#FF0033CC"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnConfirm"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="240dp"
android:layout_height="80dp"
android:layout_marginStart="50dp"
android:background="@drawable/bg_blue_ripple"
android:text="确认"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText,UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="80dp"
android:src="@mipmap/ic_tip_warn"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="系统异常,请稍后重试!"
android:textColor="#ff000000"
android:textSize="36sp"
android:textStyle="bold" />
</LinearLayout>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:ignore="HardcodedText">
<ImageView
android:layout_width="wrap_content"
android:layout_height="80dp"
android:src="@mipmap/ic_empty_view"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginBottom="39dp"
android:text="暂无该物品"
android:textColor="#ff000000"
android:textSize="36sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请检查物品名称,或点击“添加物品”按钮新增物品信息"
android:textColor="#ff999999"
android:textSize="30sp" />
</LinearLayout>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvWarehouse"
android:layout_width="280dp"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="10"
android:layout_margin="1dp"
android:overScrollMode="never"
tools:listitem="@layout/list_item_dropdown"
android:background="@drawable/bg_white_radius10_stroke" />
</FrameLayout>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/ripple_effect_light">
<TextView
android:id="@+id/tvDropdown"
android:layout_width="match_parent"
android:layout_height="70dp"
android:gravity="center"
android:textColor="#ff000033"
android:textSize="24sp"
android:textStyle="bold"
tools:text="选择仓库" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#90D5E1FF" />
</LinearLayout>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="82dp"
android:layout_marginVertical="10dp"
android:layout_marginHorizontal="20dp"
tools:background="@drawable/bg_white_stroke_blue_ripple">
<TextView
android:id="@+id/tvGoodsName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
tools:text="高杆白菜"
android:textColor="#ff666666"
android:textSize="30sp"
android:maxLines="1"
android:ellipsize="end"
android:textStyle="bold" />
</FrameLayout>
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="86dp"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/tvGoodsName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="物品名称"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvProcurementUnit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="采购单位"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvProcurementCount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="采购数量"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvProcurementPrice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="采购单价(元)"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvProcurementAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="采购金额(元)"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvReceiptCount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="收货数量"
android:textColor="#ff999999"
android:textSize="26sp" />
<TextView
android:id="@+id/tvGoodsWeight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="物品重量(克)"
android:textColor="#ff999999"
android:textSize="26sp" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.6">
<TextView
android:id="@+id/tvState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:text="状态"
android:textColor="#ff999999"
android:textSize="26sp" />
<ImageView
android:id="@+id/ivState"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:gravity="center"
android:src="@mipmap/ic_receipt_no"
android:visibility="gone"
tools:ignore="ContentDescription" />
</FrameLayout>
</LinearLayout>

Some files were not shown because too many files have changed in this diff Show More