feat: 国际进港新增提取出库和进港查询功能页面

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 16:14:14 +08:00
parent b994f43bc7
commit 1476f1368a
20 changed files with 1854 additions and 1 deletions

View File

@@ -27,7 +27,7 @@ import com.scwang.smart.refresh.layout.api.RefreshLayout
import java.text.SimpleDateFormat
import java.util.*
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_LIST)
//@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_LIST)
class GjjQueryListActivity : BaseActivity(), View.OnClickListener {
private val currentTitleName = "国际进港查询"

View File

@@ -0,0 +1,57 @@
package com.lukouguoji.gjj.activity
import android.app.Activity
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.ActivityIntImpPickUpDlvBinding
import com.lukouguoji.gjj.viewModel.IntImpPickUpDLVViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
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.router.ARouterConstants
/**
* 国际进港-提取出库
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_PICK_UP_DLV)
class IntImpPickUpDLVActivity :
BaseBindingActivity<ActivityIntImpPickUpDlvBinding, IntImpPickUpDLVViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_pick_up_dlv
override fun viewModelClass() = IntImpPickUpDLVViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港出库")
binding.viewModel = viewModel
// 观察全选状态,更新图标透明度
viewModel.isAllChecked.observe(this) { isAllChecked ->
binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f
}
// 绑定分页
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
// 监听刷新事件
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
// 初始化代理人列表
viewModel.initAgentList()
// 初始加载数据
viewModel.refresh()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
viewModel.onActivityResult(requestCode, resultCode, data)
}
}
}

View File

@@ -0,0 +1,51 @@
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.ActivityIntImpQueryBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryViewModel
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.getLifecycleOwner
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际进港查询列表页
*/
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_LIST)
class IntImpQueryActivity :
BaseBindingActivity<ActivityIntImpQueryBinding, IntImpQueryViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_query
override fun viewModelClass() = IntImpQueryViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("进港查询")
binding.viewModel = viewModel
viewModel.pageModel
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
viewModel.initAgentList()
viewModel.refresh()
}
companion object {
@JvmStatic
fun start(context: Context) {
context.startActivity(Intent(context, IntImpQueryActivity::class.java))
}
}
}

View File

@@ -0,0 +1,87 @@
package com.lukouguoji.gjj.dialog
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.DialogIntImpQueryFilterBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.enums.PopupPosition
import dev.DevUtils
import dev.utils.app.info.KeyValue
/**
* 国际进港查询筛选抽屉
*/
class IntImpQueryFilterDialogModel(
val spCode: MutableLiveData<String>,
val flightNo: MutableLiveData<String>,
val dest: MutableLiveData<String>,
val awbType: MutableLiveData<String>,
val businessType: MutableLiveData<String>,
val goodsCn: MutableLiveData<String>,
private val onConfirm: () -> Unit
) : BaseDialogModel<DialogIntImpQueryFilterBinding>(DIALOG_TYPE_DRAWER) {
val awbTypeList = MutableLiveData(
listOf(
KeyValue("全部", ""),
KeyValue("主单", "1"),
KeyValue("分单", "2")
)
)
val businessTypeList = MutableLiveData(
listOf(
KeyValue("全部", ""),
KeyValue("普货", "1"),
KeyValue("特货", "2")
)
)
override fun layoutId() = R.layout.dialog_int_imp_query_filter
override fun onBuild(builder: XPopup.Builder) {
super.onBuild(builder)
builder.popupPosition(PopupPosition.Right)
val activity = DevUtils.getTopActivity()
val activityWidth = activity.window.decorView.width
builder.maxWidth(activityWidth / 3)
builder.popupWidth(activityWidth / 3)
}
override fun onDialogCreated(context: Context) {
binding.model = this
binding.lifecycleOwner = context as? androidx.lifecycle.LifecycleOwner
val titleColor = Color.parseColor("#666666")
binding.root.findViewById<TextView>(R.id.title_name)?.text = "筛选条件"
binding.root.findViewById<TextView>(R.id.title_name)?.setTextColor(titleColor)
binding.root.findViewById<TextView>(R.id.tool_tv_back)?.setTextColor(titleColor)
binding.root.findViewById<ImageView>(R.id.tool_iv_back)?.imageTintList = ColorStateList.valueOf(titleColor)
binding.root.findViewById<View>(R.id.toolbar)?.setBackgroundColor(Color.WHITE)
binding.root.findViewById<View>(R.id.tool_back)?.setOnClickListener {
dismiss()
}
}
fun onResetClick() {
spCode.value = ""
flightNo.value = ""
dest.value = ""
awbType.value = ""
businessType.value = ""
goodsCn.value = ""
}
fun onConfirmClick() {
dismiss()
onConfirm()
}
}

