出入库功能改版

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 { plugins {
alias(libs.plugins.android.application) // alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) // alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose) // alias(libs.plugins.kotlin.compose)
id("com.google.devtools.ksp") id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.dagger.hilt.android") id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
id("kotlin-parcelize") id("kotlin-parcelize")
// id("compose.compiler")
kotlin("kapt")
alias(libs.plugins.kotlin.compose)
} }
android { android {
@@ -54,7 +59,11 @@ android {
} }
buildFeatures { buildFeatures {
compose = true compose = true
viewBinding = true
} }
// composeOptions {
// kotlinCompilerExtensionVersion = "1.5.4"
// }
sourceSets { sourceSets {
named("main") { named("main") {
jniLibs.srcDirs("libs") jniLibs.srcDirs("libs")
@@ -119,7 +128,20 @@ dependencies {
implementation(libs.core) implementation(libs.core)
implementation(libs.android.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:1.7.0")
implementation("androidx.compose.foundation:foundation-layout: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" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.sw.inbound.activity.ReceiptActivity"
android:screenOrientation="landscape"/>
<activity android:name="com.sw.inbound.activity.SelfProcurementActivity" />
<!-- <activity--> <!-- <activity-->
<!-- android:name=".InitActivity"--> <!-- 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 * 具体业务baseurl
*/ */
var appBaseUrl: String = "" var appBaseUrl: String = "http://192.168.1.201:14801"
/** /**
* 设备id * 设备id
+5 -2
View File
@@ -1,6 +1,7 @@
package com.sw.inbound package com.sw.inbound
import android.app.Application import android.app.Application
import com.sw.inbound.objbox.ObjectBox
import com.sw.inbound.utils.AppUtil import com.sw.inbound.utils.AppUtil
import com.sw.inbound.utils.ContextUtils import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.CrashHandler import com.sw.inbound.utils.CrashHandler
@@ -12,20 +13,22 @@ import timber.log.Timber
class MyApp : Application() { class MyApp : Application() {
companion object { companion object {
const val DEBUG: Boolean = true const val DEBUG: Boolean = true
var instance: MyApp?=null
} }
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
instance = this
Timber.plant(Timber.DebugTree()) Timber.plant(Timber.DebugTree())
ContextUtils.initAppContext(this) ContextUtils.initAppContext(this)
GlobalData.appVersion = AppUtil.getAppVersionCode(this).toString() GlobalData.appVersion = AppUtil.getAppVersionCode(this).toString()
var deviceId = AppUtil.getUDID(this) var deviceId = AppUtil.getUDID(this)
deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212" ///deviceId = "6ce7cd59-b875-38b2-b73d-88a570be3212"
GlobalData.deviceId = deviceId GlobalData.deviceId = deviceId
val spUtil = SPUtil.getInstance(context = ContextUtils.getAppContext()) val spUtil = SPUtil.getInstance(context = ContextUtils.getAppContext())
GlobalData.appToken = spUtil.get(GlobalKey.KEY_TOKEN, "") as String GlobalData.appToken = spUtil.get(GlobalKey.KEY_TOKEN, "") as String
ObjectBox.init(this)
// 初始化崩溃处理器 // 初始化崩溃处理器
CrashHandler.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 storageTypeStr = value
} }
get() { get() {
return GlobalData.storageTypeList.find { it.id == storageType }?.value ?: "" return GlobalData.storageTypeList.find { it.id == storageType.toString() }?.value ?: ""
} }
val netRateStr: String val netRateStr: String
@@ -99,7 +100,7 @@ data class GoodsAddParam(
val unitIdStr: String val unitIdStr: String
get() { get() {
return GlobalData.unitTypeList.find { it.id == unitId }?.value ?: "" return GlobalData.unitTypeList.find { it.id == unitId.toString() }?.value ?: ""
} }
val unitIdStrPlace: String val unitIdStrPlace: String
@@ -121,13 +122,13 @@ data class GoodsAddParam(
if (purchaseUnit == 0) { if (purchaseUnit == 0) {
return "" return ""
} }
return GlobalData.unitTypeList.find { it.id == purchaseUnit }?.value ?: "" return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: ""
} }
fun hasNullField(): String? { fun hasNullField(): String? {
if (goodName == null || goodName!!.isEmpty()) if (goodName == null || goodName!!.isEmpty())
return "请录入物品名称" return "请录入物品名称"
if (goodType == null || goodType == 0) { if (goodType.isNullOrBlank() || goodType == "0") {
return "请选择物品类型" return "请选择物品类型"
} }
if (storageType == null || storageType == 0) { if (storageType == null || storageType == 0) {
@@ -19,7 +19,7 @@ data class GoodsPurchaseUnitParam(
val unitIdStr: String val unitIdStr: String
get() { get() {
if (unitId == 0) return "" if (unitId == 0) return ""
return GlobalData.unitTypeList.find { it.id == unitId }?.value ?: "" return GlobalData.unitTypeList.find { it.id == unitId.toString() }?.value ?: ""
} }
val purchaseUnitStr: String val purchaseUnitStr: String
@@ -27,7 +27,7 @@ data class GoodsPurchaseUnitParam(
if (purchaseUnit == 0) { if (purchaseUnit == 0) {
return "" return ""
} }
return GlobalData.unitTypeList.find { it.id == purchaseUnit }?.value ?: "" return GlobalData.unitTypeList.find { it.id == purchaseUnit.toString() }?.value ?: ""
} }
fun hasNullField(): String? { fun hasNullField(): String? {
@@ -17,11 +17,11 @@ data class PurchaseWarehouseParam(
/** /**
* 物品id * 物品id
*/ */
var goodsId: Int = 0, var goodsId: String = "",
/** /**
* 库存单位 * 库存单位
*/ */
var kcUnitId: Int = -1, var kcUnitId: String? = "",
/** /**
* 入库数量 * 入库数量
*/ */
@@ -45,11 +45,11 @@ data class PurchaseWarehouseParam(
/** /**
* (物品列表里 businessUnitId字段的值) * (物品列表里 businessUnitId字段的值)
*/ */
var goodPurId: Int = -1, var goodPurId: String?="",
/** /**
* 仓库id * 仓库id
*/ */
var warehouseId: Int = -1, var warehouseId: String?="",
/** /**
* 采购库存转换关系 * 采购库存转换关系
@@ -75,10 +75,10 @@ data class PurchaseWarehouseParam(
val warehouseNameStr: String val warehouseNameStr: String
get() { get() {
if (warehouseId == -1) { if (warehouseId.isNullOrBlank()) {
return "" return ""
} }
return GlobalData.warehouseTypeList.find { it.id == warehouseId }?.value ?: "" return GlobalData.warehouseTypeList.find { it.id == warehouseId.toString() }?.value ?: ""
// if (warehouseName == null) { // if (warehouseName == null) {
// return "" // return ""
// } // }
@@ -111,15 +111,15 @@ data class PurchaseWarehouseParam(
return goodsName!! return goodsName!!
} }
val unitDictTypeList: List<DictType> // val unitDictTypeList: List<DictType>
get() { // get() {
return if (unitList == null) emptyList() // return if (unitList == null) emptyList()
else { // else {
unitList!!.filter { it.businessUnitId != null && it.purchaseUnitName != null }.map { // unitList!!.filter { it.businessUnitId != null && it.purchaseUnitName != null }.map {
DictType(it.businessUnitId?.toInt() ?: 0, it.purchaseUnitName ?: "") // DictType(it.businessUnitId?.toInt() ?: 0, it.purchaseUnitName ?: "")
} // }
} // }
} // }
val unitNameStr: String val unitNameStr: String
get() { get() {
@@ -152,12 +152,12 @@ data class PurchaseWarehouseParam(
} }
fun hasNullField(): String? { fun hasNullField(): String? {
if (goodsId == null || goodsId == 0 || goodsName == null || goodsName!!.isEmpty()) if (goodsId.isNullOrBlank() || goodsName == null || goodsName!!.isEmpty())
return "请选择物品" return "请选择物品"
if (warehouseId == null || warehouseId == -1) { if (warehouseId.isNullOrBlank()) {
return "请选择仓库" return "请选择仓库"
} }
if (goodPurId == null || goodPurId == -1) { if (goodPurId.isNullOrBlank()) {
return "请选择采购单位" return "请选择采购单位"
} }
if (goodsCount == null || goodsCount == 0.0) { if (goodsCount == null || goodsCount == 0.0) {
@@ -14,11 +14,11 @@ data class UploadInfo(
/** /**
* 收货单id * 收货单id
*/ */
var id: Int, var id: String,
/** /**
* 供应商id * 供应商id
*/ */
var supplierId: Int? = null, var supplierId: String? = null,
/** /**
* *
* 物品信息 【全部收货使用】 * 物品信息 【全部收货使用】
@@ -77,7 +77,7 @@ private data class UploadGoodsInfo(
/** /**
* 采购单位id * 采购单位id
*/ */
var purchaseUnitId: Int = 0, var purchaseUnitId: String = "",
/** /**
* 收货数量 * 收货数量
@@ -1,11 +1,24 @@
package com.sw.inbound.model.response 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>( data class ApiResponse<T>(
val code: Int, val code: String,
val success: Boolean? = false, val msg: String? = "",
val message: String? = "", val data: T? = null
val result: T? = null,
val timestamp: Long? = 0
) { ) {
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 @Parcelize
data class DictType( data class DictType(
val id: Int, val id: String?=null,
val value: String val value: String?=null
) : Parcelable ) : Parcelable
@@ -16,11 +16,11 @@ data class GoodsInfo(
/** /**
* 数据id * 数据id
*/ */
var id: Int? = 0, var id: String? = "",
/** /**
* 物品Id * 物品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 = "", var recUnitPriceTaxInTemp: String = "",
@@ -36,7 +36,7 @@ data class GoodsInfo(
/** /**
* 新单价 部分收货需要 * 新单价 部分收货需要
*/ */
var newRecUnitPriceTaxIn: Float? = null, var newRecUnitPriceTaxIn: Double? = null,
var newRecUnitPriceTaxInTemp: String = "", var newRecUnitPriceTaxInTemp: String = "",
/** /**
@@ -47,22 +47,22 @@ data class GoodsInfo(
/** /**
* 采购单位id * 采购单位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 = "", var recPriceExItemTemp: String = "",
/** /**
* 仓库id * 仓库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 consumeValue: String? = "",
// 收货数量 收货入参 // 收货数量 收货入参
var receivedNum: Float? = null, var receivedNum: Double? = null,
// 收货数量显示 // 收货数量显示
var receivedNumTemp: String = "", var receivedNumTemp: String = "",
// 重量 收货入参 // 重量 收货入参
@@ -96,7 +96,12 @@ data class GoodsInfo(
var isAdjusted: Boolean = false, 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() { ) : Parcelable, BaseBean() {
val goodNameStr: String val goodNameStr: String
@@ -120,7 +125,7 @@ data class GoodsInfo(
val receivedNumCount: String val receivedNumCount: String
get() { get() {
if (receivedNum == null || receivedNum == 0f) if (receivedNum == null || receivedNum == 0.toDouble())
return "0" return "0"
return receivedNum?.toSafeString(unitName) ?: "0" return receivedNum?.toSafeString(unitName) ?: "0"
@@ -128,9 +133,9 @@ data class GoodsInfo(
val dualCountStr: String val dualCountStr: String
get() { 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)}" "${receivedNum.toSafeString(unitName)}/${receiveCount.toSafeString(unitName)}"
} else if (receivedNum != null && receivedNum != 0f) { } else if (receivedNum != null && receivedNum != 0.toDouble()) {
"${receivedNum.toSafeString(unitName)}/-" "${receivedNum.toSafeString(unitName)}/-"
} else { } else {
receiveCountListStr receiveCountListStr
@@ -139,33 +144,33 @@ data class GoodsInfo(
val recUnitPriceTaxInStr: String val recUnitPriceTaxInStr: String
get() { get() {
if (recUnitPriceTaxIn == 0f) return "" if (recUnitPriceTaxIn == 0.toDouble()) return ""
return recUnitPriceTaxIn?.toFormattedString() ?: "" return recUnitPriceTaxIn?.toFormattedString() ?: ""
} }
val recUnitPriceTaxInListStr: String val recUnitPriceTaxInListStr: String
get() { get() {
if (recUnitPriceTaxIn == 0f) return "-" if (recUnitPriceTaxIn == 0.toDouble()) return "-"
return recUnitPriceTaxIn?.toFormattedString() ?: "-" return recUnitPriceTaxIn?.toFormattedString() ?: "-"
} }
val newRecUnitPriceTaxInListStr: String val newRecUnitPriceTaxInListStr: String
get() { get() {
if (newRecUnitPriceTaxIn == 0f) return "-" if (newRecUnitPriceTaxIn == 0.toDouble()) return "-"
return newRecUnitPriceTaxIn?.toFormattedString() ?: "-" return newRecUnitPriceTaxIn?.toFormattedString() ?: "-"
} }
val receiveCountStr: String val receiveCountStr: String
get() { get() {
return when (receiveCount) { return when (receiveCount) {
0f -> "" 0.toDouble() -> ""
else -> receiveCount?.toSafeString(unitName) ?: "" else -> receiveCount?.toSafeString(unitName) ?: ""
} }
} }
val receiveCountListStr: String val receiveCountListStr: String
get() { get() {
return when (receiveCount) { return when (receiveCount) {
0f -> "-" 0.toDouble() -> "-"
else -> receiveCount?.toSafeString(unitName) ?: "-" else -> receiveCount?.toSafeString(unitName) ?: "-"
} }
} }
@@ -173,14 +178,14 @@ data class GoodsInfo(
val recPriceExItemStr: String val recPriceExItemStr: String
get() { get() {
return when (recPriceExItem) { return when (recPriceExItem) {
0f -> "" 0.toDouble() -> ""
else -> recPriceExItem?.toFormattedString() ?: "" else -> recPriceExItem?.toFormattedString() ?: ""
} }
} }
val recPriceExItemListStr: String val recPriceExItemListStr: String
get() { get() {
return when (recPriceExItem) { return when (recPriceExItem) {
0f -> "-" 0.toDouble() -> "-"
else -> recPriceExItem?.toFormattedString() ?: "-" else -> recPriceExItem?.toFormattedString() ?: "-"
} }
} }
@@ -217,7 +222,7 @@ data class GoodsInfo(
purchaseUnitIdStr = value purchaseUnitIdStr = value
} }
get() { get() {
return GlobalData.unitTypeList.find { it.id == purchaseUnitId }?.value ?: "" return GlobalData.unitTypeList.find { it.id == purchaseUnitId.toString() }?.value ?: ""
} }
val warehouseNameStr: String val warehouseNameStr: String
@@ -229,16 +234,16 @@ data class GoodsInfo(
} }
fun hasNullField(): String? { fun hasNullField(): String? {
if (warehouseId == null) { if (warehouseId.isNullOrBlank()) {
return "请选择仓库" return "请选择仓库"
} }
if (receivedNum == null || receivedNum == 0f) { if (receivedNum == null || receivedNum == 0.toDouble()) {
return "请输入收货数量或进行称重" return "请输入收货数量或进行称重"
} }
if (newRecUnitPriceTaxIn == null || newRecUnitPriceTaxIn == 0f) { if (newRecUnitPriceTaxIn == null || newRecUnitPriceTaxIn == 0.toDouble()) {
return "请输入收货单价" return "请输入收货单价"
} }
if (recPriceExItem == null || recPriceExItem == 0f) { if (recPriceExItem == null || recPriceExItem == 0.toDouble()) {
return "请输入收货金额" return "请输入收货金额"
} }
if (goodsWeight == null || goodsWeight!!.toFloat() <= 0) { if (goodsWeight == null || goodsWeight!!.toFloat() <= 0) {
@@ -27,7 +27,7 @@ data class GoodsType(
* 物品id * 物品id
*/ */
@SerializedName("id") @SerializedName("id")
val id: Int? = 0, val id: String? = "",
@SerializedName("idResult") @SerializedName("idResult")
val idResult: String? = "", val idResult: String? = "",
@SerializedName("kidTypes") @SerializedName("kidTypes")
@@ -37,7 +37,7 @@ data class GoodsType(
@SerializedName("pageSize") @SerializedName("pageSize")
val pageSize: String? = "", val pageSize: String? = "",
@SerializedName("status") @SerializedName("status")
val status: Int? = 0, val status: Boolean? = false,
@SerializedName("superName") @SerializedName("superName")
val superName: String? = "", val superName: String? = "",
@SerializedName("typeCode") @SerializedName("typeCode")
@@ -7,11 +7,11 @@ data class PurchaseInfo(
/** /**
* 单据id * 单据id
*/ */
var id: Int = 0, var id: String,
/** /**
* 供应商id * 供应商id
*/ */
var supplierId: Int = 0, var supplierId: String,
/** /**
* 供应商名称 * 供应商名称
*/ */
@@ -31,13 +31,17 @@ data class SearchGoodsInfo(
) : Parcelable { ) : Parcelable {
@Parcelize @Parcelize
data class Record( data class Record(
@SerializedName("relativeUrl")
val relativeUrl: String? = "",
@SerializedName("goodsCode") @SerializedName("goodsCode")
val goodsCode: String? = "", val goodsCode: String? = "",
@SerializedName("id")
val id: String? = "",
/** /**
* 物品id * 物品id
*/ */
@SerializedName("goodsId") @SerializedName("goodsId")
val goodsId: Int? = 0, val goodsId: String? = "",
/** /**
* 物品名称 * 物品名称
*/ */
@@ -58,6 +62,7 @@ data class SearchGoodsInfo(
* 库存与克的转换值 * 库存与克的转换值
*/ */
val consumeValue: String? = "", val consumeValue: String? = "",
val purchaseValue: String? = "",
@SerializedName("specification") @SerializedName("specification")
val specification: String? = "", val specification: String? = "",
@@ -71,7 +76,8 @@ data class SearchGoodsInfo(
@SerializedName("unitVoList") @SerializedName("unitVoList")
val unitVoList: List<UnitVo>? = listOf(), val unitVoList: List<UnitVo>? = listOf(),
@SerializedName("zjmCode") @SerializedName("zjmCode")
val zjmCode: String? = "" val zjmCode: String? = "",
var isSelected: Boolean = false
) : Parcelable { ) : Parcelable {
val goodsNameStr: String val goodsNameStr: String
get() { get() {
@@ -1,53 +1,62 @@
package com.sw.inbound.model.response package com.sw.inbound.model.response
import android.os.Parcelable //import android.os.Parcelable
import com.google.gson.annotations.SerializedName //import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize //import kotlinx.parcelize.Parcelize
/** /**
* 存储方式 * 存储方式
*/ */
@Parcelize
data class StorageType( data class StorageType(
@SerializedName("childList") val id:String?=null,
val childList: List<String?>? = listOf(), val value:String?=null,
@SerializedName("createTime") val text:String?=null,
val createTime: String? = "", val title:String?=null,
@SerializedName("createUserNo") val label:String?=null,
val createUserNo: String? = "",
@SerializedName("depth") )
val depth: String? = "", //@Parcelize
@SerializedName("description") //data class StorageType(
val description: String? = "", // @SerializedName("childList")
@SerializedName("dictId") // val childList: List<String?>? = listOf(),
val dictId: String? = "", // @SerializedName("createTime")
@SerializedName("eaId") // val createTime: String? = "",
val eaId: Int? = 0, // @SerializedName("createUserNo")
@SerializedName("fid") // val createUserNo: String? = "",
val fid: String? = "", // @SerializedName("depth")
@SerializedName("id") // val depth: String? = "",
val id: Int? = 0, // @SerializedName("description")
@SerializedName("idc") // val description: String? = "",
val idc: String? = "", // @SerializedName("dictId")
/** // val dictId: String? = "",
* 名称 // @SerializedName("eaId")
*/ // val eaId: Int? = 0,
@SerializedName("itemText") // @SerializedName("fid")
val itemText: String? = "", // val fid: String? = "",
/** // @SerializedName("id")
* 对应值 // val id: String? = "",
*/ // @SerializedName("idc")
@SerializedName("itemValue") // val idc: String? = "",
val itemValue: String? = "", // /**
@SerializedName("level") // * 名称
val level: Int? = 0, // */
@SerializedName("sortOrder") // @SerializedName("itemText")
val sortOrder: Int? = 0, // val itemText: String? = "",
@SerializedName("status") // /**
val status: Int? = 0, // * 对应值
@SerializedName("updateTime") // */
val updateTime: String? = "", // @SerializedName("itemValue")
@SerializedName("updateUserNo") // val itemValue: String? = "",
val updateUserNo: String? = "" // @SerializedName("level")
) : Parcelable // 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 * 订单id
*/ */
@SerializedName("id") @SerializedName("id")
val id: Int = 0, val id: String? = "",
@SerializedName("pageNum") @SerializedName("pageNum")
val pageNum: String? = "", val pageNum: String? = "",
@SerializedName("pageSize") @SerializedName("pageSize")
@@ -100,7 +100,7 @@ data class SupplierInfo(
* 供应商id * 供应商id
*/ */
@SerializedName("supplierId") @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.PurchaseInfo
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.model.response.StorageType 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.SupplierResponse
import com.sw.inbound.model.response.User import com.sw.inbound.model.response.User
import okhttp3.MultipartBody import okhttp3.MultipartBody
@@ -30,6 +31,10 @@ import retrofit2.http.Url
* api接口 * api接口
*/ */
interface ApiService { interface ApiService {
private val apiPrefix: String
get() = "/terminal/neglect/inbound"
/** /**
* device获取token * device获取token
*/ */
@@ -56,28 +61,33 @@ interface ApiService {
suspend fun login( suspend fun login(
@Url url: String = "${GlobalData.appBaseUrl}/sys/loginPad", @Url url: String = "${GlobalData.appBaseUrl}/sys/loginPad",
@Body body: LoginParam, @Body body: LoginParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<User> ): 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( suspend fun getReceiveList(
@Url url: String = "${GlobalData.appBaseUrl}/pad/receivePage", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/receivePage",
@Query("pageNo") pageNo: Int, @Body param:Map<String, String>
@Query("pageSize") pageSize: Int, ): ApiResponse<List<SupplierInfo>?>
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<SupplierResponse>
/** /**
* 采购单入库-详情 * 采购单入库-详情
*/ */
@GET//("pad/receiveDetail") @GET//("pad/receiveDetail")
suspend fun getReceiveDetail( suspend fun getReceiveDetail(
@Url url: String = "${GlobalData.appBaseUrl}/pad/receiveDetail", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/receiveDetail",
@Query("id") id: Int, @Query("id") id: String
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<PurchaseInfo> ): ApiResponse<PurchaseInfo>
/** /**
@@ -85,9 +95,8 @@ interface ApiService {
*/ */
@POST//("pad/partialReceiptGoods") @POST//("pad/partialReceiptGoods")
suspend fun partialReceipt( suspend fun partialReceipt(
@Url url: String = "${GlobalData.appBaseUrl}/pad/partialReceiptGoods", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/partialReceiptGoods",
@Body uploadInfo: UploadInfo, @Body uploadInfo: UploadInfo
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean> ): ApiResponse<Boolean>
/** /**
@@ -95,9 +104,8 @@ interface ApiService {
*/ */
@POST//("pad/saveAndReceiveAndGoWare") @POST//("pad/saveAndReceiveAndGoWare")
suspend fun confirmReceipt( suspend fun confirmReceipt(
@Url url: String = "${GlobalData.appBaseUrl}/pad/saveAndReceiveAndGoWare", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/saveAndReceiveAndGoWare",
@Body uploadInfo: UploadInfo, @Body uploadInfo: UploadInfo,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean> ): ApiResponse<Boolean>
/** /**
@@ -105,9 +113,10 @@ interface ApiService {
*/ */
@GET//("sys/dict/getDictItemByF") @GET//("sys/dict/getDictItemByF")
suspend fun getGoodsStorageType( suspend fun getGoodsStorageType(
@Url url: String = "${GlobalData.appBaseUrl}/sys/dict/getDictItemByF", // @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/sys/dict/getDictItemByF",
@Query("dictCode") dictCode: String = "goods_storage_type", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/getDictItemByF",
@Header("x-access-token") token: String = GlobalData.appToken // @Query("dictCode") dictCode: String = "goods_storage_type",
@Query("dictCode") dictCode: String = "ccfs",
): ApiResponse<List<StorageType>> ): ApiResponse<List<StorageType>>
/** /**
@@ -115,8 +124,7 @@ interface ApiService {
*/ */
@GET//("pad/notLimitList") @GET//("pad/notLimitList")
suspend fun getGoodsType( suspend fun getGoodsType(
@Url url: String = "${GlobalData.appBaseUrl}/pad/notLimitList", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/notLimitList",
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<GoodsType> ): ApiResponse<GoodsType>
/** /**
@@ -124,9 +132,8 @@ interface ApiService {
*/ */
@GET//("pad/dataList") @GET//("pad/dataList")
suspend fun getDictType( suspend fun getDictType(
@Url url: String = "${GlobalData.appBaseUrl}/pad/dataList", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/dataList",
@Query("type") type: String, @Query("type") type: String
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<List<DictType>> ): ApiResponse<List<DictType>>
/** /**
@@ -135,22 +142,21 @@ interface ApiService {
@Multipart @Multipart
@POST//("sys/common/upload") @POST//("sys/common/upload")
suspend fun uploadImage( 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("code") code: RequestBody,
@Part file: MultipartBody.Part, @Part file: MultipartBody.Part,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<String> ): ApiResponse<String>
/** /**
* 搜索物品列表 * 搜索物品列表
*/ */
@GET//("pad/goodsInfoList") @POST//("pad/goodsInfoList")
suspend fun searchGoodsInfoList( suspend fun searchGoodsInfoList(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsInfoList", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsInfoList",
@Query("goodsName") goodsName: String, @Body param:Map<String, String>
@Query("pageNo") pageNo: Int, // @Query("goodsName") goodsName: String,
@Query("pageSize") pageSize: Int, // @Query("pageNum" ) pageNo: Int,
@Header("x-access-token") token: String = GlobalData.appToken // @Query("pageSize" ) pageSize: Int,
): ApiResponse<SearchGoodsInfo> ): ApiResponse<SearchGoodsInfo>
/** /**
@@ -158,9 +164,8 @@ interface ApiService {
*/ */
@POST//("pad/goodsAdd") @POST//("pad/goodsAdd")
suspend fun selfPurchaseGoodsAdd( suspend fun selfPurchaseGoodsAdd(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsAdd", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAdd",
@Body goodsAddParam: GoodsAddParam, @Body goodsAddParam: GoodsAddParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<SearchGoodsInfo> ): ApiResponse<SearchGoodsInfo>
/** /**
@@ -168,9 +173,8 @@ interface ApiService {
*/ */
@POST//("pad/goodsAddUnit") @POST//("pad/goodsAddUnit")
suspend fun goodsAddUnit( suspend fun goodsAddUnit(
@Url url: String = "${GlobalData.appBaseUrl}/pad/goodsAddUnit", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/goodsAddUnit",
@Body purchaseUnitParam: GoodsPurchaseUnitParam, @Body purchaseUnitParam: GoodsPurchaseUnitParam,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean> ): ApiResponse<Boolean>
/** /**
@@ -178,9 +182,8 @@ interface ApiService {
*/ */
@POST//("pad/SelfPurchasedGoods") @POST//("pad/SelfPurchasedGoods")
suspend fun selfPurchaseWarehousing( suspend fun selfPurchaseWarehousing(
@Url url: String = "${GlobalData.appBaseUrl}/pad/SelfPurchasedGoods", @Url url: String = "${GlobalData.appBaseUrl}${apiPrefix}/pad/selfPurchasedGoods",
@Body list: List<PurchaseWarehouseParam>, @Body list: List<PurchaseWarehouseParam>,
@Header("x-access-token") token: String = GlobalData.appToken
): ApiResponse<Boolean> ): ApiResponse<Boolean>
} }
@@ -17,6 +17,8 @@ class RequestInterceptor : Interceptor {
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Accept", "application/json") .header("Accept", "application/json")
.header("deviceId", GlobalData.deviceId) .header("deviceId", GlobalData.deviceId)
.header("X-DEVICE-CODE", GlobalData.deviceId)
.header("x-access-token", GlobalData.appToken)
// .header("Authorization", "Bearer ${getToken()}") // .header("Authorization", "Bearer ${getToken()}")
// .header("x-access-token", 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.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.sw.inbound.InitActivity import com.sw.inbound.MainActivity
import timber.log.Timber import timber.log.Timber
/** /**
@@ -14,7 +14,7 @@ class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) { if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
Timber.d("设备启动完成,开始执行自启动逻辑") Timber.d("设备启动完成,开始执行自启动逻辑")
val intent = Intent(context, InitActivity::class.java) val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent) context.startActivity(intent)
} }
@@ -25,31 +25,31 @@ abstract class BaseRepository {
// } else { // } else {
// "HTTP Error: ${e.code()} - ${e.message()}" // "HTTP Error: ${e.code()} - ${e.message()}"
// } // }
ApiResponse(code = e.code(), message = e.message()) ApiResponse(code = "${e.code()}", msg = e.message())
} }
is SocketTimeoutException -> { is SocketTimeoutException -> {
ApiResponse(code = -2, message = "请求超时: ${e.message}") ApiResponse(code = "-2", msg = "请求超时: ${e.message}")
} }
is ConnectException -> { is ConnectException -> {
ApiResponse(code = -3, message = "连接失败: ${e.message}") ApiResponse(code = "-3", msg = "连接失败: ${e.message}")
} }
is SSLHandshakeException -> { is SSLHandshakeException -> {
ApiResponse(code = -4, message = "SSL握手失败: ${e.message}") ApiResponse(code = "-4", msg = "SSL握手失败: ${e.message}")
} }
is JsonParseException -> { is JsonParseException -> {
ApiResponse(code = -5, message = "JSON解析错误: ${e.message}") ApiResponse(code = "-5", msg = "JSON解析错误: ${e.message}")
} }
is IOException -> { is IOException -> {
ApiResponse(code = -6, message = "网络IO错误: ${e.message}") ApiResponse(code = "-6", msg = "网络IO错误: ${e.message}")
} }
else -> { 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.PurchaseInfo
import com.sw.inbound.model.response.SearchGoodsInfo import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.model.response.StorageType 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.SupplierResponse
import com.sw.inbound.model.response.User import com.sw.inbound.model.response.User
import com.sw.inbound.network.api.ApiService import com.sw.inbound.network.api.ApiService
@@ -56,13 +57,18 @@ class RemoteRepository @Inject constructor(
return safeApiCall { apiService.login(body = loginParam) } 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 { 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 { return safeApiCall {
apiService.getReceiveDetail(id = id) apiService.getReceiveDetail(id = id)
} }
@@ -115,7 +121,7 @@ class RemoteRepository @Inject constructor(
val part = val part =
FileUtils.genRequestPart(context = ContextUtils.getAppContext(), imageUri = uri) FileUtils.genRequestPart(context = ContextUtils.getAppContext(), imageUri = uri)
if (part == null) { if (part == null) {
ApiResponse(code = -1, message = "解析图片失败", result = "") ApiResponse(code = "-1", msg = "解析图片失败")
} else { } else {
apiService.uploadImage(code = codeRequestBody, file = part) apiService.uploadImage(code = codeRequestBody, file = part)
} }
@@ -146,11 +152,12 @@ class RemoteRepository @Inject constructor(
pageSize: Int = 10 pageSize: Int = 10
): ApiResponse<SearchGoodsInfo> { ): ApiResponse<SearchGoodsInfo> {
return safeApiCall { return safeApiCall {
apiService.searchGoodsInfoList( val map = mutableMapOf(
goodsName = goodsName, "goodsName" to goodsName,
pageNo = pageNo, "pageNum" to pageNo.toString(),
pageSize = pageSize "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.HomeScreen
import com.sw.inbound.ui.page.LoginScreen import com.sw.inbound.ui.page.LoginScreen
import com.sw.inbound.ui.page.PurchaseOrderScreen import com.sw.inbound.ui.page.PurchaseOrderScreen
import com.sw.inbound.ui.page.ReceiptProductScreen //import com.sw.inbound.ui.page.ReceiptProductScreen
import com.sw.inbound.ui.page.SelfProcurementScreen //import com.sw.inbound.ui.page.SelfProcurementScreen
import com.sw.inbound.ui.page.TestScreen //import com.sw.inbound.ui.page.TestScreen
import com.sw.inbound.ui.weight.GlobalLoading import com.sw.inbound.ui.weight.GlobalLoading
import com.sw.inbound.utils.SPUtil import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ToastUtils import com.sw.inbound.utils.ToastUtils
@@ -107,11 +107,12 @@ private fun NavHost(
.fillMaxSize() .fillMaxSize()
.padding(padding), .padding(padding),
navController = navController, 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) { // composable(Screen.Test.route) {
TestScreen(modifier = Modifier, navController) // TestScreen(modifier = Modifier, navController)
} // }
// 首页 // 首页
composable(Screen.Home.route) { composable(Screen.Home.route) {
HomeScreen(modifier = Modifier, navController, onBackRequest = onBackRequest) HomeScreen(modifier = Modifier, navController, onBackRequest = onBackRequest)
@@ -128,28 +129,28 @@ private fun NavHost(
) { ) {
PurchaseOrderScreen(modifier = Modifier.fillMaxSize(), navController) PurchaseOrderScreen(modifier = Modifier.fillMaxSize(), navController)
} }
// 自采单 // // 自采单
composable( // composable(
Screen.SelfProcurement.route, // Screen.SelfProcurement.route,
enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画 // enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
exitTransition = { fadeOut(animationSpec = tween(0)) } // 无退出动画 // exitTransition = { fadeOut(animationSpec = tween(0)) } // 无退出动画
) { // ) {
SelfProcurementScreen(modifier = Modifier, navController) // SelfProcurementScreen(modifier = Modifier, navController)
} // }
// 收货 // // 收货
composable( // composable(
Screen.ReceiptProduct.route, // Screen.ReceiptProduct.route,
enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画 // enterTransition = { fadeIn(animationSpec = tween(0)) }, // 无进入动画
exitTransition = { fadeOut(animationSpec = tween(0)) }, // 无退出动画 // exitTransition = { fadeOut(animationSpec = tween(0)) }, // 无退出动画
arguments = listOf( // arguments = listOf(
navArgument(name = "id", builder = { type = NavType.IntType }), // navArgument(name = "id", builder = { type = NavType.IntType }),
navArgument(name = "supplierId", builder = { type = NavType.IntType }) // navArgument(name = "supplierId", builder = { type = NavType.IntType })
) // )
) { backStackEntry -> // ) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: 0 // val id = backStackEntry.arguments?.getString("id") ?: ""
val supplierId = backStackEntry.arguments?.getInt("supplierId") ?: 0 // val supplierId = backStackEntry.arguments?.getString("supplierId") ?: ""
ReceiptProductScreen(modifier = Modifier, navController, id, 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 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}") { // data object ReceiptProduct : Screen("receipt_product?id={id}&supplierId={supplierId}") {
fun createRoute(id: Int, supplierId: Int) = // fun createRoute(id: Int, supplierId: Int) =
"receipt_product?id=${id}&supplierId=${supplierId}" // "receipt_product?id=${id}&supplierId=${supplierId}"
} // }
// 添加物品 // 添加物品
data object AddProduct : Screen("addProduct") // data object AddProduct : Screen("addProduct")
data object Test : Screen("Test") // data object Test : Screen("Test")
} }
@@ -23,11 +23,13 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.sw.inbound.R 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.Screen
import com.sw.inbound.ui.weight.TopTitleBar import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.viewmodel.UserViewModel import com.sw.inbound.viewmodel.UserViewModel
import timber.log.Timber import timber.log.Timber
@@ -78,6 +80,11 @@ fun HomeScreen(
indication = null indication = null
) { ) {
navController.navigate(Screen.PurchaseOrder.route) 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), painter = painterResource(R.mipmap.ic_order_purchase),
contentDescription = "采购单入库" contentDescription = "采购单入库"
@@ -91,14 +98,19 @@ fun HomeScreen(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = null indication = null
) { ) {
navController.navigate( // navController.navigate(
Screen.SelfProcurement.route, navOptions = NavOptions.Builder() // Screen.SelfProcurement.route, navOptions = NavOptions.Builder()
.setEnterAnim(0) // .setEnterAnim(0)
.setExitAnim(0) // .setExitAnim(0)
.setPopEnterAnim(0) // .setPopEnterAnim(0)
.setPopExitAnim(0) // .setPopExitAnim(0)
.build() // .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), painter = painterResource(R.mipmap.ic_order_self_procurement),
contentDescription = "自采入库" contentDescription = "自采入库"
@@ -49,7 +49,6 @@ import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.weight.CustomButton import com.sw.inbound.ui.weight.CustomButton
import com.sw.inbound.utils.QRCodeUtil import com.sw.inbound.utils.QRCodeUtil
import com.sw.inbound.utils.SPUtil import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.viewmodel.UserViewModel import com.sw.inbound.viewmodel.UserViewModel
import timber.log.Timber import timber.log.Timber
@@ -120,12 +119,17 @@ fun LoginScreen(
.height(120.dp), .height(120.dp),
text = "登录", text = "登录",
onClick = { onClick = {
if (username.isEmpty() || password.isEmpty()) { //if (username.isEmpty() || password.isEmpty()) {
ToastUtils.showToast("用户名或密码不能为空") // ToastUtils.showToast("用户名或密码不能为空")
return@CustomButton // return@CustomButton
} //}
viewModel.login(username, password) 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), borderColor = colorResource(R.color.blue),
textColor = colorResource(R.color.white), textColor = colorResource(R.color.white),
@@ -51,14 +51,17 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.sw.inbound.R 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.dashedBorder
import com.sw.inbound.ext.toFormattedString import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.model.response.SupplierInfo 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.blackTextStyle
import com.sw.inbound.ui.theme.AppTypography.grayTextStyle import com.sw.inbound.ui.theme.AppTypography.grayTextStyle
import com.sw.inbound.ui.weight.BottomActionBar import com.sw.inbound.ui.weight.BottomActionBar
import com.sw.inbound.ui.weight.TopTitleBar import com.sw.inbound.ui.weight.TopTitleBar
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.viewmodel.PurchaseOrderViewModel import com.sw.inbound.viewmodel.PurchaseOrderViewModel
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@@ -148,14 +151,20 @@ fun PurchaseOrderScreen(
contentPadding = PaddingValues(16.dp), contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(30.dp) horizontalArrangement = Arrangement.spacedBy(30.dp)
) { ) {
items(items = products, key = { it!!.id }) { items(items = products, key = { it!!.id?:"" }) {
PurchaseOrderItem(it!!) { PurchaseOrderItem(it!!) {
navController.navigate( // navController.navigate(
Screen.ReceiptProduct.createRoute( // Screen.ReceiptProduct.createRoute(
it.id, // it.id,
it.supplierId // 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 = { modifier = Modifier, onLeftButtonClick = {
navController.popBackStack() navController.popBackStack()
}, onRight2ButtonClick = { }, 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( Text(
if (product.receiveStatus == 4) "部分收货" else "收货", 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 //package com.sw.inbound.ui.page
//
//
import android.annotation.SuppressLint //import android.annotation.SuppressLint
import androidx.compose.runtime.Composable //import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier //import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController //import androidx.navigation.NavHostController
//
//
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") //@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable //@Composable
fun TestScreen(modifier: Modifier.Companion, navController: NavHostController) { //fun TestScreen(modifier: Modifier.Companion, navController: NavHostController) {
//
} //}
//
@@ -1,113 +1,113 @@
package com.sw.inbound.ui.weight //package com.sw.inbound.ui.weight
//
import androidx.compose.foundation.background //import androidx.compose.foundation.background
import androidx.compose.foundation.border //import androidx.compose.foundation.border
import androidx.compose.foundation.layout.fillMaxWidth //import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape //import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenuItem //import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api //import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox //import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults //import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.LocalTextStyle //import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable //import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
import androidx.compose.material3.Text //import androidx.compose.material3.Text
import androidx.compose.material3.TextField //import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable //import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue //import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf //import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember //import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue //import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier //import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color //import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource //import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle //import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight //import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign //import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp //import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp //import androidx.compose.ui.unit.sp
import com.sw.inbound.R //import com.sw.inbound.R
import com.sw.inbound.model.response.DictType //import com.sw.inbound.model.response.DictType
import com.sw.inbound.ui.theme.AppTypography //import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.ui.theme.Black_141428 //import com.sw.inbound.ui.theme.Black_141428
//
/** ///**
* 表单中的下拉菜单 // * 表单中的下拉菜单
*/ // */
@OptIn(ExperimentalMaterial3Api::class) //@OptIn(ExperimentalMaterial3Api::class)
@Composable //@Composable
fun CustomDropdownTextField( //fun CustomDropdownTextField(
value: String, // value: String,
onValueChange: (String) -> Unit, // onValueChange: (String) -> Unit,
dropdownItems: List<DictType>, // dropdownItems: List<DictType>,
modifier: Modifier = Modifier, // modifier: Modifier = Modifier,
placeholderValue: String = "请选择", // placeholderValue: String = "请选择",
textAlign: TextAlign = TextAlign.Start, // textAlign: TextAlign = TextAlign.Start,
textStyle: TextStyle? = null, // textStyle: TextStyle? = null,
enabled: Boolean = true, // enabled: Boolean = true,
) { //) {
var expanded by remember { mutableStateOf(false) } // var expanded by remember { mutableStateOf(false) }
var newTextStyle = textStyle // var newTextStyle = textStyle
?: LocalTextStyle.current.copy( // ?: LocalTextStyle.current.copy(
color = Black_141428, // color = Black_141428,
fontSize = 24.sp, // fontSize = 24.sp,
fontWeight = FontWeight.Bold, // fontWeight = FontWeight.Bold,
textAlign = textAlign // textAlign = textAlign
) // )
//
ExposedDropdownMenuBox( // ExposedDropdownMenuBox(
modifier = modifier, // modifier = modifier,
expanded = expanded || !enabled, // expanded = expanded || !enabled,
onExpandedChange = { expanded = it }, // onExpandedChange = { expanded = it },
) { // ) {
TextField( // TextField(
value = value, // value = value,
onValueChange = onValueChange, // onValueChange = onValueChange,
readOnly = true, // readOnly = true,
textStyle = newTextStyle, // textStyle = newTextStyle,
//
shape = RoundedCornerShape(10.dp), // shape = RoundedCornerShape(10.dp),
trailingIcon = { // trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) // ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
}, // },
colors = ExposedDropdownMenuDefaults.textFieldColors( // colors = ExposedDropdownMenuDefaults.textFieldColors(
focusedContainerColor = Color.Transparent, // focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent, // unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent, // disabledContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent, // focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent // unfocusedIndicatorColor = Color.Transparent
), // ),
placeholder = { // placeholder = {
Text( // Text(
modifier = modifier.fillMaxWidth(), // modifier = modifier.fillMaxWidth(),
text = placeholderValue, style = AppTypography.gray96a0aaTextStyle.copy( // text = placeholderValue, style = AppTypography.gray96a0aaTextStyle.copy(
textAlign = textAlign // textAlign = textAlign
) // )
) // )
}, // },
modifier = Modifier // modifier = Modifier
.fillMaxWidth() // .fillMaxWidth()
.background(Color.Transparent) // .background(Color.Transparent)
.border( // .border(
width = 2.dp, // width = 2.dp,
color = colorResource(R.color.border_line), // color = colorResource(R.color.border_line),
shape = RoundedCornerShape(10.dp) // shape = RoundedCornerShape(10.dp)
) // )
.menuAnchor(PrimaryNotEditable, true) // .menuAnchor(PrimaryNotEditable, true)
) // )
//
ExposedDropdownMenu( // ExposedDropdownMenu(
expanded = expanded, // expanded = expanded,
onDismissRequest = { expanded = false } // onDismissRequest = { expanded = false }
) { // ) {
dropdownItems.forEach { item -> // dropdownItems.forEach { item ->
DropdownMenuItem( // DropdownMenuItem(
text = { Text(text = item.value, style = AppTypography.black141428TextStyle) }, // text = { Text(text = item.value?:"", style = AppTypography.black141428TextStyle) },
onClick = { // onClick = {
onValueChange(item.value) // onValueChange(item.value?:"")
expanded = false // expanded = false
} // }
) // )
} // }
} // }
} // }
} //}
@@ -1,106 +1,106 @@
package com.sw.inbound.ui.weight //package com.sw.inbound.ui.weight
//
import androidx.compose.foundation.background //import androidx.compose.foundation.background
import androidx.compose.foundation.shape.RoundedCornerShape //import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenuItem //import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api //import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox //import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults //import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable //import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
import androidx.compose.material3.Text //import androidx.compose.material3.Text
import androidx.compose.material3.TextField //import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable //import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue //import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf //import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember //import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue //import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier //import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color //import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource //import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle //import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight //import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp //import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp //import androidx.compose.ui.unit.sp
import com.sw.inbound.R //import com.sw.inbound.R
import com.sw.inbound.model.response.DictType //import com.sw.inbound.model.response.DictType
//
/** ///**
* 自定义顶部仓库下拉 // * 自定义顶部仓库下拉
*/ // */
@OptIn(ExperimentalMaterial3Api::class) //@OptIn(ExperimentalMaterial3Api::class)
@Composable //@Composable
fun CustomSpinner( //fun CustomSpinner(
items: List<DictType>, // items: List<DictType>,
selectedItem: String, // selectedItem: String,
onItemSelected: (DictType) -> Unit, // onItemSelected: (DictType) -> Unit,
modifier: Modifier = Modifier, // modifier: Modifier = Modifier,
) { //) {
// var expanded by remember { mutableStateOf(false) } //// var expanded by remember { mutableStateOf(false) }
var expanded by remember { mutableStateOf(true) } // var expanded by remember { mutableStateOf(true) }
//
ExposedDropdownMenuBox( // ExposedDropdownMenuBox(
expanded = expanded, // expanded = expanded,
onExpandedChange = { expanded = !expanded }, // onExpandedChange = { expanded = !expanded },
modifier = modifier.background( // modifier = modifier.background(
color = Color(0x80FFFFFF), // color = Color(0x80FFFFFF),
shape = RoundedCornerShape(10.dp) // 圆角背景 // shape = RoundedCornerShape(10.dp) // 圆角背景
) // )
) { // ) {
TextField( // TextField(
value = selectedItem, // value = selectedItem,
onValueChange = {}, // onValueChange = {},
readOnly = true, // readOnly = true,
textStyle = TextStyle( // textStyle = TextStyle(
color = Color.White, // color = Color.White,
fontSize = 24.sp, // fontSize = 24.sp,
fontWeight = FontWeight.Bold // fontWeight = FontWeight.Bold
), // ),
shape = RoundedCornerShape(10.dp), // shape = RoundedCornerShape(10.dp),
trailingIcon = { // trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) // ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
}, // },
colors = ExposedDropdownMenuDefaults.textFieldColors( // colors = ExposedDropdownMenuDefaults.textFieldColors(
focusedContainerColor = colorResource(R.color.blue), // focusedContainerColor = colorResource(R.color.blue),
unfocusedContainerColor = colorResource(R.color.blue), // unfocusedContainerColor = colorResource(R.color.blue),
disabledContainerColor = colorResource(R.color.blue), // disabledContainerColor = colorResource(R.color.blue),
focusedTextColor = Color.White, // focusedTextColor = Color.White,
unfocusedTextColor = Color.White, // unfocusedTextColor = Color.White,
cursorColor = Color.White, // cursorColor = Color.White,
focusedIndicatorColor = Color.Transparent, // focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent, // unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.White.copy(alpha = 0.8f), // focusedLabelColor = Color.White.copy(alpha = 0.8f),
unfocusedLabelColor = Color.White.copy(alpha = 0.8f), // unfocusedLabelColor = Color.White.copy(alpha = 0.8f),
focusedTrailingIconColor = Color.White, // focusedTrailingIconColor = Color.White,
unfocusedTrailingIconColor = Color.White // unfocusedTrailingIconColor = Color.White
), // ),
modifier = Modifier.menuAnchor(PrimaryNotEditable, true) // modifier = Modifier.menuAnchor(PrimaryNotEditable, true)
) // )
//
ExposedDropdownMenu( // ExposedDropdownMenu(
expanded = expanded, // expanded = expanded,
onDismissRequest = { expanded = false }, // onDismissRequest = { expanded = false },
modifier = Modifier // modifier = Modifier
.background(colorResource(R.color.blue)) // .background(colorResource(R.color.blue))
.exposedDropdownSize(matchTextFieldWidth = true) // .exposedDropdownSize(matchTextFieldWidth = true)
) { // ) {
items.forEach { item -> // items.forEach { item ->
DropdownMenuItem( // DropdownMenuItem(
text = { // text = {
Text( // Text(
text = item.value, // text = item.value?:"",
style = TextStyle( // style = TextStyle(
color = Color.White, // color = Color.White,
fontSize = 24.sp, // fontSize = 24.sp,
fontWeight = FontWeight.Bold // fontWeight = FontWeight.Bold
), // ),
) // )
}, // },
onClick = { // onClick = {
onItemSelected(item) // onItemSelected(item)
expanded = false // expanded = false
} // }
) // )
} // }
} // }
} // }
} //}
@@ -1,216 +1,216 @@
package com.sw.inbound.ui.weight //package com.sw.inbound.ui.weight
//
import android.widget.Toast //import android.widget.Toast
import androidx.camera.view.CameraController //import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController //import androidx.camera.view.LifecycleCameraController
import androidx.compose.foundation.layout.Column //import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer //import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize //import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height //import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width //import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable //import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect //import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect //import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState //import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue //import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf //import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableIntStateOf //import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf //import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember //import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue //import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment //import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier //import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext //import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp //import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat //import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.LocalLifecycleOwner //import androidx.lifecycle.compose.LocalLifecycleOwner
import com.sw.inbound.ext.medium //import com.sw.inbound.ext.medium
import com.sw.inbound.model.request.PurchaseWarehouseParam //import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.SearchGoodsInfo //import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.ui.theme.AppTypography //import com.sw.inbound.ui.theme.AppTypography
import com.sw.inbound.utils.InteractionUtils.Debouncer //import com.sw.inbound.utils.InteractionUtils.Debouncer
import com.sw.inbound.utils.rememberPhotoCapture //import com.sw.inbound.utils.rememberPhotoCapture
import com.sw.inbound.viewmodel.BaseViewModel //import com.sw.inbound.viewmodel.BaseViewModel
import com.sw.inbound.viewmodel.ReceiptViewModel //import com.sw.inbound.viewmodel.ReceiptViewModel
import com.sw.inbound.viewmodel.SelfProcurementViewModel //import com.sw.inbound.viewmodel.SelfProcurementViewModel
import timber.log.Timber //import timber.log.Timber
//
enum class PageType { //enum class PageType {
/** // /**
* 自采 // * 自采
*/ // */
SELF_PROCUREMENT, // SELF_PROCUREMENT,
//
/** // /**
* 收货 // * 收货
*/ // */
RECEIPT_PRODUCT // RECEIPT_PRODUCT
} //}
//
/** ///**
* 菜品识别组件 // * 菜品识别组件
*/ // */
@Composable //@Composable
fun IdentityView( //fun IdentityView(
showSearchView: Boolean = false, // showSearchView: Boolean = false,
onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {}, // onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {},
checkedItem: PurchaseWarehouseParam? = null, // checkedItem: PurchaseWarehouseParam? = null,
baseViewModel: BaseViewModel, // baseViewModel: BaseViewModel,
pageType: PageType // pageType: PageType
) { //) {
val context = LocalContext.current // val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current // val lifecycleOwner = LocalLifecycleOwner.current
val weightInfo by baseViewModel.weightInfo.collectAsState() // val weightInfo by baseViewModel.weightInfo.collectAsState()
val identityList by baseViewModel.identityListItems.collectAsState() // val identityList by baseViewModel.identityListItems.collectAsState()
val receiptList by baseViewModel.receiptList.collectAsState() // val receiptList by baseViewModel.receiptList.collectAsState()
val searchList by baseViewModel.searchListItems.collectAsState() // val searchList by baseViewModel.searchListItems.collectAsState()
// var lastWeight by remember { mutableStateOf<Double?>(null) } //// var lastWeight by remember { mutableStateOf<Double?>(null) }
var lastWeight by remember { mutableDoubleStateOf(0.0) } // var lastWeight by remember { mutableDoubleStateOf(0.0) }
val lastPhotoUri by baseViewModel.lastPhotoUri.collectAsState() // val lastPhotoUri by baseViewModel.lastPhotoUri.collectAsState()
var pageNum by remember { mutableIntStateOf(1) } // var pageNum by remember { mutableIntStateOf(1) }
val isMoreLoading by baseViewModel.isMoreLoading.collectAsState() // val isMoreLoading by baseViewModel.isMoreLoading.collectAsState()
val canLoadMore by baseViewModel.canLoadMore.collectAsState() // val canLoadMore by baseViewModel.canLoadMore.collectAsState()
var list = if (identityList.isNotEmpty()) { // var list = if (identityList.isNotEmpty()) {
identityList // identityList
} else { // } else {
searchList // searchList
} // }
val debouncer = remember { Debouncer(2000) } // val debouncer = remember { Debouncer(2000) }
var isCameraReady by remember { mutableStateOf(false) } // var isCameraReady by remember { mutableStateOf(false) }
//
// CameraX 控制器 // // CameraX 控制器
val cameraController = remember { // val cameraController = remember {
LifecycleCameraController(context).apply { // LifecycleCameraController(context).apply {
// 必须设置有效的用例 // // 必须设置有效的用例
setEnabledUseCases( // setEnabledUseCases(
CameraController.IMAGE_CAPTURE or // CameraController.IMAGE_CAPTURE or
CameraController.VIDEO_CAPTURE // CameraController.VIDEO_CAPTURE
) // )
} // }
} // }
//
// 需要搜索的信息 // // 需要搜索的信息
var searchInfo by remember { mutableStateOf("") } // var searchInfo by remember { mutableStateOf("") }
// 创建拍照工具实例 // // 创建拍照工具实例
val (photoCaptureHelper, takePhoto) = rememberPhotoCapture( // val (photoCaptureHelper, takePhoto) = rememberPhotoCapture(
cameraController = cameraController, // cameraController = cameraController,
onSuccess = { savedUri -> // onSuccess = { savedUri ->
// 处理拍照成功的逻辑 // // 处理拍照成功的逻辑
baseViewModel.updateLastPhotoUri(savedUri) // baseViewModel.updateLastPhotoUri(savedUri)
Timber.d("photoUri = $savedUri") // Timber.d("photoUri = $savedUri")
if (pageType == PageType.SELF_PROCUREMENT) { // if (pageType == PageType.SELF_PROCUREMENT) {
(baseViewModel as SelfProcurementViewModel).updateSelectedItem(null) // (baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
} else if (pageType == PageType.RECEIPT_PRODUCT) { // } else if (pageType == PageType.RECEIPT_PRODUCT) {
(baseViewModel as ReceiptViewModel).updateSelectedItem(null) // (baseViewModel as ReceiptViewModel).updateSelectedItem(null)
} // }
baseViewModel.getIdentityList(savedUri) // baseViewModel.getIdentityList(savedUri)
}, // },
onError = { error -> // onError = { error ->
// 处理拍照失败的逻辑 // // 处理拍照失败的逻辑
Toast.makeText(context, error, Toast.LENGTH_SHORT).show() // Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
baseViewModel.updateLastPhotoUri(null) // baseViewModel.updateLastPhotoUri(null)
} // }
) // )
//
// 绑定生命周期 // // 绑定生命周期
DisposableEffect(lifecycleOwner) { // DisposableEffect(lifecycleOwner) {
cameraController.bindToLifecycle(lifecycleOwner) // cameraController.bindToLifecycle(lifecycleOwner)
onDispose { // onDispose {
cameraController.unbind() // cameraController.unbind()
isCameraReady = false // isCameraReady = false
} // }
} // }
//
LaunchedEffect(weightInfo) { // LaunchedEffect(weightInfo) {
Timber.d("LaunchedEffect weightInfo1 = $weightInfo, lastWeight = $lastWeight") // Timber.d("LaunchedEffect weightInfo1 = $weightInfo, lastWeight = $lastWeight")
if (weightInfo - lastWeight > 1.0) { // if (weightInfo - lastWeight > 1.0) {
Timber.d("LaunchedEffect pageType = $pageType, receiptList = ${receiptList.size}") // Timber.d("LaunchedEffect pageType = $pageType, receiptList = ${receiptList.size}")
var canIdentity = false // var canIdentity = false
if (pageType == PageType.RECEIPT_PRODUCT) { // if (pageType == PageType.RECEIPT_PRODUCT) {
val selectItem = (baseViewModel as ReceiptViewModel).selectedItem.value // val selectItem = (baseViewModel as ReceiptViewModel).selectedItem.value
canIdentity = // canIdentity =
receiptList.isNotEmpty() && (selectItem == null || selectItem.goodId == 0) // receiptList.isNotEmpty() && (selectItem == null || selectItem.goodId.isNullOrBlank())
} else if (pageType == PageType.SELF_PROCUREMENT) { // } else if (pageType == PageType.SELF_PROCUREMENT) {
val selectItem = (baseViewModel as SelfProcurementViewModel).selectedItem.value // val selectItem = (baseViewModel as SelfProcurementViewModel).selectedItem.value
canIdentity = selectItem == null || selectItem.goodsId == 0 // canIdentity = selectItem == null || selectItem.goodsId.isNullOrBlank()
} // }
Timber.d("LaunchedEffect canIdentity = $canIdentity") // Timber.d("LaunchedEffect canIdentity = $canIdentity")
if (canIdentity) { // if (canIdentity) {
debouncer.debounce { // debouncer.debounce {
Timber.d("LaunchedEffect isCameraReady = $isCameraReady") // Timber.d("LaunchedEffect isCameraReady = $isCameraReady")
if (isCameraReady) { // if (isCameraReady) {
takePhoto() // takePhoto()
} // }
} // }
} // }
} // }
lastWeight = weightInfo // lastWeight = weightInfo
} // }
//
// 监听相机初始化 // // 监听相机初始化
LaunchedEffect(Unit) { // LaunchedEffect(Unit) {
try { // try {
cameraController.initializationFuture.addListener({ // cameraController.initializationFuture.addListener({
isCameraReady = true // isCameraReady = true
Timber.d("Camera initialized successfully") // Timber.d("Camera initialized successfully")
}, ContextCompat.getMainExecutor(context)) // }, ContextCompat.getMainExecutor(context))
} catch (e: Exception) { // } catch (e: Exception) {
Timber.d("Camera initialized error = ${e.message}") // Timber.d("Camera initialized error = ${e.message}")
} // }
} // }
//
Column( // Column(
modifier = Modifier // modifier = Modifier
.fillMaxSize(), // .fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally // horizontalAlignment = Alignment.CenterHorizontally
) { // ) {
CameraPreview( // CameraPreview(
modifier = Modifier // modifier = Modifier
.width(397.dp) // .width(397.dp)
.height(298.dp), // .height(298.dp),
controller = cameraController, // controller = cameraController,
photoUri = lastPhotoUri // photoUri = lastPhotoUri
) // )
if (showSearchView) { // if (showSearchView) {
Spacer(modifier = Modifier.height(30.dp)) // Spacer(modifier = Modifier.height(30.dp))
CustomSearchView(onSearchClick = { // CustomSearchView(onSearchClick = {
if (pageType == PageType.SELF_PROCUREMENT) { // if (pageType == PageType.SELF_PROCUREMENT) {
(baseViewModel as SelfProcurementViewModel).updateSelectedItem(null) // (baseViewModel as SelfProcurementViewModel).updateSelectedItem(null)
} // }
searchInfo = it // searchInfo = it
baseViewModel.searchGoodsInfoList(it) // baseViewModel.searchGoodsInfoList(it)
}) // })
} // }
Spacer(modifier = Modifier.height(30.dp)) // Spacer(modifier = Modifier.height(30.dp))
if (showSearchView) { // if (showSearchView) {
SingleSelectButtonGroup( // SingleSelectButtonGroup(
modifier = Modifier // modifier = Modifier
.height(64.dp) // .height(64.dp)
.width(192.dp), options = list, // .width(192.dp), options = list,
onOptionSelected = onOptionSelected, // onOptionSelected = onOptionSelected,
onLoadMore = { // onLoadMore = {
Timber.d("加载更多 canLoadMore = $canLoadMore") // Timber.d("加载更多 canLoadMore = $canLoadMore")
if (!canLoadMore) { // if (!canLoadMore) {
return@SingleSelectButtonGroup // return@SingleSelectButtonGroup
} // }
pageNum++ // pageNum++
baseViewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum) // baseViewModel.searchGoodsInfoList(goodsName = searchInfo, pageNo = pageNum)
}, // },
checkedItem = list.find { it.goodsId == checkedItem?.goodsId }, // checkedItem = list.find { it.goodsId == checkedItem?.goodsId },
isMoreLoading = isMoreLoading, // isMoreLoading = isMoreLoading,
canLoadMore = canLoadMore // canLoadMore = canLoadMore
) // )
} else { // } else {
SingleSelectButtonGroup( // SingleSelectButtonGroup(
modifier = Modifier // modifier = Modifier
.height(70.dp) // .height(70.dp)
.width(215.dp), // .width(215.dp),
options = list, // options = list,
horizontalSpacing = 30.dp, // horizontalSpacing = 30.dp,
verticalSpacing = 20.dp, // verticalSpacing = 20.dp,
onOptionSelected = onOptionSelected, // onOptionSelected = onOptionSelected,
unSelectedTextStyle = AppTypography.blackTextStyle.medium() // unSelectedTextStyle = AppTypography.blackTextStyle.medium()
) // )
} // }
} // }
} //}
@@ -1,83 +1,83 @@
package com.sw.inbound.ui.weight //package com.sw.inbound.ui.weight
//
import androidx.compose.foundation.Image //import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable //import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement //import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row //import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer //import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth //import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height //import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding //import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width //import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardActions //import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions //import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text //import androidx.compose.material3.Text
import androidx.compose.runtime.Composable //import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment //import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier //import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource //import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign //import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp //import androidx.compose.ui.unit.dp
import com.sw.inbound.R //import com.sw.inbound.R
import com.sw.inbound.model.response.DictType //import com.sw.inbound.model.response.DictType
import com.sw.inbound.ui.theme.AppTypography //import com.sw.inbound.ui.theme.AppTypography
//
/** ///**
* 横向输入框 包含左侧文件+右侧输入框 // * 横向输入框 包含左侧文件+右侧输入框
*/ // */
@Composable //@Composable
fun RowInputLayout( //fun RowInputLayout(
label: String, // 左侧文字 // label: String, // 左侧文字
value: String, // value: String,
onValueChange: (String) -> Unit, // onValueChange: (String) -> Unit,
dropdownItems: List<DictType>? = null, // 下拉列表 // dropdownItems: List<DictType>? = null, // 下拉列表
hasNext: Boolean = true, // 键盘显示下一步 // hasNext: Boolean = true, // 键盘显示下一步
inputType: InputType = InputType.Text, // inputType: InputType = InputType.Text,
trailingLabel: String? = null, // 尾部文字 // trailingLabel: String? = null, // 尾部文字
keyboardOptions: KeyboardOptions? = null, // keyboardOptions: KeyboardOptions? = null,
keyboardActions: KeyboardActions? = null, // keyboardActions: KeyboardActions? = null,
isInitUpdate: Boolean = false, // 是否根据原始数据更新 // isInitUpdate: Boolean = false, // 是否根据原始数据更新
showRightButton: Boolean = false, // showRightButton: Boolean = false,
onRightButtonClick: () -> Unit = {}, // onRightButtonClick: () -> Unit = {},
) { //) {
val textWidth = if (showRightButton) 218.dp else 290.dp // val textWidth = if (showRightButton) 218.dp else 290.dp
Row( // Row(
modifier = Modifier // modifier = Modifier
.height(60.dp) // .height(60.dp)
.fillMaxWidth() // .fillMaxWidth()
.padding(horizontal = 30.dp), // .padding(horizontal = 30.dp),
horizontalArrangement = Arrangement.SpaceBetween, // horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically // verticalAlignment = Alignment.CenterVertically
) { // ) {
Text(label, style = AppTypography.black141428TextStyle) // Text(label, style = AppTypography.black141428TextStyle)
// Spacer(modifier = Modifier.width(67.dp)) //// Spacer(modifier = Modifier.width(67.dp))
Spacer(modifier = Modifier.weight(1f)) // Spacer(modifier = Modifier.weight(1f))
if (dropdownItems == null) { // if (dropdownItems == null) {
CustomTextField( // CustomTextField(
modifier = Modifier.width(textWidth), // modifier = Modifier.width(textWidth),
value = value, onValueChange = onValueChange, // value = value, onValueChange = onValueChange,
textAlign = TextAlign.End, // textAlign = TextAlign.End,
trailingLabel = trailingLabel, // trailingLabel = trailingLabel,
hasNext = hasNext, // hasNext = hasNext,
inputType = inputType, // inputType = inputType,
keyboardOptions = keyboardOptions, // keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions, // keyboardActions = keyboardActions,
isInitUpdate = isInitUpdate // isInitUpdate = isInitUpdate
) // )
} else { // } else {
CustomDropdownTextField( // CustomDropdownTextField(
modifier = Modifier.width(textWidth), // modifier = Modifier.width(textWidth),
value = value, // value = value,
dropdownItems = dropdownItems, // dropdownItems = dropdownItems,
onValueChange = onValueChange, // onValueChange = onValueChange,
textAlign = TextAlign.End // textAlign = TextAlign.End
) // )
} // }
if (showRightButton) { // if (showRightButton) {
Spacer(modifier = Modifier.width(12.dp)) // Spacer(modifier = Modifier.width(12.dp))
Image(modifier = Modifier.clickable { // Image(modifier = Modifier.clickable {
onRightButtonClick() // onRightButtonClick()
}, painter = painterResource(R.drawable.ic_add), contentDescription = "添加") // }, painter = painterResource(R.drawable.ic_add), contentDescription = "添加")
} // }
} // }
} //}
@@ -48,7 +48,8 @@ import kotlinx.coroutines.delay
@Composable @Composable
fun TopTitleBar( fun TopTitleBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
title: String = "采购单入库", // title: String = "采购单入库",
title: String = "出入库管理",
user: User? = null, user: User? = null,
onLogoutClick: () -> Unit = {} 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 retrofit2.HttpException
import timber.log.Timber import timber.log.Timber
import java.io.IOException import java.io.IOException
import kotlin.collections.List
abstract class BaseViewModel( abstract class BaseViewModel(
private val repository: RemoteRepository private val repository: RemoteRepository
@@ -94,8 +95,8 @@ abstract class BaseViewModel(
if (response.isSuccess()) { if (response.isSuccess()) {
return true return true
} }
Timber.d("msg = ${response.message}, code = ${response.code}") Timber.d("msg = ${response.msg}, code = ${response.code}")
ToastUtils.showToast("${response.message}(${response.code})") //ToastUtils.showToast("${response.msg}(${response.code})")
return false return false
} }
@@ -182,10 +183,25 @@ abstract class BaseViewModel(
/** /**
* 搜索物品 * 搜索物品
*/ */
fun searchGoodsInfoList(
suspend fun searchGoodsInfoList2(
goodsName: String, goodsName: String,
pageNo: Int = 1, pageNo: Int = 1,
pageSize: Int = 10 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 { launch {
if (pageNo > 1) { if (pageNo > 1) {
@@ -203,9 +219,11 @@ abstract class BaseViewModel(
} else { } else {
_searchListItems.value = data.records _searchListItems.value = data.records
} }
searchCallback?.invoke(pageNo, _searchListItems.value)
} }
} else { } else {
_searchListItems.value = emptyList<SearchGoodsInfo.Record>() _searchListItems.value = emptyList<SearchGoodsInfo.Record>()
searchCallback?.invoke(pageNo, _searchListItems.value)
} }
} }
} }
@@ -217,10 +235,11 @@ abstract class BaseViewModel(
if (parseResponse(response)) { if (parseResponse(response)) {
Timber.d("getGoodsStorageType data = ${response.result}") Timber.d("getGoodsStorageType data = ${response.result}")
response.result?.let { response.result?.let {
// val dictType = DictType(response.data) val list: MutableList<DictType> = mutableListOf()
val list = mutableListOf<DictType>() response.result
for (type in response.result) { ?.filter { it.id.isNullOrBlank().not() && it.title.isNullOrBlank().not() }
list.add(DictType(type.itemValue!!.toInt(), type.itemText!!)) ?.forEach {
list.add(DictType(id = it.id, value = it.title))
} }
GlobalData.storageTypeList = list GlobalData.storageTypeList = list
} }
@@ -230,42 +249,53 @@ abstract class BaseViewModel(
val response1 = repository.getGoodsType() val response1 = repository.getGoodsType()
if (parseResponse(response1)) { if (parseResponse(response1)) {
Timber.d("getGoodsType data = ${response1.result?.allType}") Timber.d("getGoodsType data = ${response1.result?.allType}")
response1.result?.let {
if (response1.result.allType != null) {
val list = mutableListOf<DictType>() val list = mutableListOf<DictType>()
for (type in response1.result.allType) { response1.result
list.add(DictType(type!!.id!!, type.typeName!!)) ?.allType
} ?.filter { it?.id.isNullOrBlank().not() && it.typeName.isNullOrBlank().not() }
GlobalData.goodsTypeList = list ?.forEach {
} list.add(DictType(it!!.id, it.typeName!!))
} }
GlobalData.goodsTypeList = list.toList()
} else { } else {
Timber.e("getGoodsType msg = ${response1.message}, code = ${response1.code}") Timber.e("getGoodsType msg = ${response1.message}, code = ${response1.code}")
} }
val response2 = repository.getDictType(RemoteRepository.TypeEnum.WAREHOUSE) val response2 = repository.getDictType(RemoteRepository.TypeEnum.WAREHOUSE)
if (parseResponse(response2)) { if (parseResponse(response2)) {
Timber.d("getDictType WAREHOUSE data = ${response2.result}") Timber.d("getDictType WAREHOUSE data = ${response2.result}")
response2.result?.let { val list: MutableList<DictType> = mutableListOf()
GlobalData.warehouseTypeList = response2.result 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 { } else {
Timber.e("getDictType WAREHOUSE msg = ${response2.message}, code = ${response2.code}") Timber.e("getDictType WAREHOUSE msg = ${response2.message}, code = ${response2.code}")
} }
val response3 = repository.getDictType(RemoteRepository.TypeEnum.SUPPLIER) val response3 = repository.getDictType(RemoteRepository.TypeEnum.SUPPLIER)
if (parseResponse(response3)) { if (parseResponse(response3)) {
Timber.d("getDictType SUPPLIER data = ${response3.result}") Timber.d("getDictType SUPPLIER data = ${response3.result}")
response3.result?.let { val list: MutableList<DictType> = mutableListOf()
GlobalData.supplierTypeList = response3.result 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 { } else {
Timber.e("getDictType SUPPLIER msg = ${response3.message}, code = ${response3.code}") Timber.e("getDictType SUPPLIER msg = ${response3.message}, code = ${response3.code}")
} }
val response4 = repository.getDictType(RemoteRepository.TypeEnum.UNIT) val response4 = repository.getDictType(RemoteRepository.TypeEnum.UNIT)
if (parseResponse(response4)) { if (parseResponse(response4)) {
Timber.d("getDictType UNIT data = ${response4.result}") Timber.d("getDictType UNIT data = ${response4.result}")
response4.result?.let { val list: MutableList<DictType> = mutableListOf()
GlobalData.unitTypeList = response4.result 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 { } else {
Timber.e("getDictType UNIT msg = ${response4.message}, code = ${response4.code}") Timber.e("getDictType UNIT msg = ${response4.message}, code = ${response4.code}")
} }
@@ -31,7 +31,7 @@ class PurchaseOrderViewModel @Inject constructor(
val response = repository.getReceiveList(pageNum, pageSize) val response = repository.getReceiveList(pageNum, pageSize)
updateMoreLoading(false) updateMoreLoading(false)
if (parseResponse(response)) { if (parseResponse(response)) {
response.result?.records?.let { response.result?.let {
updateCanLoadMore(it.size >= pageSize) updateCanLoadMore(it.size >= pageSize)
Timber.d("加载更多 canLoadMore =${it.size >= pageSize}") Timber.d("加载更多 canLoadMore =${it.size >= pageSize}")
_supplierList.value = _supplierList.value + it _supplierList.value = _supplierList.value + it
@@ -42,7 +42,7 @@ class PurchaseOrderViewModel @Inject constructor(
launchWithLoading { launchWithLoading {
val response = repository.getReceiveList(pageNum, pageSize) val response = repository.getReceiveList(pageNum, pageSize)
if (parseResponse(response)) { if (parseResponse(response)) {
response.result?.records?.let { response.result?.let {
_supplierList.value = it _supplierList.value = it
} }
} }
@@ -5,6 +5,7 @@ import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeBigDecimal import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.ext.toSafeFloat import com.sw.inbound.ext.toSafeFloat
import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.request.UploadInfo import com.sw.inbound.model.request.UploadInfo
import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.GoodsInfo import com.sw.inbound.model.response.GoodsInfo
@@ -99,11 +100,11 @@ class ReceiptViewModel @Inject constructor(
_showReceiptDialog.value = showDialog _showReceiptDialog.value = showDialog
} }
fun updateSelectedItemWithSwitch(purchaseOrder: GoodsInfo?) { // fun updateSelectedItemWithSwitch(purchaseOrder: GoodsInfo?) {
viewModelScope.launch { // viewModelScope.launch {
updateSelectedItem(purchaseOrder) // updateSelectedItem(purchaseOrder)
} // }
} // }
override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) { override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
val firstItem = unadjustedOrders.value.find { order -> val firstItem = unadjustedOrders.value.find { order ->
@@ -118,41 +119,42 @@ class ReceiptViewModel @Inject constructor(
/** /**
* 更新选中的item * 更新选中的item
*/ */
fun updateSelectedItem(purchaseOrder: GoodsInfo?) { // fun updateSelectedItem(purchaseOrder: GoodsInfo?) {
if (purchaseOrder != null) { // if (purchaseOrder != null) {
if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) { // if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) {
if (purchaseOrder.newRecUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入 // if (purchaseOrder.newRecUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
val result = // val result =
purchaseOrder.receivedNum!!.times(purchaseOrder.newRecUnitPriceTaxIn!!) // purchaseOrder.receivedNum!!.times(purchaseOrder.newRecUnitPriceTaxIn!!)
purchaseOrder.recPriceExItem = result.toSafeFloat() // purchaseOrder.recPriceExItem = result.toSafeFloat()
purchaseOrder.recPriceExItemTemp = result.toFormattedString() // purchaseOrder.recPriceExItemTemp = result.toFormattedString()
} else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入 // } else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
val result = // val result =
purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!) // purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!)
purchaseOrder.newRecUnitPriceTaxIn = result.toSafeFloat() // purchaseOrder.newRecUnitPriceTaxIn = result.toSafeFloat()
purchaseOrder.newRecUnitPriceTaxInTemp = result.toFormattedString() // purchaseOrder.newRecUnitPriceTaxInTemp = result.toFormattedString()
} // }
} else { // } else {
if (_priceUserInput.value) { // if (_priceUserInput.value) {
purchaseOrder.recPriceExItem = 0f // purchaseOrder.recPriceExItem = 0f
purchaseOrder.recPriceExItemTemp = "" // purchaseOrder.recPriceExItemTemp = ""
} else if (_amountUserInput.value) { // } else if (_amountUserInput.value) {
purchaseOrder.newRecUnitPriceTaxIn = 0f // purchaseOrder.newRecUnitPriceTaxIn = 0f
purchaseOrder.newRecUnitPriceTaxInTemp = "" // purchaseOrder.newRecUnitPriceTaxInTemp = ""
} // }
} // }
} else { // } else {
_countUserInput.value = false // _countUserInput.value = false
_priceUserInput.value = false // _priceUserInput.value = false
_amountUserInput.value = false // _amountUserInput.value = false
} // }
_selectedItem.value = purchaseOrder // _selectedItem.value = purchaseOrder
} // }
fun getReceiveDetail(id: Int) { fun getReceiveDetail(id: String, action:(PurchaseInfo?)->Unit = {}) {
launchWithLoading { launchWithLoading {
val response = repository.getReceiveDetail(id) val response = repository.getReceiveDetail(id)
if (parseResponse(response)) { if (parseResponse(response)) {
action(response.result)
_currentPurchaseInfo.value = response.result _currentPurchaseInfo.value = response.result
initOrders() initOrders()
} }
@@ -199,23 +201,23 @@ class ReceiptViewModel @Inject constructor(
/** /**
* 更新所有商品仓库 * 更新所有商品仓库
*/ */
fun updateAllPurchaseStore(warehouse: DictType, predicate: (GoodsInfo) -> Boolean = { true }) { // fun updateAllPurchaseStore(warehouse: DictType, predicate: (GoodsInfo) -> Boolean = { true }) {
_orders.update { currentList -> // _orders.update { currentList ->
currentList.map { order -> // currentList.map { order ->
if (predicate(order)) order.copy( // if (predicate(order)) order.copy(
warehouseId = warehouse.id, // warehouseId = warehouse.id,
warehouseName = warehouse.value // warehouseName = warehouse.value
) else order // ) else order
} // }
} // }
} // }
// 删除订单 // 删除订单
fun removePurchaseOrder(orderId: Int) { // fun removePurchaseOrder(orderId: Int) {
_orders.update { current -> // _orders.update { current ->
current.filterNot { it.goodId == orderId } // current.filterNot { it.goodId == orderId }
} // }
} // }
// 清空列表 // 清空列表
fun clearPurchaseOrders() { fun clearPurchaseOrders() {
@@ -243,67 +245,72 @@ class ReceiptViewModel @Inject constructor(
_amountUserInput.value = boolean _amountUserInput.value = boolean
} }
private var weightCallback:((Int)->Unit)?=null
fun readWeight(callback:(Int)->Unit) {
weightCallback = callback
}
override fun handleSensorScale(weight: Double) { override fun handleSensorScale(weight: Double) {
val currentItem = _selectedItem.value weightCallback?.invoke((weight*1000).toInt())
// val currentItem = _selectedItem.value
currentItem?.let { info -> //
// 用户输入数量后不再通过重量反算 // currentItem?.let { info ->
if (_countUserInput.value) { // // 用户输入数量后不再通过重量反算
_selectedItem.value = info.copy( // if (_countUserInput.value) {
goodsWeight = weight.toSafeBigDecimal(), // _selectedItem.value = info.copy(
) // goodsWeight = weight.toSafeBigDecimal(),
return // )
} // return
var consumeValue = currentItem.consumeValue?.toSafeDouble() ?: 1.0 // }
var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0 // var consumeValue = currentItem.consumeValue?.toSafeDouble() ?: 1.0
if (consumeValue == 0.0) { // var purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0
consumeValue = 1.0 // if (consumeValue == 0.0) {
} // consumeValue = 1.0
if (purchaseValue == 0.0) { // }
purchaseValue = 1.0 // if (purchaseValue == 0.0) {
} // purchaseValue = 1.0
val count = // }
weight * 1000 / consumeValue / purchaseValue // val count =
val finalCount = count.toSafeFloat(currentItem.unitName) // weight * 1000 / consumeValue / purchaseValue
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $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 -> { // val finalPrice = when {
0f // finalCount == 0f -> {
} // 0f
// }
_amountUserInput.value && !_priceUserInput.value -> { //
info.recPriceExItem!!.div(finalCount).toSafeFloat() // _amountUserInput.value && !_priceUserInput.value -> {
} // info.recPriceExItem!!.div(finalCount).toSafeFloat()
// }
else -> 0f //
} // else -> 0f
// 计算金额 // }
val finalAmount = when { // // 计算金额
finalCount == 0f -> { // val finalAmount = when {
0f // finalCount == 0f -> {
} // 0f
// }
_priceUserInput.value && !_amountUserInput.value -> { //
finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat() // _priceUserInput.value && !_amountUserInput.value -> {
} // finalCount.times(info.newRecUnitPriceTaxIn!!).toSafeFloat()
// }
else -> 0f //
} // else -> 0f
// }
_selectedItem.value = info.copy( //
goodsWeight = weight.toSafeBigDecimal(), // _selectedItem.value = info.copy(
// 收货数量 // goodsWeight = weight.toSafeBigDecimal(),
receivedNumTemp = finalCount.toFormattedString(), // // 收货数量
receivedNum = finalCount, // receivedNumTemp = finalCount.toFormattedString(),
// 单价 // receivedNum = finalCount,
newRecUnitPriceTaxIn = if (_priceUserInput.value) info.newRecUnitPriceTaxIn else finalPrice, // // 单价
newRecUnitPriceTaxInTemp = if (_priceUserInput.value) info.newRecUnitPriceTaxInTemp else finalPrice.toFormattedString(), // 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(), // recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount,
) // recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(),
} // )
// }
} }
fun partialReceipt(uploadInfo: UploadInfo) { 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 //package com.sw.inbound.viewmodel
//
import androidx.lifecycle.viewModelScope //import androidx.lifecycle.viewModelScope
import com.sw.inbound.GlobalData //import com.sw.inbound.GlobalData
import com.sw.inbound.ext.toFormattedString //import com.sw.inbound.ext.toFormattedString
import com.sw.inbound.ext.toSafeBigDecimal //import com.sw.inbound.ext.toSafeBigDecimal
import com.sw.inbound.ext.toSafeDouble //import com.sw.inbound.ext.toSafeDouble
import com.sw.inbound.model.request.GoodsAddParam //import com.sw.inbound.model.request.GoodsAddParam
import com.sw.inbound.model.request.GoodsPurchaseUnitParam //import com.sw.inbound.model.request.GoodsPurchaseUnitParam
import com.sw.inbound.model.request.PurchaseWarehouseParam //import com.sw.inbound.model.request.PurchaseWarehouseParam
import com.sw.inbound.model.response.DictType //import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.SearchGoodsInfo //import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.repository.RemoteRepository //import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.ContextUtils //import com.sw.inbound.utils.ContextUtils
import com.sw.inbound.utils.FileUtils //import com.sw.inbound.utils.FileUtils
import com.sw.inbound.utils.ToastUtils //import com.sw.inbound.utils.ToastUtils
import dagger.hilt.android.lifecycle.HiltViewModel //import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay //import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow //import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow //import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update //import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch //import kotlinx.coroutines.launch
import timber.log.Timber //import timber.log.Timber
import javax.inject.Inject //import javax.inject.Inject
//
/** ///**
* 自采购 // * 自采购
*/ // */
@HiltViewModel //@HiltViewModel
class SelfProcurementViewModel @Inject constructor( //class SelfProcurementViewModel @Inject constructor(
private val repository: RemoteRepository // private val repository: RemoteRepository
) : BaseViewModel(repository) { //) : BaseViewModel(repository) {
//
private val _addGoodsResult = MutableStateFlow<Boolean>(false) // private val _addGoodsResult = MutableStateFlow<Boolean>(false)
val addGoodsResult: StateFlow<Boolean> = _addGoodsResult // val addGoodsResult: StateFlow<Boolean> = _addGoodsResult
//
private val _addGoodsPurchaseUnitResult = MutableStateFlow<Boolean>(false) // private val _addGoodsPurchaseUnitResult = MutableStateFlow<Boolean>(false)
val addGoodsPurchaseUnitResult: StateFlow<Boolean> = _addGoodsPurchaseUnitResult // val addGoodsPurchaseUnitResult: StateFlow<Boolean> = _addGoodsPurchaseUnitResult
//
private val _addToWarehouseResult = MutableStateFlow<Boolean>(false) // private val _addToWarehouseResult = MutableStateFlow<Boolean>(false)
val addToWarehouseResult: StateFlow<Boolean> = _addToWarehouseResult // val addToWarehouseResult: StateFlow<Boolean> = _addToWarehouseResult
//
private val _selectedItem = MutableStateFlow<PurchaseWarehouseParam?>(null) // private val _selectedItem = MutableStateFlow<PurchaseWarehouseParam?>(null)
val selectedItem: StateFlow<PurchaseWarehouseParam?> = _selectedItem // val selectedItem: StateFlow<PurchaseWarehouseParam?> = _selectedItem
//
// 全局仓库信息 // // 全局仓库信息
private val _globalWarehouse = MutableStateFlow<DictType>(DictType(-1, "选择仓库")) // private val _globalWarehouse = MutableStateFlow<DictType>(DictType("", "选择仓库"))
val globalWarehouse: StateFlow<DictType> = _globalWarehouse // val globalWarehouse: StateFlow<DictType> = _globalWarehouse
//
// 采购列表 // // 采购列表
private val _purchaseList = MutableStateFlow<List<PurchaseWarehouseParam>>(emptyList()) // private val _purchaseList = MutableStateFlow<List<PurchaseWarehouseParam>>(emptyList())
val purchaseList: StateFlow<List<PurchaseWarehouseParam>> = _purchaseList // val purchaseList: StateFlow<List<PurchaseWarehouseParam>> = _purchaseList
//
// 表单状态 // // 表单状态
private val _goodsAddParam = MutableStateFlow<GoodsAddParam>(GoodsAddParam()) // private val _goodsAddParam = MutableStateFlow<GoodsAddParam>(GoodsAddParam())
val goodsAddParam: StateFlow<GoodsAddParam> = _goodsAddParam // val goodsAddParam: StateFlow<GoodsAddParam> = _goodsAddParam
//
private val _goodsAddUnitParam = // private val _goodsAddUnitParam =
MutableStateFlow<GoodsPurchaseUnitParam>(GoodsPurchaseUnitParam()) // MutableStateFlow<GoodsPurchaseUnitParam>(GoodsPurchaseUnitParam())
val goodsAddUnitParam: StateFlow<GoodsPurchaseUnitParam> = _goodsAddUnitParam // val goodsAddUnitParam: StateFlow<GoodsPurchaseUnitParam> = _goodsAddUnitParam
//
// 快速添加弹窗状态 // // 快速添加弹窗状态
private val _showAddProductDialog = MutableStateFlow<Boolean>(false) // private val _showAddProductDialog = MutableStateFlow<Boolean>(false)
val showAddProductDialog: StateFlow<Boolean> = _showAddProductDialog // val showAddProductDialog: StateFlow<Boolean> = _showAddProductDialog
//
// 添加采购单位弹窗状态 // // 添加采购单位弹窗状态
private val _showAddPurchaseUnitDialog = MutableStateFlow<Boolean>(false) // private val _showAddPurchaseUnitDialog = MutableStateFlow<Boolean>(false)
val showAddPurchaseUnitDialog: StateFlow<Boolean> = _showAddPurchaseUnitDialog // val showAddPurchaseUnitDialog: StateFlow<Boolean> = _showAddPurchaseUnitDialog
//
//
// 是否可以修改库存单位 // // 是否可以修改库存单位
private val _canChangeKcUnit = MutableStateFlow<Boolean>(false) // private val _canChangeKcUnit = MutableStateFlow<Boolean>(false)
val canChangeKcUnit: StateFlow<Boolean> = _canChangeKcUnit // val canChangeKcUnit: StateFlow<Boolean> = _canChangeKcUnit
//
// 是否可以修改消耗值 // // 是否可以修改消耗值
private val _canChangeConsumeValue = MutableStateFlow<Boolean>(false) // private val _canChangeConsumeValue = MutableStateFlow<Boolean>(false)
val canChangeConsumeValue: StateFlow<Boolean> = _canChangeConsumeValue // val canChangeConsumeValue: StateFlow<Boolean> = _canChangeConsumeValue
//
/** // /**
* 数量是否是用户输入的值 // * 数量是否是用户输入的值
*/ // */
private val _countUserInput = MutableStateFlow<Boolean>(false) // private val _countUserInput = MutableStateFlow<Boolean>(false)
//
/** // /**
* 单价是否是用户输入的值 // * 单价是否是用户输入的值
*/ // */
private val _priceUserInput = MutableStateFlow<Boolean>(false) // private val _priceUserInput = MutableStateFlow<Boolean>(false)
//
/** // /**
* 金额输入状态 // * 金额输入状态
*/ // */
private val _amountUserInput = MutableStateFlow<Boolean>(false) // private val _amountUserInput = MutableStateFlow<Boolean>(false)
//
// private val _storeSelectState = MutableStateFlow<String>("") //// private val _storeSelectState = MutableStateFlow<String>("")
// val storeSelectState = _storeSelectState //// val storeSelectState = _storeSelectState
// fun updateStoreState(store:String) { //// fun updateStoreState(store:String) {
// _storeSelectState.value = store //// _storeSelectState.value = store
//// }
// /**
// * 更新全局仓库
// */
// fun updateGlobalWarehouse(dictType: DictType) {
// _globalWarehouse.value = dictType
// } // }
/** //
* 更新全局仓库 // override fun handleSensorScale(weight: Double) {
*/ // val currentItem = _selectedItem.value
fun updateGlobalWarehouse(dictType: DictType) { //
_globalWarehouse.value = dictType // currentItem?.let { info ->
}
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
}
// val selectUnitType = currentItem.selectUnitType // val selectUnitType = currentItem.selectUnitType
// if (selectUnitType == null) return@startScale // // 用户输入数量后不再通过重量反算
// if (_countUserInput.value || selectUnitType == null) {
var consumeValue = selectUnitType.consumeValue?.toSafeDouble() ?: 1.0 // _selectedItem.value = info.copy(
var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0 // goodsWeight = weight.toSafeBigDecimal(),
if (consumeValue == 0.0) { // )
consumeValue = 1.0 // return
} // }
if (purchaseValue == 0.0) { //
purchaseValue = 1.0 //// val selectUnitType = currentItem.selectUnitType
} //// if (selectUnitType == null) return@startScale
val count = //
weight * 1000 / consumeValue / purchaseValue // var consumeValue = selectUnitType.consumeValue?.toSafeDouble() ?: 1.0
val finalCount = count.toSafeDouble(currentItem.unitName) // var purchaseValue = selectUnitType.purchaseValue?.toDouble() ?: 1.0
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") // if (consumeValue == 0.0) {
// consumeValue = 1.0
Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ") // }
// 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入 // if (purchaseValue == 0.0) {
val finalPrice = // purchaseValue = 1.0
if (finalCount == 0.0) { // }
0.0 // val count =
} else if (_amountUserInput.value && !_priceUserInput.value) { // weight * 1000 / consumeValue / purchaseValue
info.goodsPrice.div(finalCount).toSafeDouble() // val finalCount = count.toSafeDouble(currentItem.unitName)
} else 0.0 // Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
//
// 计算金额 单价不为空,不是数量输入 也不是金额输入 // Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ")
val finalAmount = // // 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入
if (finalCount == 0.0) { // val finalPrice =
0.0 // if (finalCount == 0.0) {
} else if (_priceUserInput.value && !_amountUserInput.value) { // 0.0
finalCount.times(info.goodsUnitPrice).toSafeDouble() // } else if (_amountUserInput.value && !_priceUserInput.value) {
} else 0.0 // info.goodsPrice.div(finalCount).toSafeDouble()
Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ") // } else 0.0
_selectedItem.value = info.copy( //
goodsWeight = weight.toSafeBigDecimal(), // // 计算金额 单价不为空,不是数量输入 也不是金额输入
// 数量 // val finalAmount =
goodsCountTemp = finalCount.toFormattedString(), // if (finalCount == 0.0) {
goodsCount = finalCount, // 0.0
// 单价 // } else if (_priceUserInput.value && !_amountUserInput.value) {
goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice, // finalCount.times(info.goodsUnitPrice).toSafeDouble()
goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(), // } else 0.0
// 金额 // Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ")
goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount, // _selectedItem.value = info.copy(
goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString() // goodsWeight = weight.toSafeBigDecimal(),
) // // 数量
} // goodsCountTemp = finalCount.toFormattedString(),
} // goodsCount = finalCount,
// // 单价
fun updateAddProductDialog(show: Boolean) { // goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice,
_showAddProductDialog.value = show // goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(),
if (!show) { // // 金额
_goodsAddParam.value = GoodsAddParam() // goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount,
} // goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString()
} // )
// }
fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) { // }
// updateLastPhotoUri(null) //
if (purchaseOrder != null) { // fun updateAddProductDialog(show: Boolean) {
if (purchaseOrder.goodsCount != 0.0) { // _showAddProductDialog.value = show
if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入 // if (!show) {
Timber.d("updateSelectedItem 计算金额") // _goodsAddParam.value = GoodsAddParam()
val result = // }
purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice) // }
purchaseOrder.goodsPrice = result.toSafeDouble() //
purchaseOrder.goodsPriceTemp = result.toFormattedString() // fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) {
} else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入 //// updateLastPhotoUri(null)
Timber.d("updateSelectedItem 计算单价") // if (purchaseOrder != null) {
val result = // if (purchaseOrder.goodsCount != 0.0) {
purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount) // if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
purchaseOrder.goodsUnitPrice = result.toSafeDouble() // Timber.d("updateSelectedItem 计算金额")
purchaseOrder.goodsUnitPriceTemp = result.toFormattedString() // val result =
} // purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice)
} else { // purchaseOrder.goodsPrice = result.toSafeDouble()
if (_priceUserInput.value) { // purchaseOrder.goodsPriceTemp = result.toFormattedString()
purchaseOrder.goodsPrice = 0.0 // } else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
purchaseOrder.goodsPriceTemp = "" // Timber.d("updateSelectedItem 计算单价")
} else if (_amountUserInput.value) { // val result =
purchaseOrder.goodsUnitPrice = 0.0 // purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount)
purchaseOrder.goodsUnitPriceTemp = "" // purchaseOrder.goodsUnitPrice = result.toSafeDouble()
} // purchaseOrder.goodsUnitPriceTemp = result.toFormattedString()
} // }
} else { // } else {
// 重置输入状态 // if (_priceUserInput.value) {
Timber.d("重置输入状态") // purchaseOrder.goodsPrice = 0.0
_countUserInput.value = false // purchaseOrder.goodsPriceTemp = ""
_priceUserInput.value = false // } else if (_amountUserInput.value) {
_amountUserInput.value = false // purchaseOrder.goodsUnitPrice = 0.0
} // purchaseOrder.goodsUnitPriceTemp = ""
_selectedItem.value = purchaseOrder // }
Timber.d("updateSelectedItem 更新,goodsUnitPrice = ${_selectedItem.value?.goodsUnitPrice}, ${_selectedItem.value?.goodsUnitPriceTemp}") // }
} // } else {
// // 重置输入状态
fun updateGoodsAddParam(newState: GoodsAddParam) { // Timber.d("重置输入状态")
_goodsAddParam.value = newState // _countUserInput.value = false
} // _priceUserInput.value = false
// _amountUserInput.value = false
fun cleanGoodsAddParam() { // }
_goodsAddParam.value = GoodsAddParam() // _selectedItem.value = purchaseOrder
} // Timber.d("updateSelectedItem 更新,goodsUnitPrice = ${_selectedItem.value?.goodsUnitPrice}, ${_selectedItem.value?.goodsUnitPriceTemp}")
// }
// 添加订单 //
fun addPurchaseItem(purchaseOrder: PurchaseWarehouseParam) { // fun updateGoodsAddParam(newState: GoodsAddParam) {
_purchaseList.update { currentList -> // _goodsAddParam.value = newState
currentList + purchaseOrder // }
} //
updateSelectedItem(null) // fun cleanGoodsAddParam() {
} // _goodsAddParam.value = GoodsAddParam()
// }
// 更新订单 //
fun updatePurchaseItem(purchaseOrder: PurchaseWarehouseParam) { // // 添加订单
_purchaseList.update { currentList -> // fun addPurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
currentList.map { order -> // _purchaseList.update { currentList ->
if (order.goodsId == purchaseOrder.goodsId) purchaseOrder else order // currentList + purchaseOrder
} // }
} // updateSelectedItem(null)
} // }
//
// 删除订单 // // 更新订单
fun removePurchaseOrder(orderId: Int) { // fun updatePurchaseItem(purchaseOrder: PurchaseWarehouseParam) {
_purchaseList.update { currentList -> // _purchaseList.update { currentList ->
currentList.filterNot { it.goodsId == orderId } // currentList.map { order ->
} // if (order.goodsId == purchaseOrder.goodsId) purchaseOrder else order
} // }
// }
/** // }
* 根据位置删除物品 //
*/ // // 删除订单
fun removePurchaseOrderByIndex(index: Int) { //// fun removePurchaseOrder(orderId: Int) {
_purchaseList.update { currentList -> //// _purchaseList.update { currentList ->
currentList.toMutableList().apply { //// currentList.filterNot { it.goodsId == orderId }
removeAt(index) //// }
} //// }
} //
} // /**
// * 根据位置删除物品
// 清空列表 // */
fun clearPurchaseOrders() { // fun removePurchaseOrderByIndex(index: Int) {
_purchaseList.value = emptyList() // _purchaseList.update { currentList ->
} // currentList.toMutableList().apply {
// removeAt(index)
override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) { // }
updateSelectedItemWithSearch(goodsInfo) // }
} // }
//
fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) { // // 清空列表
val warehouse = _globalWarehouse.value // fun clearPurchaseOrders() {
viewModelScope.launch { // _purchaseList.value = emptyList()
updateSelectedItem(null) // }
delay(50) //
_selectedItem.value = PurchaseWarehouseParam( // override fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {
warehouseId = warehouse.id, //// updateSelectedItemWithSearch(goodsInfo)
goodsId = searchFirst.goodsId ?: 0, // }
goodsName = searchFirst.goodsName, //
kcUnitId = searchFirst.kcUnitId ?: 0, //// fun updateSelectedItemWithSearch(searchFirst: SearchGoodsInfo.Record) {
unitList = searchFirst.unitVoList, //// val warehouse = _globalWarehouse.value
consumeValue = searchFirst.consumeValue ?: "" //// viewModelScope.launch {
) //// updateSelectedItem(null)
} //// delay(50)
} //// _selectedItem.value = PurchaseWarehouseParam(
//// warehouseId = warehouse.id,
/** //// goodsId = searchFirst.goodsId ?: 0,
* 数量输入状态 //// goodsName = searchFirst.goodsName,
*/ //// kcUnitId = searchFirst.kcUnitId ?: 0,
fun updateCountInputState(boolean: Boolean) { //// unitList = searchFirst.unitVoList,
_countUserInput.value = boolean //// consumeValue = searchFirst.consumeValue ?: ""
} //// )
//// }
/** //// }
* 单价输入状态 //
*/ // /**
fun updatePriceInputState(boolean: Boolean) { // * 数量输入状态
_priceUserInput.value = boolean // */
} // fun updateCountInputState(boolean: Boolean) {
// _countUserInput.value = boolean
/** // }
* 金额输入状态 //
*/ // /**
fun updateAmountInputState(boolean: Boolean) { // * 单价输入状态
_amountUserInput.value = boolean // */
} // fun updatePriceInputState(boolean: Boolean) {
// _priceUserInput.value = boolean
/** // }
* 添加商品 //
*/ // /**
fun addGoodsInfo() { // * 金额输入状态
val imageUri = GlobalData.imageUri // */
if (imageUri == null) { // fun updateAmountInputState(boolean: Boolean) {
ToastUtils.showToast("请先进行图片采集") // _amountUserInput.value = boolean
return // }
} //
val errInfo = _goodsAddParam.value.hasNullField() // /**
if (errInfo != null) { // * 添加商品
ToastUtils.showToast(errInfo) // */
return //// fun addGoodsInfo() {
} //// val imageUri = GlobalData.imageUri
//// if (imageUri == null) {
launchWithLoading { //// ToastUtils.showToast("请先进行图片采集")
val uploadResponse = repository.uploadImage(imageUri) //// return
if (!parseResponse(uploadResponse)) { //// }
return@launchWithLoading //// val errInfo = _goodsAddParam.value.hasNullField()
} //// if (errInfo != null) {
// ToastUtils.showToast("图片上传成功,${uploadResponse.data}") //// ToastUtils.showToast(errInfo)
GlobalData.imageUri = null //// return
_goodsAddParam.value.relativeUrl = uploadResponse.result //// }
val response = repository.selfPurchaseGoodsAdd(_goodsAddParam.value) ////
if (!parseResponse(response)) { //// launchWithLoading {
return@launchWithLoading //// val uploadResponse = repository.uploadImage(imageUri)
} //// if (!parseResponse(uploadResponse)) {
FileUtils.deleteFileWithUri(context = ContextUtils.getAppContext(), uri = imageUri) //// return@launchWithLoading
_showAddProductDialog.value = false //// }
_goodsAddParam.value = GoodsAddParam() ////// ToastUtils.showToast("图片上传成功,${uploadResponse.data}")
val searchFirst = response.result!!.records?.get(0) //// GlobalData.imageUri = null
searchFirst?.let { //// _goodsAddParam.value.relativeUrl = uploadResponse.result
updateSelectedItemWithSearch(searchFirst) //// val response = repository.selfPurchaseGoodsAdd(_goodsAddParam.value)
} //// if (!parseResponse(response)) {
_addGoodsResult.value = true //// return@launchWithLoading
} //// }
} //// FileUtils.deleteFileWithUri(context = ContextUtils.getAppContext(), uri = imageUri)
//// _showAddProductDialog.value = false
fun updateAddPurchaseUnitDialog(show: Boolean) { //// _goodsAddParam.value = GoodsAddParam()
if (_selectedItem.value == null) return //// val searchFirst = response.result!!.records?.get(0)
_showAddPurchaseUnitDialog.value = show //// searchFirst?.let {
if (show) { //// updateSelectedItemWithSearch(searchFirst)
val hasUnitId = GlobalData.unitTypeList.any { it.id == _selectedItem.value!!.kcUnitId } //// }
_canChangeKcUnit.value = !hasUnitId //// _addGoodsResult.value = true
_canChangeConsumeValue.value = //// }
_selectedItem.value!!.consumeValue.trim().isEmpty() == true //// }
} else { //
_goodsAddUnitParam.value = GoodsPurchaseUnitParam() // fun updateAddPurchaseUnitDialog(show: Boolean) {
} // if (_selectedItem.value == null) return
} // _showAddPurchaseUnitDialog.value = show
// if (show) {
fun updateGoodsPurchaseUnit(goodsPurchaseUnitParam: GoodsPurchaseUnitParam?) { // val hasUnitId =
if (goodsPurchaseUnitParam == null) { // GlobalData.unitTypeList.any { it.id == _selectedItem.value!!.kcUnitId.toString() }
_goodsAddUnitParam.value = GoodsPurchaseUnitParam() // _canChangeKcUnit.value = !hasUnitId
} else { // _canChangeConsumeValue.value =
_goodsAddUnitParam.value = goodsPurchaseUnitParam // _selectedItem.value!!.consumeValue.trim().isEmpty() == true
} // } else {
} // _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
// }
fun updateDropdownTextChange(canChange: Boolean) { // }
_canChangeKcUnit.value == canChange //
} // fun updateGoodsPurchaseUnit(goodsPurchaseUnitParam: GoodsPurchaseUnitParam?) {
// if (goodsPurchaseUnitParam == null) {
fun addGoodsPurchaseUnit() { // _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
val errorInfo = _goodsAddUnitParam.value.hasNullField() // } else {
if (errorInfo != null) { // _goodsAddUnitParam.value = goodsPurchaseUnitParam
ToastUtils.showToast(errorInfo) // }
return // }
} //
launchWithLoading { // fun updateDropdownTextChange(canChange: Boolean) {
val response = repository.selfPurchaseGoodsAddUnit(_goodsAddUnitParam.value) // _canChangeKcUnit.value == canChange
if (parseResponse(response)) { // }
_showAddPurchaseUnitDialog.value = false //
_goodsAddUnitParam.value = GoodsPurchaseUnitParam() // fun addGoodsPurchaseUnit() {
// _addGoodsPurchaseUnitResult.value = true // val errorInfo = _goodsAddUnitParam.value.hasNullField()
ToastUtils.showToast("采购单位添加成功") // if (errorInfo != null) {
// ToastUtils.showToast(errorInfo)
// 通过id搜索物品,补充采购单位 // return
val response = repository.searchGoodsInfoList( // }
goodsName = "${_selectedItem.value?.goodsId}" // launchWithLoading {
) // val response = repository.selfPurchaseGoodsAddUnit(_goodsAddUnitParam.value)
if (parseResponse(response)) { // if (parseResponse(response)) {
val searchList: List<SearchGoodsInfo.Record> = // _showAddPurchaseUnitDialog.value = false
response.result?.records ?: emptyList() // _goodsAddUnitParam.value = GoodsPurchaseUnitParam()
if (searchList.isNotEmpty()) { //// _addGoodsPurchaseUnitResult.value = true
val searchItem = searchList[0] // ToastUtils.showToast("采购单位添加成功")
_selectedItem.value = _selectedItem.value?.copy( //
unitList = searchItem.unitVoList, // // 通过id搜索物品,补充采购单位
kcUnitId = searchItem.kcUnitId ?: 0, // val response = repository.searchGoodsInfoList(
consumeValue = searchItem.consumeValue ?: "" // 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) // /**
} // * 物品提交入库
} // */
} // 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() { fun getInitInfo() {
Timber.d("getInitInfo isFirstLaunch = $isFirstLaunch") Timber.d("getInitInfo isFirstLaunch = $isFirstLaunch")
if (isFirstLaunch) { //if (isFirstLaunch) {
getUserInfo() getUserInfo()
getDictType() getDictType()
isFirstLaunch = false isFirstLaunch = false
} //}
} }
fun login(userName: String, password: String) = launchWithLoading { 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