feat: 国际进港查询详情页面(三Tab:运单/仓库/库位信息)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 11:34:20 +08:00
parent edb1f576b7
commit baaa9c5615
21 changed files with 1417 additions and 3 deletions

View File

@@ -24,7 +24,7 @@ import com.lukouguoji.module_base.BaseActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO)
// @Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO) // 已替换为 IntImpQueryDetailsActivity
class GjjQueryInfoActivity : BaseActivity(), View.OnClickListener {
private lateinit var viewModel: GjjQueryInfoViewModel

View File

@@ -11,6 +11,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
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.getLifecycleOwner
import com.lukouguoji.module_base.router.ARouterConstants
@@ -33,6 +34,9 @@ class IntImpQueryActivity :
viewModel.pageModel
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
// 注册列表项点击事件
binding.rv.addOnItemClickListener(viewModel)
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpQueryDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.base.CustomVP2Adapter
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际进港查询详情页面
*/
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO)
class IntImpQueryDetailsActivity :
BaseBindingActivity<ActivityIntImpQueryDetailsBinding, IntImpQueryDetailsViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_query_details
override fun viewModelClass() = IntImpQueryDetailsViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港查询详情")
binding.viewModel = viewModel
// 初始化ViewModel(传入maWbId)
viewModel.initOnCreated(intent)
// 配置ViewPager2
binding.vp.adapter = CustomVP2Adapter(
viewModel.fragmentList,
supportFragmentManager,
lifecycle
)
binding.vp.isUserInputEnabled = false // 禁用滑动
binding.vp.offscreenPageLimit = 3 // 预加载3个Fragment
// 监听Tab索引变化,切换Fragment
viewModel.currentTab.observe(this) {
binding.vp.setCurrentItem(it, false)
}
// 加载详情数据
viewModel.loadDetails()
}
companion object {
@JvmStatic
fun start(context: Context, maWbId: Long?) {
val starter = Intent(context, IntImpQueryDetailsActivity::class.java)
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "")
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,89 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryStorageBinding
import com.lukouguoji.gjj.holder.IntImpQueryStorageViewHolder
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.bean.GjjStorageUse
import com.lukouguoji.module_base.http.net.NetApply
/**
* 国际进港查询详情 - 库位信息Fragment
*/
class IntImpQueryStorageFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryStorageBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
private lateinit var adapter: CommonAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_storage,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
initRecyclerView()
observeData()
return binding.root
}
private fun initRecyclerView() {
adapter = CommonAdapter(
requireContext(),
R.layout.item_int_imp_query_storage,
IntImpQueryStorageViewHolder::class.java
)
binding.rvStorageList.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = this@IntImpQueryStorageFragment.adapter
}
}
private fun observeData() {
viewModel.storageUseList.observe(viewLifecycleOwner) { mapList ->
if (mapList.isEmpty()) {
binding.rvStorageList.visibility = View.GONE
binding.llEmpty.visibility = View.VISIBLE
} else {
val beanList = mapList.map { map ->
try {
val json = NetApply.gson.toJson(map)
NetApply.gson.fromJson(json, GjjStorageUse::class.java)
} catch (e: Exception) {
e.printStackTrace()
GjjStorageUse()
}
}
binding.rvStorageList.visibility = View.VISIBLE
binding.llEmpty.visibility = View.GONE
adapter.refresh(beanList)
}
}
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryStorageFragment().apply {
viewModel = vm
}
}
}

View File

@@ -0,0 +1,89 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryWarehouseBinding
import com.lukouguoji.gjj.holder.IntImpQueryWarehouseViewHolder
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.bean.GjjWarehouse
import com.lukouguoji.module_base.http.net.NetApply
/**
* 国际进港查询详情 - 仓库信息Fragment
*/
class IntImpQueryWarehouseFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryWarehouseBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
private lateinit var adapter: CommonAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_warehouse,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
initRecyclerView()
observeData()
return binding.root
}
private fun initRecyclerView() {
adapter = CommonAdapter(
requireContext(),
R.layout.item_int_imp_query_warehouse,
IntImpQueryWarehouseViewHolder::class.java
)
binding.rvWarehouseList.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = this@IntImpQueryWarehouseFragment.adapter
}
}
private fun observeData() {
viewModel.warehouseList.observe(viewLifecycleOwner) { mapList ->
if (mapList.isEmpty()) {
binding.rvWarehouseList.visibility = View.GONE
binding.llEmpty.visibility = View.VISIBLE
} else {
val beanList = mapList.map { map ->
try {
val json = NetApply.gson.toJson(map)
NetApply.gson.fromJson(json, GjjWarehouse::class.java)
} catch (e: Exception) {
e.printStackTrace()
GjjWarehouse()
}
}
binding.rvWarehouseList.visibility = View.VISIBLE
binding.llEmpty.visibility = View.GONE
adapter.refresh(beanList)
}
}
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryWarehouseFragment().apply {
viewModel = vm
}
}
}

View File

@@ -0,0 +1,44 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryWaybillBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
/**
* 国际进港查询详情 - 运单信息Fragment
*/
class IntImpQueryWaybillFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryWaybillBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_waybill,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = viewModel
return binding.root
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryWaybillFragment().apply {
viewModel = vm
}
}
}

View File

