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 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.User
import com.sw.inbound.model.response.ZoneOption
@@ -52,6 +53,11 @@ object GlobalData {
*/
var inboundZoneList: List<ZoneOption> = emptyList()
/**
* 规格
*/
var specOptionList: List<SpecOption> = emptyList()
/**
* 具体业务 BaseUrl
*/
@@ -51,6 +51,7 @@ class StoreActivity : GoodsListActivity() {
private fun preloadInboundOptions() {
storeViewModel.loadSupplierOptions(callback = { GlobalData.inboundSupplierList = it })
storeViewModel.loadZoneOptions(callback = { GlobalData.inboundZoneList = it })
storeViewModel.loadSpecOptions(callback = { GlobalData.specOptionList = it })
}
/** 隐藏采购单列表、仓库下拉、提交按钮等本页面不需要的控件 */
@@ -164,6 +164,12 @@ class InboundGoodsStoreDialog(
val id = zone.id?.toString() ?: return@mapNotNull null
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(
FormField(
"溯源码",
@@ -188,10 +194,11 @@ class InboundGoodsStoreDialog(
),
FormField(
"入库规格",
FieldType.TEXT,
apiKey = "spec",
FieldType.DROPDOWN,
extraApiKeys = mapOf("spec" to "id", "spec_dictText" to "value"),
required = true,
hint = "输入入库规格"
hint = "选择入库规格",
options = specOptions
),
FormField(
"入库数量",
@@ -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
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.InboundApiResponse
import com.sw.inbound.model.response.SupplierOption
@@ -41,6 +42,13 @@ interface InboundApiService {
@Query("keyword") keyword: String? = null
): 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 以便动态组装字段 */
@POST
suspend fun submitRawInbound(
@@ -3,6 +3,7 @@ package com.sw.inbound.repository
import com.google.gson.JsonParseException
import com.sw.inbound.model.response.IngredientByTrace
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.ZoneOption
import com.sw.inbound.network.api.InboundApiService
@@ -43,6 +44,11 @@ class InboundRepository @Inject constructor(
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> {
return safeCall { apiService.submitRawInbound(param = param) }
@@ -3,6 +3,7 @@ package com.sw.inbound.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
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.ZoneOption
import com.sw.inbound.repository.InboundRepository
@@ -24,6 +25,9 @@ class StoreViewModel @Inject constructor(
private val _supplierOptions = MutableStateFlow<List<SupplierOption>>(emptyList())
val supplierOptions: StateFlow<List<SupplierOption>> = _supplierOptions
private val _specOptions = MutableStateFlow<List<SpecOption>>(emptyList())
val specOptions: StateFlow<List<SpecOption>> = _specOptions
/** 按溯源码查食材,结果通过 callback 返回 */
fun getIngredientByTrace(
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) {
viewModelScope.launch {