feat(inbound): 添加规格下拉选择功能

- 新增 SpecOption 数据模型定义
- 在 GlobalData 中添加 specOptionList 全局变量
- 实现 InboundApiService 中的 getSpecOptions 接口
- 添加 InboundRepository 中的 getSpecOptions 方法
- 在 StoreViewModel 中添加 specOptions 相关状态管理
- 在 StoreActivity 预加载规格选项数据
- 将入库规格字段从文本框改为下拉选择框
- 修复代码中的空字符串初始化问题
This commit is contained in:
2026-06-08 14:38:03 +08:00
parent 74fcd65f1b
commit c76164fa66
7 changed files with 62 additions and 6 deletions
@@ -2,6 +2,7 @@ package com.sw.inbound
import android.net.Uri import android.net.Uri
import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.SpecOption
import com.sw.inbound.model.response.SupplierOption import com.sw.inbound.model.response.SupplierOption
import com.sw.inbound.model.response.User import com.sw.inbound.model.response.User
import com.sw.inbound.model.response.ZoneOption import com.sw.inbound.model.response.ZoneOption
@@ -52,6 +53,11 @@ object GlobalData {
*/ */
var inboundZoneList: List<ZoneOption> = emptyList() var inboundZoneList: List<ZoneOption> = emptyList()
/**
* 规格
*/
var specOptionList: List<SpecOption> = emptyList()
/** /**
* 具体业务 BaseUrl * 具体业务 BaseUrl
*/ */
@@ -51,6 +51,7 @@ class StoreActivity : GoodsListActivity() {
private fun preloadInboundOptions() { private fun preloadInboundOptions() {
storeViewModel.loadSupplierOptions(callback = { GlobalData.inboundSupplierList = it }) storeViewModel.loadSupplierOptions(callback = { GlobalData.inboundSupplierList = it })
storeViewModel.loadZoneOptions(callback = { GlobalData.inboundZoneList = it }) storeViewModel.loadZoneOptions(callback = { GlobalData.inboundZoneList = it })
storeViewModel.loadSpecOptions(callback = { GlobalData.specOptionList = it })
} }
/** 隐藏采购单列表、仓库下拉、提交按钮等本页面不需要的控件 */ /** 隐藏采购单列表、仓库下拉、提交按钮等本页面不需要的控件 */
@@ -105,7 +105,7 @@ class InboundGoodsStoreDialog(
FieldType.TEXT, FieldType.TEXT,
apiKey = "materialName", apiKey = "materialName",
required = true, required = true,
value = goods?.materName ?:"", value = goods?.materName ?: "",
hint = "请输入食材名称" hint = "请输入食材名称"
), ),
FormField( FormField(
@@ -164,6 +164,12 @@ class InboundGoodsStoreDialog(
val id = zone.id?.toString() ?: return@mapNotNull null val id = zone.id?.toString() ?: return@mapNotNull null
DictType(id = id, value = zone.zoneName) DictType(id = id, value = zone.zoneName)
} }
val specOptions = GlobalData.specOptionList.mapNotNull { spec ->
if (spec.dictCode.isNullOrEmpty() || spec.dictLabel.isNullOrEmpty()) {
return@mapNotNull null
}
DictType(id = spec.dictCode, value = spec.dictLabel)
}
return mutableListOf( return mutableListOf(
FormField( FormField(
"溯源码", "溯源码",
@@ -188,10 +194,11 @@ class InboundGoodsStoreDialog(
), ),
FormField( FormField(
"入库规格", "入库规格",
FieldType.TEXT, FieldType.DROPDOWN,
apiKey = "spec", extraApiKeys = mapOf("spec" to "id", "spec_dictText" to "value"),
required = true, required = true,
hint = "输入入库规格" hint = "选择入库规格",
options = specOptions
), ),
FormField( FormField(
"入库数量", "入库数量",
@@ -323,7 +330,7 @@ class InboundGoodsStoreDialog(
val param = buildParamMap() val param = buildParamMap()
// weight 来自秤,不在表单中,额外注入 // weight 来自秤,不在表单中,额外注入
param["weight"] = realWeight / 1000.0 param["weight"] = realWeight / 1000.0
param["materId"] = goods?.materId ?:"" param["materId"] = goods?.materId ?: ""
Loading.show(storeActivity ?: return) Loading.show(storeActivity ?: return)
storeActivity?.storeViewModel?.submitRawInbound(param) { success, msg -> storeActivity?.storeViewModel?.submitRawInbound(param) { success, msg ->
Loading.dismiss() Loading.dismiss()
@@ -344,7 +351,7 @@ class InboundGoodsStoreDialog(
// inboundTime 净菜取当前时间,不在表单中 // inboundTime 净菜取当前时间,不在表单中
val inboundTime = isoFormat.format(Date()) val inboundTime = isoFormat.format(Date())
param["inboundTime"] = inboundTime param["inboundTime"] = inboundTime
param["materId"] = goods?.materId ?:"" param["materId"] = goods?.materId ?: ""
val expiryDate = param["expiryDate"] as? String val expiryDate = param["expiryDate"] as? String
param["expiryDate"] = expiryDate + " " + inboundTime.split(" ").getOrNull(1) param["expiryDate"] = expiryDate + " " + inboundTime.split(" ").getOrNull(1)
@@ -0,0 +1,9 @@
package com.sw.inbound.model.response
/**
* 字典下拉,dictLabel 用于界面展示,dictCode 用于提交入参
*/
data class SpecOption(
var dictLabel:String?,
var dictCode:String?,
)
@@ -1,6 +1,7 @@
package com.sw.inbound.network.api package com.sw.inbound.network.api
import com.sw.inbound.GlobalData import com.sw.inbound.GlobalData
import com.sw.inbound.model.response.SpecOption
import com.sw.inbound.model.response.IngredientByTrace import com.sw.inbound.model.response.IngredientByTrace
import com.sw.inbound.model.response.InboundApiResponse import com.sw.inbound.model.response.InboundApiResponse
import com.sw.inbound.model.response.SupplierOption import com.sw.inbound.model.response.SupplierOption
@@ -41,6 +42,13 @@ interface InboundApiService {
@Query("keyword") keyword: String? = null @Query("keyword") keyword: String? = null
): InboundApiResponse<List<SupplierOption>> ): InboundApiResponse<List<SupplierOption>>
/** 规格下拉列表,dictType=nut_spec_type */
@GET
suspend fun getSpecOptions(
@Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/dict-items",
@Query("dictType") dictType: String = "nut_spec_type"
): InboundApiResponse<List<SpecOption>?>
/** 毛菜入库提交,入参为 Map 以便动态组装字段 */ /** 毛菜入库提交,入参为 Map 以便动态组装字段 */
@POST @POST
suspend fun submitRawInbound( suspend fun submitRawInbound(
@@ -3,6 +3,7 @@ package com.sw.inbound.repository
import com.google.gson.JsonParseException import com.google.gson.JsonParseException
import com.sw.inbound.model.response.IngredientByTrace import com.sw.inbound.model.response.IngredientByTrace
import com.sw.inbound.model.response.InboundApiResponse import com.sw.inbound.model.response.InboundApiResponse
import com.sw.inbound.model.response.SpecOption
import com.sw.inbound.model.response.SupplierOption import com.sw.inbound.model.response.SupplierOption
import com.sw.inbound.model.response.ZoneOption import com.sw.inbound.model.response.ZoneOption
import com.sw.inbound.network.api.InboundApiService import com.sw.inbound.network.api.InboundApiService
@@ -43,6 +44,11 @@ class InboundRepository @Inject constructor(
return safeCall { apiService.getSupplierOptions(type = type, keyword = keyword) } return safeCall { apiService.getSupplierOptions(type = type, keyword = keyword) }
} }
/** 规格下拉列表 */
suspend fun getSpecOptions(): InboundApiResponse<List<SpecOption>?> {
return safeCall { apiService.getSpecOptions() }
}
/** 毛菜入库提交 */ /** 毛菜入库提交 */
suspend fun submitRawInbound(param: Map<String, Any>): InboundApiResponse<Unit> { suspend fun submitRawInbound(param: Map<String, Any>): InboundApiResponse<Unit> {
return safeCall { apiService.submitRawInbound(param = param) } return safeCall { apiService.submitRawInbound(param = param) }
@@ -3,6 +3,7 @@ package com.sw.inbound.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sw.inbound.model.response.IngredientByTrace import com.sw.inbound.model.response.IngredientByTrace
import com.sw.inbound.model.response.SpecOption
import com.sw.inbound.model.response.SupplierOption import com.sw.inbound.model.response.SupplierOption
import com.sw.inbound.model.response.ZoneOption import com.sw.inbound.model.response.ZoneOption
import com.sw.inbound.repository.InboundRepository import com.sw.inbound.repository.InboundRepository
@@ -24,6 +25,9 @@ class StoreViewModel @Inject constructor(
private val _supplierOptions = MutableStateFlow<List<SupplierOption>>(emptyList()) private val _supplierOptions = MutableStateFlow<List<SupplierOption>>(emptyList())
val supplierOptions: StateFlow<List<SupplierOption>> = _supplierOptions val supplierOptions: StateFlow<List<SupplierOption>> = _supplierOptions
private val _specOptions = MutableStateFlow<List<SpecOption>>(emptyList())
val specOptions: StateFlow<List<SpecOption>> = _specOptions
/** 按溯源码查食材,结果通过 callback 返回 */ /** 按溯源码查食材,结果通过 callback 返回 */
fun getIngredientByTrace( fun getIngredientByTrace(
traceCode: String, traceCode: String,
@@ -78,6 +82,21 @@ class StoreViewModel @Inject constructor(
} }
} }
/** 加载规格列表,结果同时更新 StateFlow 并通过 callback 返回 */
fun loadSpecOptions(callback: ((List<SpecOption>) -> Unit)? = null) {
viewModelScope.launch {
val response = repository.getSpecOptions()
if (response.isSuccess()) {
val list = response.data ?: emptyList()
_specOptions.value = list
callback?.invoke(list)
} else {
Timber.e("loadSpecOptions failed: ${response.msg}")
callback?.invoke(emptyList())
}
}
}
/** 毛菜入库提交 */ /** 毛菜入库提交 */
fun submitRawInbound(param: Map<String, Any>, callback: (Boolean, String?) -> Unit) { fun submitRawInbound(param: Map<String, Any>, callback: (Boolean, String?) -> Unit) {
viewModelScope.launch { viewModelScope.launch {