@@ -0,0 +1,20 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpQueryStorageBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjStorageUse
/**
* 国际进港查询详情-库位信息ViewHolder
*/
class IntImpQueryStorageViewHolder(view: View) :
BaseViewHolder<GjjStorageUse, ItemIntImpQueryStorageBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
}
}

View File

@@ -15,5 +15,8 @@ class IntImpQueryViewHolder(view: View) :
val bean = getItemBean(item)!!
binding.bean = bean
binding.executePendingBindings()
// 注册整行点击事件
notifyItemClick(position, binding.ll)
}
}

View File

@@ -0,0 +1,20 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpQueryWarehouseBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjWarehouse
/**
* 国际进港查询详情-仓库信息ViewHolder
*/
class IntImpQueryWarehouseViewHolder(view: View) :
BaseViewHolder<GjjWarehouse, ItemIntImpQueryWarehouseBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
}
}

View File

@@ -0,0 +1,129 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.fragment.IntImpQueryStorageFragment
import com.lukouguoji.gjj.fragment.IntImpQueryWarehouseFragment
import com.lukouguoji.gjj.fragment.IntImpQueryWaybillFragment
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
/**
* 国际进港查询详情-ViewModel
*/
class IntImpQueryDetailsViewModel : BaseViewModel() {
// ==================== 基础数据 ====================
var maWbId: String = "" // 运单主键ID
// ==================== Tab管理 ====================
val currentTab = MutableLiveData(0) // 当前Tab索引 (0/1/2)
// ==================== 详情数据 ====================
val detailData = MutableLiveData<Map<String, Any>>(emptyMap())
// 运单信息 (maWb)
val maWbData = MutableLiveData<Map<String, Any>>(emptyMap())
// 仓库列表 (warehouseList)
val warehouseList = MutableLiveData<List<Map<String, Any>>>(emptyList())
// 库位列表 (storageUseList)
val storageUseList = MutableLiveData<List<Map<String, Any>>>(emptyList())
// ==================== Fragment列表 ====================
val fragmentList by lazy {
listOf(
IntImpQueryWaybillFragment.newInstance(this), // 运单信息
IntImpQueryWarehouseFragment.newInstance(this), // 仓库信息
IntImpQueryStorageFragment.newInstance(this) // 库位信息
)
}
// ==================== 方法区 ====================
/**
* 初始化(从Intent获取maWbId)
*/
fun initOnCreated(intent: Intent) {
maWbId = intent.getStringExtra(Constant.Key.ID) ?: ""
}
/**
* Tab点击事件
*/
fun onTabClick(index: Int) {
currentTab.value = index
}
/**
* 加载详情数据
*/
fun loadDetails() {
if (maWbId.isEmpty()) {
showToast("运单ID为空")
return
}
val maWbIdValue = maWbId.toLongOrNull()
if (maWbIdValue == null) {
showToast("运单ID格式错误")
return
}
val params = mapOf("maWbId" to maWbIdValue).toRequestBody()
launchLoadingCollect({ NetApply.api.getIntImpQueryDetails(params) }) {
onSuccess = { result ->
val data = result.data ?: emptyMap()
detailData.value = data
// 解析 maWb 对象
@Suppress("UNCHECKED_CAST")
val maWb = data["maWb"] as? Map<String, Any> ?: emptyMap()
// 合并数据并添加组合字段
val mergedData = mutableMapOf<String, Any>()
mergedData.putAll(maWb)
// 添加组合字段: wbNo = prefix + no
val prefix = maWb["prefix"] as? String ?: ""
val no = maWb["no"] as? String ?: ""
if (prefix.isNotEmpty() || no.isNotEmpty()) {
mergedData["wbNo"] = "$prefix$no"
}
// 锁定状态转中文
val lockState = maWb["lockState"]
if (lockState != null) {
val lockStateInt = when (lockState) {
is Double -> lockState.toInt()
is Int -> lockState
else -> null
}
mergedData["lockStateText"] = when (lockStateInt) {
0 -> "未锁定"
1 -> "已锁定"
else -> ""
}
}
maWbData.value = mergedData
// 解析 warehouseList 列表
@Suppress("UNCHECKED_CAST")
val whList = data["warehouseList"] as? List<Map<String, Any>> ?: emptyList()
warehouseList.value = whList
// 解析 storageUseList 列表
@Suppress("UNCHECKED_CAST")
val suList = data["storageUseList"] as? List<Map<String, Any>> ?: emptyList()
storageUseList.value = suList
}
}
}
}

View File

@@ -6,9 +6,13 @@ import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.dialog.IntImpQueryFilterDialogModel
import com.lukouguoji.gjj.holder.IntImpQueryViewHolder
import com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.IntImpQueryBean
import com.lukouguoji.module_base.common.Constant
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.showToast
@@ -21,7 +25,7 @@ import com.lukouguoji.module_base.ktx.formatDate
/**
* 国际进港查询ViewModel
*/
class IntImpQueryViewModel : BasePageViewModel() {
class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
// ==================== 搜索条件 ====================
val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate())
@@ -145,6 +149,12 @@ class IntImpQueryViewModel : BasePageViewModel() {
}
}
override fun onItemClick(position: Int, type: Int) {
val list = pageModel.rv?.commonAdapter()?.items as? List<IntImpQueryBean> ?: return
val bean = list.getOrNull(position) ?: return
IntImpQueryDetailsActivity.start(getTopActivity(), bean.maWbId)
}
fun initAgentList() {
launchCollect({
NetApply.api.getIntImpAgentList()