fix: 进港移库归属更正——删除误建IntImpMove,重新适配到国内进港DomImpMove
设计稿11「进港移库」经确认归属国内进港移库(DomImpMove后端8接口齐全), 此前误判为国际进港并预接了不存在的IntImpMove模块(问题清单#31作废)。 - 删除module_gjj的IntImpMove全套实现(3页面+Bean+Api+菜单+路由+权限串) - GnjMoveStashListActivity双形态适配:待移库/已移库Tab走search/searchMoved 双端点,Tab角标、筛选弹层4项、全选/批量移库复用平板既有链路 - 新增手机专属页:运单详情(Intent传bean零请求)+拍照上传(detail回填 已有照片,modify最小体三字段提交,与平板移交编辑页同链路) - 手机首页入口改挂国内Tab(GnViewModel补通用route跳转,权限串AppDomImpMove) - 内网真实数据双端验证通过;Proxyman A/B:wbNo/awbType生效, fdate/fno/spCode被后端静默忽略(#32)、opId/opDate恒null(#33) - 问题清单更正#31+新增#32~#34,CLAUDE.md/CHANGELOG/api-doc.md同步 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
package com.lukouguoji.gjj.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjj.R
|
||||
import com.lukouguoji.gjj.databinding.ActivityIntImpMoveBinding
|
||||
import com.lukouguoji.gjj.viewModel.IntImpMoveViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.common.ConstantEvent
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import com.lukouguoji.module_base.impl.observe
|
||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||
import com.lukouguoji.module_base.model.ScanModel
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
|
||||
/**
|
||||
* 国际进港-进港移库(5.5 寸手持端专属页面,无平板版本)
|
||||
*
|
||||
* 结构镜像 IntExpMoveActivity(国际出港移库),另有卡片长按「拍照」浮层(设计稿新增交互)。
|
||||
* ⚠️ 后端目前没有 IntImpMove 模块,接口按同名约定预接(问题清单已登记)。
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_MOVE)
|
||||
class IntImpMoveActivity : BaseBindingActivity<ActivityIntImpMoveBinding, IntImpMoveViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_int_imp_move
|
||||
|
||||
override fun viewModelClass() = IntImpMoveViewModel::class.java
|
||||
|
||||
/** 筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("进港移库")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
viewModel.initDictLists()
|
||||
|
||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
// 监听item选择变化事件,更新全选状态
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||
viewModel.onItemCheckChanged()
|
||||
}
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码运单号
|
||||
*/
|
||||
fun scanWaybill() {
|
||||
ScanModel.startScan(this, Constant.RequestCode.WAYBILL)
|
||||
}
|
||||
|
||||
// ==================== 筛选弹层 ====================
|
||||
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/**
|
||||
* 筛选:重置(只清空弹层内条件,不影响 Tab 与顶部搜索框)
|
||||
*/
|
||||
fun resetFilter() {
|
||||
viewModel.flightDate.value = ""
|
||||
viewModel.flightNo.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
viewModel.awbType.value = ""
|
||||
}
|
||||
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
// ==================== 卡片长按「拍照」浮层 ====================
|
||||
|
||||
/** 卡片长按:展开操作浮层(View.OnLongClickListener 要求返回 Boolean) */
|
||||
fun showCardActionPhone(bean: IntImpMoveBean): Boolean {
|
||||
bean.actionMenuVisible.set(true)
|
||||
return true
|
||||
}
|
||||
|
||||
/** 点浮层空白处关闭 */
|
||||
fun hideCardActionPhone(bean: IntImpMoveBean) {
|
||||
bean.actionMenuVisible.set(false)
|
||||
}
|
||||
|
||||
/** 浮层「拍照」→ 拍照上传页 */
|
||||
fun openPhoto(bean: IntImpMoveBean) {
|
||||
bean.actionMenuVisible.set(false)
|
||||
IntImpMovePhotoActivity.start(this, bean)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示移库确认对话框(底部操作条 setOnActionClick 调用)
|
||||
*/
|
||||
fun showMoveConfirmDialog() {
|
||||
val selectedItems = viewModel.getSelectedItems()
|
||||
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请至少选择一条运单")
|
||||
return
|
||||
}
|
||||
|
||||
ConfirmDialogModel(
|
||||
message = "确定要移库选中的 ${selectedItems.size} 条运单吗?",
|
||||
title = "移库确认"
|
||||
) {
|
||||
viewModel.submitMove()
|
||||
}.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码回调
|
||||
*/
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {
|
||||
val code = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.waybillNo.value = code
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
context.startActivity(Intent(context, IntImpMoveActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.lukouguoji.gjj.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.gjj.R
|
||||
import com.lukouguoji.gjj.databinding.ActivityIntImpMoveDetailBinding
|
||||
import com.lukouguoji.gjj.viewModel.IntImpMoveDetailViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
|
||||
/**
|
||||
* 国际进港移库「运单详情」(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 由列表卡片的「查看详情」进入;「异常照片」卡片的加号槽位跳拍照上传页。
|
||||
*/
|
||||
class IntImpMoveDetailActivity :
|
||||
BaseBindingActivity<ActivityIntImpMoveDetailBinding, IntImpMoveDetailViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_int_imp_move_detail
|
||||
override fun viewModelClass() = IntImpMoveDetailViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("运单详情")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
/** 「异常照片」加号槽位 → 拍照上传页 */
|
||||
fun openPhoto() {
|
||||
viewModel.dataBean.value?.let { IntImpMovePhotoActivity.start(this, it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, bean: IntImpMoveBean) {
|
||||
context.startActivity(
|
||||
Intent(context, IntImpMoveDetailActivity::class.java)
|
||||
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.lukouguoji.gjj.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.gjj.R
|
||||
import com.lukouguoji.gjj.databinding.ActivityIntImpMovePhotoBinding
|
||||
import com.lukouguoji.gjj.viewModel.IntImpMovePhotoViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||
|
||||
/**
|
||||
* 国际进港移库「拍照上传」(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 由列表卡片长按浮层「拍照」或运单详情「异常照片」加号槽位进入。
|
||||
*/
|
||||
class IntImpMovePhotoActivity :
|
||||
BaseBindingActivity<ActivityIntImpMovePhotoBinding, IntImpMovePhotoViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_int_imp_move_photo
|
||||
override fun viewModelClass() = IntImpMovePhotoViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("拍照上传")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
viewModel.rv = binding.rv
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, bean: IntImpMoveBean) {
|
||||
context.startActivity(
|
||||
Intent(context, IntImpMovePhotoActivity::class.java)
|
||||
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.lukouguoji.gjj.holder
|
||||
|
||||
import android.view.View
|
||||
import com.lukouguoji.gjj.activity.IntImpMoveActivity
|
||||
import com.lukouguoji.gjj.activity.IntImpMoveDetailActivity
|
||||
import com.lukouguoji.gjj.databinding.ItemIntImpMoveBinding
|
||||
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.ConstantEvent
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 国际进港移库列表项 ViewHolder(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 卡片交互:
|
||||
* · 勾选框点击 → 切换选中并通知 Activity 更新全选/已选计数
|
||||
* · 「查看详情」→ 运单详情页
|
||||
* · 卡片长按 → 「拍照」操作浮层(XML 绑定 activity 回调)
|
||||
*/
|
||||
class IntImpMoveViewHolder(view: View) :
|
||||
BaseViewHolder<IntImpMoveBean, ItemIntImpMoveBinding>(view) {
|
||||
|
||||
override fun onBind(item: Any?, position: Int) {
|
||||
val bean = getItemBean(item) ?: return
|
||||
binding.bean = bean
|
||||
binding.position = position
|
||||
binding.activity = itemView.context as? IntImpMoveActivity
|
||||
|
||||
// 「查看详情」→ 运单详情页
|
||||
binding.llDetail.setOnClickListener {
|
||||
IntImpMoveDetailActivity.start(itemView.context, bean)
|
||||
}
|
||||
|
||||
// 勾选框点击 - 切换选择状态
|
||||
binding.ivIcon.setOnClickListener {
|
||||
bean.checked.set(!bean.checked.get())
|
||||
binding.executePendingBindings()
|
||||
|
||||
GlobalScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).emit("check_changed")
|
||||
}
|
||||
}
|
||||
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.lukouguoji.gjj.viewModel
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.module_base.base.BaseViewModel
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
|
||||
/**
|
||||
* 国际进港移库「运单详情」ViewModel(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 列表项数据已包含详情页所需全部字段,故直接由列表带入,不额外请求接口
|
||||
* (后端暂无 IntImpMove 模块,也没有 detail 接口可查,问题清单已登记)。
|
||||
*/
|
||||
class IntImpMoveDetailViewModel : BaseViewModel() {
|
||||
|
||||
val dataBean = MutableLiveData(IntImpMoveBean())
|
||||
|
||||
fun initOnCreated(intent: Intent) {
|
||||
val json = intent.getStringExtra(Constant.Key.DATA).orEmpty()
|
||||
if (json.isNotEmpty()) {
|
||||
dataBean.value = Gson().fromJson(json, IntImpMoveBean::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package com.lukouguoji.gjj.viewModel
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.gjj.R
|
||||
import com.lukouguoji.module_base.base.BaseViewModel
|
||||
import com.lukouguoji.module_base.bean.FileBean
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.http.net.NetApply
|
||||
import com.lukouguoji.module_base.impl.ImageSelectNewViewHolder
|
||||
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
|
||||
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
||||
import com.lukouguoji.module_base.ktx.noNull
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||
import com.lukouguoji.module_base.util.MediaUtil
|
||||
import com.lukouguoji.module_base.util.UploadUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
|
||||
/**
|
||||
* 国际进港移库「拍照上传」ViewModel(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 图片选择/预览/删除复用 module_base 的 ImageSelectNewViewHolder(末位加号槽位)。
|
||||
* 提交走三字段规范(pic 缩略图 / originalPic 原图 / picNumber 数量)。
|
||||
* ⚠️ 后端暂无 IntImpMove 模块,提交接口按约定预接(问题清单已登记)。
|
||||
*/
|
||||
class IntImpMovePhotoViewModel : BaseViewModel(), IOnItemClickListener {
|
||||
|
||||
val dataBean = MutableLiveData(IntImpMoveBean())
|
||||
|
||||
// 图片网格适配器配置(复用公共图片选择组件)
|
||||
val itemViewHolder = ImageSelectNewViewHolder::class.java
|
||||
val itemLayoutId = com.lukouguoji.module_base.R.layout.item_image_select_new
|
||||
|
||||
var rv: RecyclerView? = null
|
||||
|
||||
fun initOnCreated(intent: Intent) {
|
||||
val json = intent.getStringExtra(Constant.Key.DATA).orEmpty()
|
||||
if (json.isNotEmpty()) {
|
||||
dataBean.value = Gson().fromJson(json, IntImpMoveBean::class.java)
|
||||
}
|
||||
|
||||
// 已有照片回填(pic 缩略图 + originalPic 原图),末位补加号槽位
|
||||
val bean = dataBean.value ?: IntImpMoveBean()
|
||||
val picList = bean.pic.split(",").filter { it.isNotEmpty() }
|
||||
val originalList = bean.originalPic.split(",").filter { it.isNotEmpty() }
|
||||
val images = picList.mapIndexed { index, picUrl ->
|
||||
FileBean(
|
||||
path = MediaUtil.fillUrl(picUrl),
|
||||
url = picUrl,
|
||||
originalPic = MediaUtil.fillUrl(originalList.getOrElse(index) { picUrl })
|
||||
)
|
||||
}
|
||||
rv?.post {
|
||||
rv?.commonAdapter()?.refresh(images + FileBean())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认提交:先补传未上传的本地图片,再按三字段规范提交
|
||||
*/
|
||||
fun submitClick() {
|
||||
(rv?.commonAdapter()?.items ?: emptyList())
|
||||
.asFlow()
|
||||
.map { it as FileBean }
|
||||
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
|
||||
.onEach {
|
||||
val data = UploadUtil.upload(it.path).data
|
||||
// UploadUtil 返回:newName=原图(较大),zipFileName=缩略图(较小)
|
||||
it.url = data?.zipFileName ?: ""
|
||||
it.originalPic = data?.newName ?: ""
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.onStart { showLoading() }
|
||||
.catch {
|
||||
showToast(it.message.noNull("上传图片失败"))
|
||||
dismissLoading()
|
||||
}
|
||||
.onCompletion {
|
||||
launchLoadingCollect({
|
||||
val list = (rv?.commonAdapter()?.items ?: emptyList())
|
||||
.filterIsInstance<FileBean>()
|
||||
.filter { it.path.isNotEmpty() }
|
||||
val bean = dataBean.value!!
|
||||
bean.picNumber = list.size.toString()
|
||||
bean.pic = list.joinToString(",") { MediaUtil.removeUrl(it.url) }
|
||||
bean.originalPic = list.joinToString(",") { MediaUtil.removeUrl(it.originalPic) }
|
||||
|
||||
NetApply.api.submitIntImpMovePic(bean.toRequestBody())
|
||||
}) {
|
||||
onSuccess = {
|
||||
showToast("提交成功")
|
||||
getTopActivity().finish()
|
||||
}
|
||||
onFailed = { _, msg ->
|
||||
showToast(msg.noNull("提交失败"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* 「拍照/上传」按钮:直接唤起图片选择(含拍照入口)
|
||||
*/
|
||||
fun pickClick() {
|
||||
MediaUtil.pickImage(getTopActivity(), maxNum = 9) { results ->
|
||||
val adapter = rv?.commonAdapter() ?: return@pickImage
|
||||
results.forEach { result ->
|
||||
// 在加号槽位(最后一项)之前插入
|
||||
val insertPos = (adapter.items.size - 1).coerceAtLeast(0)
|
||||
adapter.items.add(insertPos, FileBean(path = result.realPath))
|
||||
adapter.notifyItemInserted(insertPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片网格点击回调(长按出删除角标 / 点删除角标移除)
|
||||
*/
|
||||
override fun onItemClick(position: Int, type: Int) {
|
||||
val adapter = rv?.commonAdapter() ?: return
|
||||
val bean = adapter.getItem(position) as? FileBean ?: return
|
||||
when (type) {
|
||||
com.lukouguoji.module_base.R.id.rl -> {
|
||||
if (bean.path.isNotEmpty()) {
|
||||
bean.canDelete.set(!bean.canDelete.get())
|
||||
}
|
||||
}
|
||||
|
||||
com.lukouguoji.module_base.R.id.iv_delete -> {
|
||||
adapter.removeItem(position)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
package com.lukouguoji.gjj.viewModel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.lukouguoji.gjj.R
|
||||
import com.lukouguoji.gjj.holder.IntImpMoveViewHolder
|
||||
import com.lukouguoji.module_base.base.BasePageViewModel
|
||||
import com.lukouguoji.module_base.bean.IntImpMoveBean
|
||||
import com.lukouguoji.module_base.http.net.NetApply
|
||||
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
|
||||
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
import com.lukouguoji.module_base.ktx.launchCollect
|
||||
import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
||||
import com.lukouguoji.module_base.ktx.noNull
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||
import com.lukouguoji.module_base.util.CheckUtil
|
||||
import com.lukouguoji.module_base.util.DictUtils
|
||||
import dev.utils.app.info.KeyValue
|
||||
|
||||
/**
|
||||
* 国际进港移库 ViewModel(5.5 寸手持端专属页面,无平板版本)
|
||||
*
|
||||
* 结构镜像 IntExpMoveViewModel(国际出港移库)。
|
||||
* ⚠️ 后端目前没有 IntImpMove 模块(2026-07-31 api-doc 核对),接口按同名约定预接,
|
||||
* 实机会请求失败(问题清单已登记),后端交付后自动生效。
|
||||
*/
|
||||
class IntImpMoveViewModel : BasePageViewModel(), IOnItemClickListener {
|
||||
|
||||
// ========== 搜索字段(设计稿筛选弹层:航班日期 / 航班号 / 特码 / 运单类型) ==========
|
||||
val flightDate = MutableLiveData("") // 航班日期
|
||||
val flightNo = MutableLiveData("") // 航班号
|
||||
val spCode = MutableLiveData("") // 特码
|
||||
val awbType = MutableLiveData("") // 运单类型
|
||||
val moveState = MutableLiveData("0") // 移库状态(默认「待移库」Tab)
|
||||
val waybillNo = MutableLiveData("") // 运单号
|
||||
|
||||
// ========== 下拉数据 ==========
|
||||
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
val awbTypeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
|
||||
/** 状态 Tab 配置(设计稿只有两个 Tab,无「全部」) */
|
||||
val moveStateTabs = MutableLiveData(
|
||||
listOf(KeyValue("待移库", "0"), KeyValue("已移库", "1"))
|
||||
)
|
||||
|
||||
/** 状态 Tab 角标(与 [moveStateTabs] 等长) */
|
||||
val moveStateCounts = MutableLiveData(listOf("", ""))
|
||||
|
||||
/** 已选数量(底部操作条「已选 N 项」) */
|
||||
val selectedCount = MutableLiveData("0")
|
||||
|
||||
// ========== 全选状态 ==========
|
||||
val isAllChecked = MutableLiveData(false)
|
||||
|
||||
// ========== 适配器配置 ==========
|
||||
val itemViewHolder = IntImpMoveViewHolder::class.java
|
||||
val itemLayoutId = R.layout.item_int_imp_move
|
||||
|
||||
/**
|
||||
* 初始化下拉字典(特码 + 运单类型,type=II 国际进港)
|
||||
*/
|
||||
fun initDictLists() {
|
||||
// flag=1 国际;ieFlag 必须留空——传值后端返回空数组(与既有国际页面口径一致)
|
||||
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") { list ->
|
||||
spCodeList.postValue(listOf(KeyValue("全部", "")) + list)
|
||||
}
|
||||
DictUtils.getWaybillTypeList(type = "II", addAll = true) {
|
||||
awbTypeList.postValue(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun searchClick() {
|
||||
refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选/取消全选
|
||||
*/
|
||||
fun toggleSelectAll() {
|
||||
val adapter = pageModel.rv?.commonAdapter() ?: return
|
||||
val list = adapter.items.filterIsInstance<IntImpMoveBean>()
|
||||
|
||||
CheckUtil.handleAllCheck(list)
|
||||
updateCheckAllStatus()
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新全选状态与已选计数
|
||||
*/
|
||||
fun updateCheckAllStatus() {
|
||||
val adapter = pageModel.rv?.commonAdapter() ?: return
|
||||
val list = adapter.items.filterIsInstance<IntImpMoveBean>()
|
||||
|
||||
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
|
||||
selectedCount.value = list.count { it.checked.get() }.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个item选择变化时调用(从Activity接收事件)
|
||||
*/
|
||||
fun onItemCheckChanged() {
|
||||
updateCheckAllStatus()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选中的运单
|
||||
*/
|
||||
fun getSelectedItems(): List<IntImpMoveBean> {
|
||||
val adapter = pageModel.rv?.commonAdapter() ?: return emptyList()
|
||||
return adapter.items.filterIsInstance<IntImpMoveBean>().filter { it.checked.get() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交移库(在Activity中显示确认对话框后调用)
|
||||
*/
|
||||
fun submitMove() {
|
||||
val selectedItems = getSelectedItems()
|
||||
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请至少选择一条运单")
|
||||
return
|
||||
}
|
||||
|
||||
launchLoadingCollect({ NetApply.api.submitIntImpMove(selectedItems.toRequestBody()) }) {
|
||||
onSuccess = {
|
||||
showToast("移库成功")
|
||||
refresh()
|
||||
}
|
||||
onFailed = { _, msg ->
|
||||
showToast(msg.noNull("移库失败"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
*/
|
||||
override fun getData() {
|
||||
// 构建筛选参数(只传递非空值;参数名按 IntExpMove 同名约定,待后端交付核对)
|
||||
val filterParams = mutableMapOf<String, Any>()
|
||||
|
||||
flightDate.value?.takeIf { it.isNotEmpty() }?.let { filterParams["fdate"] = it }
|
||||
flightNo.value?.takeIf { it.isNotEmpty() }?.let { filterParams["fno"] = it }
|
||||
spCode.value?.takeIf { it.isNotEmpty() }?.let { filterParams["spCode"] = it }
|
||||
awbType.value?.takeIf { it.isNotEmpty() }?.let { filterParams["awbType"] = it }
|
||||
moveState.value?.takeIf { it.isNotEmpty() }?.let { filterParams["moveState"] = it }
|
||||
waybillNo.value?.takeIf { it.isNotEmpty() }?.let { filterParams["wbNo"] = it }
|
||||
|
||||
val listParams = (filterParams + mapOf(
|
||||
"pageNum" to pageModel.page,
|
||||
"pageSize" to pageModel.limit
|
||||
)).toRequestBody()
|
||||
|
||||
launchLoadingCollect({ NetApply.api.getIntImpMoveList(listParams) }) {
|
||||
onSuccess = {
|
||||
pageModel.handleListBean(it) { updateCheckAllStatus() }
|
||||
}
|
||||
}
|
||||
|
||||
// Tab 角标计数(复用统计接口,moveState=0/1 各查一次)
|
||||
loadTabCounts(filterParams)
|
||||
}
|
||||
|
||||
private fun loadTabCounts(filterParams: Map<String, Any>) {
|
||||
listOf("0", "1").forEachIndexed { index, state ->
|
||||
val params = (filterParams + mapOf("moveState" to state)).toRequestBody()
|
||||
launchCollect({ NetApply.api.getIntImpMoveTotal(params) }) {
|
||||
onSuccess = { result ->
|
||||
val count = (result.data?.wbNumber ?: 0).toString()
|
||||
val current = moveStateCounts.value?.toMutableList() ?: mutableListOf("", "")
|
||||
if (index < current.size) {
|
||||
current[index] = count
|
||||
moveStateCounts.value = current
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Item点击事件处理(点击已在ViewHolder中处理)
|
||||
*/
|
||||
override fun onItemClick(position: Int, type: Int) {
|
||||
// 卡片交互均在 ViewHolder / XML 中处理
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user