From 3fe66b513f3d339e43073460a1389a566ba6710d Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Tue, 2 Jun 2026 14:21:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(task):=20=E6=B7=BB=E5=8A=A0=E7=BB=84?= =?UTF-8?q?=E9=85=8D=E4=BB=BB=E5=8A=A1=E5=8A=9F=E8=83=BD=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增组配任务列表页面和详情页面 - 实现组配任务查询、搜索和分页功能 - 添加组配任务详情展示和状态管理 - 集成溯源码获取功能到任务详情页面 - 添加组配任务相关的API接口定义和实现 - 创建组配任务数据模型和适配器 - 在设置页面添加组配任务入口 - 重构食材物料列表项布局和显示逻辑 - 更新应用启动时的设备ID初始化逻辑 - 生成配比秤终端接口文档 --- app/src/main/AndroidManifest.xml | 10 + .../shuwei/dish/match/adapter/TaskAdapter.kt | 53 +++++ .../dish/match/adapter/TaskDetailAdapter.kt | 76 +++++++ .../com/shuwei/dish/match/base/BaseApp.kt | 3 + .../dish/match/model/NutritionModels.kt | 55 +++++ .../shuwei/dish/match/model/SettingItem.kt | 1 + .../com/shuwei/dish/match/net/ApiServiceV2.kt | 25 +++ .../shuwei/dish/match/net/NetViewModelV2.kt | 35 +++ .../dish/match/net/RemoteRepositoryV2.kt | 15 ++ .../com/shuwei/dish/match/ui/PackActivity.kt | 13 +- .../shuwei/dish/match/ui/SettingActivity.kt | 6 + .../com/shuwei/dish/match/ui/TaskActivity.kt | 207 ++++++++++++++++++ .../dish/match/ui/TaskDetailActivity.kt | 192 ++++++++++++++++ app/src/main/res/layout/activity_pack.xml | 33 +-- app/src/main/res/layout/activity_task.xml | 104 +++++++++ .../main/res/layout/activity_task_detail.xml | 163 ++++++++++++++ .../res/layout/list_item_food_material.xml | 40 ++-- app/src/main/res/layout/list_item_task.xml | 92 ++++++++ .../main/res/layout/list_item_task_detail.xml | 80 +++++++ 19 files changed, 1167 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/com/shuwei/dish/match/adapter/TaskAdapter.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/adapter/TaskDetailAdapter.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/ui/TaskActivity.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/ui/TaskDetailActivity.kt create mode 100644 app/src/main/res/layout/activity_task.xml create mode 100644 app/src/main/res/layout/activity_task_detail.xml create mode 100644 app/src/main/res/layout/list_item_task.xml create mode 100644 app/src/main/res/layout/list_item_task_detail.xml 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 @@ + + + + + + + + + + + + + + + + + + + + + + +