diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3aa6ed2..631d349 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -79,6 +79,16 @@
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
+
+
+
+
) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemTaskBinding) : QuickViewHolder(binding.root)
+
+ override fun onBindViewHolder(
+ holder: VH,
+ position: Int,
+ item: NutComboTaskVO?
+ ) {
+ holder.binding.apply {
+ tvTaskNo.text = "任务编号:${item?.taskNo}"
+ tvTargetDish.text = item?.targetDish
+ tvSpec.text = item?.spec
+ tvPlanDate.text = "计划日期:${item?.planDate}"
+ tvPortions.text = "总份数:${item?.portions}"
+ tvOwnerName.text = "负责人:${item?.ownerName}"
+
+ // 状态文本映射
+ val statusText = when (item?.comboStatus) {
+ 0 -> "待组配"
+ 1 -> "组配中"
+ 2 -> "已完成"
+ else -> "未知"
+ }
+ tvStatus.text = statusText
+ }
+ }
+
+ override fun onCreateViewHolder(
+ context: Context,
+ parent: ViewGroup,
+ viewType: Int
+ ): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemTaskBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/TaskDetailAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/TaskDetailAdapter.kt
new file mode 100644
index 0000000..6e99a78
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/adapter/TaskDetailAdapter.kt
@@ -0,0 +1,76 @@
+package com.shuwei.dish.match.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.shuwei.dish.match.R
+import com.shuwei.dish.match.databinding.ListItemTaskDetailBinding
+import com.shuwei.dish.match.model.NutComboTaskItemDetail
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.visible
+import java.math.BigDecimal
+
+/**
+ * 组配任务详情食材列表适配器
+ */
+class TaskDetailAdapter(list: MutableList) :
+ BaseQuickAdapter(list) {
+
+ inner class VH(var binding: ListItemTaskDetailBinding) : QuickViewHolder(binding.root)
+
+ /**
+ * 格式化用量字符串,去掉小数点后末尾的0
+ */
+ private fun formatQty(value: String?): String {
+ if (value.isNullOrBlank()) return "0"
+ return try {
+ BigDecimal(value).stripTrailingZeros().toPlainString()
+ } catch (e: Exception) {
+ value
+ }
+ }
+
+ override fun onBindViewHolder(
+ holder: VH,
+ position: Int,
+ item: NutComboTaskItemDetail?
+ ) {
+ holder.binding.apply {
+ tvIngredientName.text = item?.ingredientName
+
+ // 食材类别
+ val classText = when (item?.ingredientClass) {
+ 1 -> "主材"
+ 2 -> "辅材"
+ 3 -> "调料"
+ else -> "未知"
+ }
+ tvIngredientClass.text = classText
+
+ val unit = item?.unit ?: "g"
+ tvPerPortionQty.text = "每份用量:${formatQty(item?.perPortionQty)}${unit}"
+ tvActualQty.text = "实际用量:${formatQty(item?.actualQty)}${unit}"
+ tvTotalQty.text = "合计用量:${formatQty(item?.totalQty)}${unit}"
+
+ tvTraceCode.visible()
+ tvTraceCode.text = "溯源码:${(item?.traceCode ?:"").ifBlank { "-" }}"
+
+ root.setBackgroundResource(
+ if (item?.isClicked == true) R.drawable.shape_item_cook_dish
+ else R.drawable.shape_white_fb_15_corners
+ )
+ }
+ }
+
+ override fun onCreateViewHolder(
+ context: Context,
+ parent: ViewGroup,
+ viewType: Int
+ ): VH {
+ val inflater = LayoutInflater.from(context)
+ val binding = ListItemTaskDetailBinding.inflate(inflater, parent, false)
+ return VH(binding)
+ }
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt
index 074e472..833360f 100644
--- a/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt
+++ b/app/src/main/java/com/shuwei/dish/match/base/BaseApp.kt
@@ -31,6 +31,9 @@ class BaseApp : Application() {
GlobalData.appBaseUrl = savedBaseUrl
}
CrashHandler.init(this)
+
+ GlobalData.deviceId = AppUtil.getUDID(this)
+
// val deviceId = if (BuildConfig.IS_TEST_DEVICE) ScaleDeviceConfig.DEVICE_ID_2 else AppUtil.getUDID(this)
// Log.d(TAG, "onCreate: deviceId=$deviceId, isTestDevice=${BuildConfig.IS_TEST_DEVICE}")
// GlobalData.deviceId = deviceId
diff --git a/app/src/main/java/com/shuwei/dish/match/model/NutritionModels.kt b/app/src/main/java/com/shuwei/dish/match/model/NutritionModels.kt
index a9ba561..6749a1e 100644
--- a/app/src/main/java/com/shuwei/dish/match/model/NutritionModels.kt
+++ b/app/src/main/java/com/shuwei/dish/match/model/NutritionModels.kt
@@ -183,6 +183,61 @@ data class NutSupMealPackageIngredient(
val traceCode: String
)
+/**
+ * 组配任务VO - 未完成组配任务列表响应
+ */
+@Parcelize
+data class NutComboTaskVO(
+ val id: Long?,
+ val taskNo: String?,
+ val planDate: String?,
+ val canteenId: Long?,
+ val mealType: Int?,
+ val foodId: Long?,
+ val targetDish: String?,
+ val spec: String?,
+ val portions: Int?,
+ var comboStatus: Int?,
+ val ownerName: String?,
+ val createTime: String?
+) : Parcelable
+
+/**
+ * 组配任务详情VO - 组配任务详情响应
+ */
+@Parcelize
+data class NutComboTaskDetailVO(
+ val id: Long?,
+ val taskNo: String?,
+ val planDate: String?,
+ val canteenId: Long?,
+ val mealType: Int?,
+ val foodId: Long?,
+ val targetDish: String?,
+ val spec: String?,
+ val portions: Int?,
+ val comboStatus: Int?,
+ val ownerName: String?,
+ val items: List?
+) : Parcelable
+
+/**
+ * 组配任务食材明细
+ */
+@Parcelize
+data class NutComboTaskItemDetail(
+ val id: Long?,
+ val ingredientCode: String?,
+ val ingredientName: String?,
+ val ingredientClass: Int?,
+ var traceCode: String?,
+ val perPortionQty: String?,
+ val actualQty: String?,
+ val totalQty: String?,
+ val unit: String?,
+ var isClicked: Boolean? = false,
+) : Parcelable
+
/**
* ID通用DTO - 用于开始/完成组配等需要id参数的接口
*/
diff --git a/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt b/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt
index 242785c..ec1d23e 100644
--- a/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt
+++ b/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt
@@ -24,6 +24,7 @@ data class SettingItem(
WEIGHT_CONFIG("减重配置"),
CLEAN_PACKAGE("净菜包"),
MEAL_PACKAGE("餐品净菜包"),
+ GROUP_TASK("组配任务"),
MEAL_PACKAGE_TEST("餐品净菜包-测试"),
DB_INSPECT("数据库查看"),
SCALE_OBSERVE("秤数据监控"),
diff --git a/app/src/main/java/com/shuwei/dish/match/net/ApiServiceV2.kt b/app/src/main/java/com/shuwei/dish/match/net/ApiServiceV2.kt
index cfb7f67..180c88c 100644
--- a/app/src/main/java/com/shuwei/dish/match/net/ApiServiceV2.kt
+++ b/app/src/main/java/com/shuwei/dish/match/net/ApiServiceV2.kt
@@ -10,6 +10,8 @@ import com.shuwei.dish.match.model.NutSupHygieneIngredientOptionVO
import com.shuwei.dish.match.model.NutProdComboVideoVO
import com.shuwei.dish.match.model.NutProdComboTaskDTO
import com.shuwei.dish.match.model.IdDTO
+import com.shuwei.dish.match.model.NutComboTaskDetailVO
+import com.shuwei.dish.match.model.NutComboTaskVO
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@@ -135,4 +137,27 @@ interface ApiServiceV2 {
@Body param: Map
): ApiResponse
+ // ========== 五、组配任务接口 ==========
+
+ /**
+ * 查询未完成组配任务(分页)
+ */
+ @GET
+ suspend fun getIncompleteComboTasks(
+ @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/combo-task/incomplete",
+ @Query("deviceCode") deviceCode: String? = null,
+ @Query("keyword") keyword: String? = null,
+ @Query("pageNum") pageNum: Int = 1,
+ @Query("pageSize") pageSize: Int = 10
+ ): ApiResponse>
+
+ /**
+ * 获取组配任务详情
+ */
+ @GET
+ suspend fun getComboTaskDetail(
+ @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/combo-task/detail",
+ @Query("id") id: Long
+ ): ApiResponse
+
}
diff --git a/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt b/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt
index 179d3a2..35eb7b8 100644
--- a/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt
+++ b/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt
@@ -3,6 +3,8 @@ package com.shuwei.dish.match.net
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.shuwei.dish.match.model.NutCanteenVO
+import com.shuwei.dish.match.model.NutComboTaskDetailVO
+import com.shuwei.dish.match.model.NutComboTaskVO
import com.shuwei.dish.match.model.NutDictItemVO
import com.shuwei.dish.match.model.NutFoodOptionVO
import com.shuwei.dish.match.model.NutMaterOptionVO
@@ -203,4 +205,37 @@ class NetViewModelV2(
}
}
+ // ========== 组配任务接口 ==========
+
+ /**
+ * 查询未完成组配任务(回调版本)
+ */
+ fun getIncompleteComboTasksWithCallback(
+ deviceCode: String? = null,
+ keyword: String? = null,
+ pageNum: Int = 1,
+ pageSize: Int = 10,
+ onLoading: () -> Unit = {},
+ onResult: (UiState?>) -> Unit
+ ) {
+ viewModelScope.launch {
+ onLoading()
+ onResult(repository.getIncompleteComboTasks(deviceCode = deviceCode, keyword = keyword, pageNum = pageNum, pageSize = pageSize))
+ }
+ }
+
+ /**
+ * 获取组配任务详情(回调版本)
+ */
+ fun getComboTaskDetailWithCallback(
+ id: Long,
+ onLoading: () -> Unit = {},
+ onResult: (UiState) -> Unit
+ ) {
+ viewModelScope.launch {
+ onLoading()
+ onResult(repository.getComboTaskDetail(id))
+ }
+ }
+
}
diff --git a/app/src/main/java/com/shuwei/dish/match/net/RemoteRepositoryV2.kt b/app/src/main/java/com/shuwei/dish/match/net/RemoteRepositoryV2.kt
index 7158e0f..bd1e8c1 100644
--- a/app/src/main/java/com/shuwei/dish/match/net/RemoteRepositoryV2.kt
+++ b/app/src/main/java/com/shuwei/dish/match/net/RemoteRepositoryV2.kt
@@ -2,6 +2,8 @@ package com.shuwei.dish.match.net
import com.shuwei.dish.match.model.IdDTO
import com.shuwei.dish.match.model.NutCanteenVO
+import com.shuwei.dish.match.model.NutComboTaskDetailVO
+import com.shuwei.dish.match.model.NutComboTaskVO
import com.shuwei.dish.match.model.NutDictItemVO
import com.shuwei.dish.match.model.NutFoodOptionVO
import com.shuwei.dish.match.model.NutMaterOptionVO
@@ -87,4 +89,17 @@ class RemoteRepositoryV2 {
suspend fun addMealPackage(param: Map): UiState =
safeApiCall { apiService.addMealPackage(param = param) }
+ // ========== 组配任务接口 ==========
+
+ suspend fun getIncompleteComboTasks(
+ deviceCode: String? = null,
+ keyword: String? = null,
+ pageNum: Int = 1,
+ pageSize: Int = 10
+ ): UiState?> =
+ safeApiCall { apiService.getIncompleteComboTasks(deviceCode = deviceCode, keyword = keyword, pageNum = pageNum, pageSize = pageSize) }
+
+ suspend fun getComboTaskDetail(id: Long): UiState =
+ safeApiCall { apiService.getComboTaskDetail(id = id) }
+
}
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt
index 00d6893..3cd6a63 100644
--- a/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt
+++ b/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt
@@ -109,6 +109,8 @@ class PackActivity : BaseActivity() {
binding.etInputDish.isFocusableInTouchMode = false
binding.ivDishSearch.gone()
+ binding.tvGoodsName.text = "食材名称"
+
addViewClickListener()
addBackKeyListener()
initCamera(binding.flCameraContainer)
@@ -206,7 +208,7 @@ class PackActivity : BaseActivity() {
materialAdapter.notifyItemChanged(clickIndex)
}
}
- binding.btnGetCode.clickWithDebounce {
+ binding.btnGetTraceCode.clickWithDebounce {
val item = list.getOrNull(clickIndex)?:return@clickWithDebounce
//viewModelV2.getCode
}
@@ -367,12 +369,19 @@ class PackActivity : BaseActivity() {
private var clickIndex = -1
private val materialAdapter by lazy {
FoodMaterialAdapter(list).apply {
- onItemClick = { positon ->
+ onItemClick = onItemClick@{ positon ->
+ val item = getItem(positon) ?: return@onItemClick
this@PackActivity.clickIndex = positon
list.forEachIndexed { index, entity ->
entity.isClicked = index == positon
}
notifyDataSetChanged()
+ binding.tvGoodsName.text = item.goodsName
+ binding.tvMaterialType.text = when (item.materialType) {
+ 1 -> "主材"
+ 2 -> "辅材"
+ else -> "未知"
+ }
}
addOnItemChildClickListener(R.id.ivClearIcon) { _, _, position ->
val item = list.getOrNull(position) ?: return@addOnItemChildClickListener
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt
index d35ecd2..d77e652 100644
--- a/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt
+++ b/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt
@@ -116,6 +116,12 @@ class SettingActivity : BaseActivity() {
startActivity { }
}
),
+ SettingItem(
+ type = SettingItem.Type.GROUP_TASK,
+ onClick = {
+ startActivity { }
+ }
+ ),
SettingItem(
type = SettingItem.Type.MEAL_PACKAGE_TEST,
onClick = {
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/TaskActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/TaskActivity.kt
new file mode 100644
index 0000000..6b5bf35
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/TaskActivity.kt
@@ -0,0 +1,207 @@
+package com.shuwei.dish.match.ui
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.shuwei.dish.match.adapter.TaskAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.base.GlobalData
+import com.shuwei.dish.match.databinding.ActivityTaskBinding
+import com.shuwei.dish.match.model.NutComboTaskVO
+import com.shuwei.dish.match.net.NetViewModelV2
+import com.shuwei.dish.match.net.UiState
+import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.startActivity
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+
+/**
+ * 组配任务列表页面
+ */
+class TaskActivity : BaseActivity() {
+
+ companion object {
+ const val TAG = "TaskActivity"
+ const val TASK_ITEM = "taskItem"
+ }
+
+ private val binding by lazy { ActivityTaskBinding.inflate(layoutInflater) }
+ private val viewModelV2 by lazy { NetViewModelV2() }
+
+ private val taskList = mutableListOf()
+ private val taskAdapter by lazy {
+ TaskAdapter(taskList).apply {
+ setOnItemClickListener { adapter, view, position ->
+ startActivity {
+ putExtra(TaskDetailActivity.TASK_ITEM, taskList[position])
+ }
+ }
+ }
+ }
+
+ private var currentPage = 1
+ private var keyword: String? = null
+ private var isLoading = false
+ private var hasMore = true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ setHeaderBackground()
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "组配任务"
+ }, rightIconAction = {
+ it.gone()
+ }, backAction = {
+ it.setOnClickListener {
+ finish()
+ }
+ })
+
+ initRecyclerView()
+ initRefreshLayout()
+ initSearchListener()
+ loadTaskList()
+ }
+
+ /**
+ * 初始化 RecyclerView
+ */
+ private fun initRecyclerView() {
+ binding.rvTaskList.layoutManager = LinearLayoutManager(this)
+ binding.rvTaskList.adapter = taskAdapter
+ taskAdapter.setOnItemClickListener { _, _, position ->
+ val item = taskList.getOrNull(position) ?: return@setOnItemClickListener
+ val intent = Intent(this, TaskDetailActivity::class.java).apply {
+ putExtra(TASK_ITEM, item)
+ }
+ startActivity(intent)
+ }
+ }
+
+ /**
+ * 初始化 SmartRefreshLayout 下拉刷新和上拉加载
+ */
+ private fun initRefreshLayout() {
+ binding.refreshLayout.apply {
+ // 下拉刷新
+ setOnRefreshListener {
+ currentPage = 1
+ hasMore = true
+ loadTaskList()
+ }
+ // 上拉加载
+ setOnLoadMoreListener { refreshLayout ->
+ if (isLoading || !hasMore) {
+ refreshLayout.finishLoadMoreWithNoMoreData()
+ return@setOnLoadMoreListener
+ }
+ currentPage++
+ loadTaskList()
+ }
+ }
+ }
+
+ /**
+ * 搜索栏交互
+ */
+ private fun initSearchListener() {
+ binding.ivSearch.clickWithDebounce {
+ performSearch()
+ }
+ binding.etInputKeyword.addOnActionSearchListener {
+ performSearch()
+ }
+ }
+
+ /**
+ * 执行搜索
+ */
+ private fun performSearch() {
+ keyword = binding.etInputKeyword.text.toString().trim()
+ if (keyword.isNullOrBlank()) {
+ toast("请输入搜索关键字")
+ return
+ }
+ currentPage = 1
+ hasMore = true
+ taskList.clear()
+ taskAdapter.notifyDataSetChanged()
+ binding.rvTaskList.visible()
+ binding.tvEmpty.gone()
+ loadTaskList()
+ }
+
+ /**
+ * 加载组配任务列表
+ */
+ private fun loadTaskList() {
+ isLoading = true
+ viewModelV2.getIncompleteComboTasksWithCallback(
+ deviceCode = GlobalData.deviceId,
+ keyword = keyword,
+ pageNum = currentPage,
+ pageSize = 10,
+ onLoading = {
+ if (currentPage == 1) {
+ showLoading("加载中……")
+ }
+ },
+ onResult = onResult@{ state ->
+ dismissLoading()
+ isLoading = false
+ when (state) {
+ is UiState.Success -> {
+ val records = state.data?.records
+ if (currentPage == 1 && records.isNullOrEmpty()) {
+ binding.rvTaskList.gone()
+ binding.tvEmpty.visible()
+ binding.refreshLayout.finishRefresh()
+ binding.refreshLayout.finishLoadMoreWithNoMoreData()
+ return@onResult
+ }
+ if (!records.isNullOrEmpty()) {
+ binding.rvTaskList.visible()
+ binding.tvEmpty.gone()
+ if (currentPage == 1) {
+ taskList.clear()
+ }
+ taskList.addAll(records)
+ taskAdapter.notifyDataSetChanged()
+
+ // 判断是否还有更多数据
+ if (records.size < 10) {
+ hasMore = false
+ binding.refreshLayout.finishLoadMoreWithNoMoreData()
+ }
+ } else {
+ hasMore = false
+ binding.refreshLayout.finishLoadMoreWithNoMoreData()
+ }
+ binding.refreshLayout.finishRefresh()
+ binding.refreshLayout.finishLoadMore()
+ }
+
+ is UiState.Error -> {
+ toast(state.msg)
+ if (currentPage > 1) {
+ currentPage--
+ }
+ if (currentPage == 1 && taskList.isEmpty()) {
+ binding.rvTaskList.gone()
+ binding.tvEmpty.visible()
+ }
+ binding.refreshLayout.finishRefresh()
+ binding.refreshLayout.finishLoadMore(false)
+ }
+
+ else -> {}
+ }
+ }
+ )
+ }
+}
diff --git a/app/src/main/java/com/shuwei/dish/match/ui/TaskDetailActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/TaskDetailActivity.kt
new file mode 100644
index 0000000..baf9cca
--- /dev/null
+++ b/app/src/main/java/com/shuwei/dish/match/ui/TaskDetailActivity.kt
@@ -0,0 +1,192 @@
+package com.shuwei.dish.match.ui
+
+import android.os.Bundle
+import androidx.core.content.IntentCompat
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.shuwei.dish.match.adapter.TaskDetailAdapter
+import com.shuwei.dish.match.base.BaseActivity
+import com.shuwei.dish.match.databinding.ActivityTaskDetailBinding
+import com.shuwei.dish.match.model.NutComboTaskDetailVO
+import com.shuwei.dish.match.model.NutComboTaskVO
+import com.shuwei.dish.match.net.NetViewModelV2
+import com.shuwei.dish.match.net.UiState
+import com.shuwei.dish.match.utils.ext.clickWithDebounce
+import com.shuwei.dish.match.utils.ext.gone
+import com.shuwei.dish.match.utils.ext.toast
+import com.shuwei.dish.match.utils.ext.visible
+import kotlinx.coroutines.launch
+
+/**
+ * 组配任务详情页面
+ */
+class TaskDetailActivity : BaseActivity() {
+
+ companion object {
+ const val TAG = "TaskDetailActivity"
+ const val TASK_ITEM = "taskItem"
+ }
+
+ private val binding by lazy { ActivityTaskDetailBinding.inflate(layoutInflater) }
+ private val viewModelV2 by lazy { NetViewModelV2() }
+
+ private var taskItem: NutComboTaskVO? = null
+ private val itemList = mutableListOf()
+ private val itemAdapter by lazy {
+ TaskDetailAdapter(itemList).apply {
+ setOnItemClickListener { adapter, view, position ->
+ getItem(position) ?: return@setOnItemClickListener
+ itemList.forEachIndexed { index, detail ->
+ detail.isClicked = index == position
+ }
+ notifyDataSetChanged()
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ setHeaderBackground()
+
+ taskItem = IntentCompat.getParcelableExtra(intent, TASK_ITEM, NutComboTaskVO::class.java)
+
+ setTitleBar(titleBarAction = {
+ it.visible()
+ }, titleAction = {
+ it.text = "任务详情"
+ }, rightIconAction = {
+ it.gone()
+ }, backAction = {
+ it.setOnClickListener {
+ finish()
+ }
+ })
+
+ initRecyclerView()
+ initView()
+ loadDetail()
+ }
+
+ /**
+ * 初始化任务概要信息
+ */
+ private fun initView() {
+ taskItem?.let {
+ binding.tvTaskNo.text = "任务编号:${it.taskNo}"
+ binding.tvTargetDish.text = it.targetDish
+ binding.tvSpec.text = it.spec
+ binding.tvPlanDate.text = "计划日期:${it.planDate}"
+ binding.tvPortions.text = "总份数:${it.portions}"
+ binding.tvOwnerName.text = "负责人:${it.ownerName}"
+ binding.tvStatus.text = getStatusText(it.comboStatus)
+
+ // 仅待组配状态显示"开始组配"按钮
+ if (it.comboStatus == 0) {
+ binding.btnStart.visible()
+ binding.btnStart.clickWithDebounce {
+ startComboTask(it.id ?: return@clickWithDebounce)
+ }
+ } else {
+ binding.btnStart.gone()
+ }
+ }
+ binding.btnGetTraceCode.clickWithDebounce {
+
+ }
+ }
+
+ /**
+ * 初始化 RecyclerView
+ */
+ private fun initRecyclerView() {
+ binding.rvItemList.layoutManager = LinearLayoutManager(this)
+ binding.rvItemList.adapter = itemAdapter
+ }
+
+ /**
+ * 加载任务详情(食材清单)
+ */
+ private fun loadDetail() {
+ val taskId = taskItem?.id ?: return
+ viewModelV2.getComboTaskDetailWithCallback(
+ id = taskId,
+ onLoading = {
+ showLoading("加载中……")
+ },
+ onResult = onResult@{ state ->
+ dismissLoading()
+ when (state) {
+ is UiState.Success -> {
+ val detail = state.data
+ if (detail == null) {
+ toast("详情为空")
+ return@onResult
+ }
+ // 更新状态(可能已被其他设备修改)
+ binding.tvStatus.text = getStatusText(detail.comboStatus)
+ if (detail.comboStatus != 0) {
+ binding.btnStart.gone()
+ }
+
+ // 加载食材列表
+ val items = detail.items
+ if (!items.isNullOrEmpty()) {
+ itemList.clear()
+ itemList.addAll(items)
+ itemAdapter.notifyDataSetChanged()
+ } else {
+ toast("该任务无食材信息")
+ }
+ }
+
+ is UiState.Error -> toast(state.msg)
+ else -> {}
+ }
+ }
+ )
+ }
+
+ /**
+ * 开始组配
+ */
+ private fun startComboTask(taskId: Long) {
+ showLoading("正在开始组配……")
+ lifecycleScope.launch {
+ viewModelV2.startComboTask(taskId)
+ }
+ lifecycleScope.launch {
+ viewModelV2.startComboTaskState.collect { state ->
+ when (state) {
+ is UiState.Success -> {
+ dismissLoading()
+ toast("已开始组配")
+ // 刷新详情
+ loadDetail()
+ // 更新本地状态
+ taskItem?.comboStatus = 1
+ }
+
+ is UiState.Error -> {
+ dismissLoading()
+ toast(state.msg)
+ }
+
+ else -> {}
+ }
+ }
+ }
+ }
+
+ /**
+ * 状态文本映射
+ */
+ private fun getStatusText(status: Int?): String {
+ return when (status) {
+ 0 -> "待组配"
+ 1 -> "组配中"
+ 2 -> "已完成"
+ else -> "未知"
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_pack.xml b/app/src/main/res/layout/activity_pack.xml
index 059ebb4..aca6137 100644
--- a/app/src/main/res/layout/activity_pack.xml
+++ b/app/src/main/res/layout/activity_pack.xml
@@ -70,31 +70,22 @@
android:layout_marginStart="30dp"
android:textColor="@color/black"
android:textSize="30sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:maxLength="12"
android:textStyle="bold"
tools:text="豆腐" />
-
-
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_task_detail.xml b/app/src/main/res/layout/activity_task_detail.xml
new file mode 100644
index 0000000..095043b
--- /dev/null
+++ b/app/src/main/res/layout/activity_task_detail.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_food_material.xml b/app/src/main/res/layout/list_item_food_material.xml
index bd715e8..185dc8d 100644
--- a/app/src/main/res/layout/list_item_food_material.xml
+++ b/app/src/main/res/layout/list_item_food_material.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/clBlock"
android:layout_width="match_parent"
- android:layout_height="120dp"
+ android:layout_height="140dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="15dp"
@@ -21,41 +21,41 @@
android:textColor="@color/black"
android:textSize="30sp"
android:textStyle="bold"
- app:layout_constraintBottom_toTopOf="@+id/tvGoodsCode"
+ app:layout_constraintBottom_toTopOf="@+id/tvDishType"
app:layout_constraintEnd_toStartOf="@+id/tvDishWeight"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="雪菜" />
-
-
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvDishType"
+ android:text="溯源码:-" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_task_detail.xml b/app/src/main/res/layout/list_item_task_detail.xml
new file mode 100644
index 0000000..9432390
--- /dev/null
+++ b/app/src/main/res/layout/list_item_task_detail.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+