View File

@@ -0,0 +1,26 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpPickUpDlvBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.IntImpPickUpDLVBean
/**
* 国际进港-提取出库 列表项ViewHolder
*/
class IntImpPickUpDLVViewHolder(view: View) :
BaseViewHolder<IntImpPickUpDLVBean, ItemIntImpPickUpDlvBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
// 点击图标切换选中状态
binding.ivIcon.setOnClickListener {
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
}
}
}

View File

@@ -0,0 +1,19 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpQueryBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.IntImpQueryBean
/**
* 国际进港查询列表ViewHolder
*/
class IntImpQueryViewHolder(view: View) :
BaseViewHolder<IntImpQueryBean, ItemIntImpQueryBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item)!!
binding.bean = bean
binding.executePendingBindings()
}
}

View File

@@ -0,0 +1,183 @@
package com.lukouguoji.gjj.viewModel
import android.app.Activity
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.holder.IntImpPickUpDLVViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.IntImpPickUpDLVBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
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
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/**
* 国际进港-提取出库 ViewModel
*/
class IntImpPickUpDLVViewModel : BasePageViewModel() {
// ========== 搜索条件 ==========
val paymentDateStart = MutableLiveData("") // 缴费日期起
val paymentDateEnd = MutableLiveData("") // 缴费日期止
val agentCode = MutableLiveData("") // 代理人
val wbNo = MutableLiveData("") // 运单号
val pickUpNo = MutableLiveData("") // 提货单号
// ========== 下拉列表数据源 ==========
val agentList = MutableLiveData(listOf(KeyValue("全部", "")))
// ========== 统计信息 ==========
val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
// ========== 全选状态 ==========
val isAllChecked = MutableLiveData(false)
init {
isAllChecked.observeForever { checked ->
val list = pageModel.rv?.commonAdapter()?.items as? List<IntImpPickUpDLVBean>
?: return@observeForever
list.forEach { it.checked.set(checked) }
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
}
// ========== 适配器配置 ==========
val itemViewHolder = IntImpPickUpDLVViewHolder::class.java
val itemLayoutId = R.layout.item_int_imp_pick_up_dlv
/**
* 初始化代理人列表
*/
fun initAgentList() {
launchCollect({ NetApply.api.getIntImpAgentList() }) {
onSuccess = { result ->
val list = mutableListOf(KeyValue("全部", ""))
result.data?.forEach {
list.add(KeyValue(it.name ?: "", it.code ?: ""))
}
agentList.value = list
}
}
}
/**
* 搜索按钮点击
*/
fun searchClick() {
refresh()
}
/**
* 扫码运单号
*/
fun scanWbNo() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL)
}
/**
* 扫码提货单号
*/
fun scanPickUpNo() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.gnj_chu_ku_list)
}
/**
* 全选按钮点击
*/
fun checkAllClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<IntImpPickUpDLVBean> ?: return
val shouldCheckAll = !isAllChecked.value!!
list.forEach { it.checked.set(shouldCheckAll) }
isAllChecked.value = shouldCheckAll
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
/**
* 确认出库
*/
fun confirmOutbound() {
val list = pageModel.rv?.commonAdapter()?.items as? List<IntImpPickUpDLVBean> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要出库的记录")
return
}
launchLoadingCollect({ NetApply.api.confirmIntImpPickUpDLV(selectedItems.toRequestBody()) }) {
onSuccess = {
showToast("确认出库成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
/**
* 获取列表数据
*/
override fun getData() {
val filterParams = mapOf(
"beginDate" to paymentDateStart.value?.ifEmpty { null },
"endDate" to paymentDateEnd.value?.ifEmpty { null },
"agentCode" to agentCode.value?.ifEmpty { null },
"no" to wbNo.value?.ifEmpty { null },
"pkId" to pickUpNo.value?.ifEmpty { null }
)
val listParams = (filterParams + mapOf(
"page" to pageModel.page,
"limit" to pageModel.limit
)).toRequestBody()
val totalParams = filterParams.toRequestBody()
launchLoadingCollect({ NetApply.api.getIntImpPickUpDLVList(listParams) }) {
onSuccess = { result ->
pageModel.handleDataList(result.list)
pageModel.haveMore.postValue((result.pages) > pageModel.page)
}
}
launchCollect({ NetApply.api.getIntImpPickUpDLVTotal(totalParams) }) {
onSuccess = { result ->
val data = result.data
totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
}
}
}
/**
* 处理扫码结果
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
when (requestCode) {
Constant.RequestCode.WAYBILL -> {
wbNo.value = data.getStringExtra(Constant.Result.CODED_CONTENT)
refresh()
}
Constant.RequestCode.gnj_chu_ku_list -> {
pickUpNo.value = data.getStringExtra(Constant.Result.CODED_CONTENT)
refresh()
}
}
}
}
}

View File

@@ -0,0 +1,161 @@
package com.lukouguoji.gjj.viewModel
import android.app.Activity
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.dialog.IntImpQueryFilterDialogModel
import com.lukouguoji.gjj.holder.IntImpQueryViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate
/**
* 国际进港查询ViewModel
*/
class IntImpQueryViewModel : BasePageViewModel() {
// ==================== 搜索条件 ====================
val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate())
val flightDateEnd = MutableLiveData("")
val agentId = MutableLiveData("")
val outStatus = MutableLiveData("")
val waybillNo = MutableLiveData("")
// ==================== 下拉列表 ====================
val agentList = MutableLiveData(listOf(KeyValue("全部", "")))
val outStatusList = MutableLiveData(
listOf(
KeyValue("全部", ""),
KeyValue("未出库", "0"),
KeyValue("已出库", "1")
)
)
// ==================== 适配器配置 ====================
val itemViewHolder = IntImpQueryViewHolder::class.java
val itemLayoutId = R.layout.item_int_imp_query
// ==================== 统计数据 ====================
val totalCount = MutableLiveData("0")
val totalPc = MutableLiveData("0")
val totalWeight = MutableLiveData("0")
// ==================== 筛选条件 ====================
val spCode = MutableLiveData("")
val flightNo = MutableLiveData("")
val dest = MutableLiveData("")
val awbType = MutableLiveData("")
val businessType = MutableLiveData("")
val goodsCn = MutableLiveData("")
///////////////////////////////////////////////////////////////////////////
// 方法区
///////////////////////////////////////////////////////////////////////////
fun waybillScanClick() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL)
}
fun searchClick() {
refresh()
}
fun filterClick() {
val filterDialog = IntImpQueryFilterDialogModel(
spCode = spCode,
flightNo = flightNo,
dest = dest,
awbType = awbType,
businessType = businessType,
goodsCn = goodsCn,
onConfirm = { refresh() }
)
filterDialog.show()
}
override fun getData() {
val listParams = mapOf(
"pageNum" to pageModel.page,
"pageSize" to pageModel.limit,
"beginDate" to flightDateStart.value!!.ifEmpty { null },
"endDate" to flightDateEnd.value!!.ifEmpty { null },
"agentCode" to agentId.value!!.ifEmpty { null },
"outState" to outStatus.value!!.ifEmpty { null },
"wbNo" to waybillNo.value!!.ifEmpty { null },
"spCode" to spCode.value!!.ifEmpty { null },
"fno" to flightNo.value!!.ifEmpty { null },
"dest" to dest.value!!.ifEmpty { null },
"awbType" to awbType.value!!.ifEmpty { null },
"businessType" to businessType.value!!.ifEmpty { null },
"goods" to goodsCn.value!!.ifEmpty { null }
).toRequestBody()
val totalParams = mapOf(
"beginDate" to flightDateStart.value!!.ifEmpty { null },
"endDate" to flightDateEnd.value!!.ifEmpty { null },
"agentCode" to agentId.value!!.ifEmpty { null },
"outState" to outStatus.value!!.ifEmpty { null },
"wbNo" to waybillNo.value!!.ifEmpty { null },
"spCode" to spCode.value!!.ifEmpty { null },
"fno" to flightNo.value!!.ifEmpty { null },
"dest" to dest.value!!.ifEmpty { null },
"awbType" to awbType.value!!.ifEmpty { null },
"businessType" to businessType.value!!.ifEmpty { null },
"goods" to goodsCn.value!!.ifEmpty { null }
).toRequestBody()
launchLoadingCollect({
NetApply.api.getIntImpQueryList(listParams)
}) {
onSuccess = { pageInfo ->
pageModel.handleListBean(pageInfo.toBaseListBean())
}
}
launchCollect({
NetApply.api.getIntImpQueryTotal(totalParams)
}) {
onSuccess = { result ->
val data = result.data
totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
when (requestCode) {
Constant.RequestCode.WAYBILL -> {
waybillNo.value = data.getStringExtra(Constant.Result.CODED_CONTENT)
refresh()
}
}
}
}
fun initAgentList() {
launchCollect({
NetApply.api.getIntImpAgentList()
}) {
onSuccess = { result ->
val list = mutableListOf(KeyValue("全部", ""))
result.data?.forEach {
list.add(KeyValue(it.name ?: "", it.code ?: ""))
}
agentList.value = list
}
}
}
}