From 9c4588e47e7e1bbb1e2f617ee07fa739c8291cf0 Mon Sep 17 00:00:00 2001 From: YANG JIANKUAN Date: Thu, 23 Jul 2026 12:25:30 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=9B=BD=E9=99=85=E5=87=BA?= =?UTF-8?q?=E6=B8=AF=E6=9F=A5=E8=AF=A2=E7=AD=9B=E9=80=89=E6=94=B9=E5=86=85?= =?UTF-8?q?=E5=B5=8C=E9=9D=A2=E6=9D=BF=E5=B9=B6=E5=AF=B9=E9=BD=90=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E8=BF=9B=E6=B8=AF=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 筛选由XPopup全屏抽屉改为内嵌滑动面板,不再遮挡标题栏 - 有筛选条件时筛选按钮显示红点(hasFilter) - 航班号锁定大写字母数字、目的港锁定大写字母 - 运单类型走字典接口(type=IO 国际出港),修正原错误的"10" - 修复PadDataLayoutNew重置后Spinner UI未清空(国际进港同组件一并修复) Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 2 +- .../ui/weight/data/layout/PadDataLayoutNew.kt | 3 +- .../gjc/activity/GjcQueryActivity.kt | 178 +++++--- .../gjc/dialog/GjcQueryFilterDialogModel.kt | 101 ----- .../gjc/viewModel/GjcQueryViewModel.kt | 91 +++- .../src/main/res/drawable/bg_red_dot.xml | 5 + .../main/res/layout/activity_gjc_query.xml | 424 ++++++++++-------- ...filter.xml => layout_gjc_query_filter.xml} | 329 +++++++------- 8 files changed, 614 insertions(+), 519 deletions(-) delete mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/dialog/GjcQueryFilterDialogModel.kt create mode 100644 module_gjc/src/main/res/drawable/bg_red_dot.xml rename module_gjc/src/main/res/layout/{dialog_gjc_query_filter.xml => layout_gjc_query_filter.xml} (72%) diff --git a/CLAUDE.md b/CLAUDE.md index 946682c..fd8b34d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -719,7 +719,7 @@ XxxDialogModel(onConfirm = { refresh() }).show() |------|------|------|------| | 底部 | `DIALOG_TYPE_BOTTOM` | 操作选项 | 默认类型 | | 中间 | `DIALOG_TYPE_CENTER` | 确认框、表单输入 | `ConfirmDialogModel` | -| 抽屉 | `DIALOG_TYPE_DRAWER` | 筛选条件 | `GjcQueryFilterDialogModel` | +| 抽屉 | `DIALOG_TYPE_DRAWER` | 通用右侧抽屉 | 见下方模板 | | 全屏 | `DIALOG_TYPE_FULL` | 列表展示 | `NoticeMessageDialogModel` | ### 抽屉弹窗(筛选场景) diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/PadDataLayoutNew.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/PadDataLayoutNew.kt index c064c3b..54ac9e7 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/PadDataLayoutNew.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/PadDataLayoutNew.kt @@ -278,7 +278,8 @@ class PadDataLayoutNew : FrameLayout { tvSpinner.text = list.find { b -> b.value == value }?.key ?: value - if (value.isNotEmpty() && list.isNotEmpty()) { + // 同步 Spinner 选中项(含 value 为空时重置到对应项,如"全部"),修复重置后 UI 不清空的问题 + if (list.isNotEmpty()) { val index = list.indexOfFirst { b -> b.value == value } if (index >= 0) { spinner.post { diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcQueryActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcQueryActivity.kt index aecf0f8..37918c2 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcQueryActivity.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcQueryActivity.kt @@ -1,56 +1,122 @@ -package com.lukouguoji.gjc.activity - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import com.alibaba.android.arouter.facade.annotation.Route -import com.lukouguoji.gjc.R -import com.lukouguoji.gjc.databinding.ActivityGjcQueryBinding -import com.lukouguoji.gjc.viewModel.GjcQueryViewModel -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_GJC_QUERY_LIST) -class GjcQueryActivity : - BaseBindingActivity() { - - override fun layoutId() = R.layout.activity_gjc_query - - override fun viewModelClass() = GjcQueryViewModel::class.java - - override fun initOnCreate(savedInstanceState: Bundle?) { - setBackArrow("国际出港查询") - - binding.viewModel = viewModel - - // 绑定分页逻辑 - viewModel.pageModel - .bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner()) - - // 监听刷新事件 - FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { - viewModel.refresh() - } - - // 初始化代理列表 - viewModel.initAgentList() - - // 初始加载 - viewModel.refresh() - } - - companion object { - @JvmStatic - fun start(context: Context) { - val starter = Intent(context, GjcQueryActivity::class.java) - context.startActivity(starter) - } - } -} +package com.lukouguoji.gjc.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.widget.FrameLayout +import com.alibaba.android.arouter.facade.annotation.Route +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.databinding.ActivityGjcQueryBinding +import com.lukouguoji.gjc.viewModel.GjcQueryViewModel +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.ktx.setUpperCaseAlphanumericFilter +import com.lukouguoji.module_base.ktx.setUpperCaseLetterFilter +import com.lukouguoji.module_base.router.ARouterConstants + +/** + * 国际出港查询列表页 + */ +@Route(path = ARouterConstants.ACTIVITY_URL_GJC_QUERY_LIST) +class GjcQueryActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_gjc_query + + override fun viewModelClass() = GjcQueryViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("国际出港查询") + + binding.viewModel = viewModel + + // 绑定分页逻辑 + viewModel.pageModel + .bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner()) + + // 监听刷新事件 + FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { + viewModel.refresh() + } + + // 初始化代理列表 & 筛选下拉列表 + viewModel.initAgentList() + viewModel.initFilterLists() + + // 观察筛选面板显示状态 + viewModel.filterVisible.observe(this) { visible -> + if (visible) showFilterPanel() else hideFilterPanel() + } + + // 航班号:大写字母+数字 + binding.filterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter() + // 目的港:仅大写字母 + binding.filterPanel.filterDest.et.setUpperCaseLetterFilter() + + // 初始加载 + viewModel.refresh() + } + + private fun showFilterPanel() { + val panel = binding.filterPanel.root + val overlay = binding.filterOverlay + val panelWidth = window.decorView.width / 3 + + panel.layoutParams = (panel.layoutParams as FrameLayout.LayoutParams).apply { + width = panelWidth + gravity = Gravity.END + } + + // 先 INVISIBLE 完成测量,避免第一次显示时闪烁 + panel.visibility = View.INVISIBLE + panel.translationX = panelWidth.toFloat() + overlay.visibility = View.VISIBLE + overlay.alpha = 0f + + panel.post { + panel.visibility = View.VISIBLE + panel.animate().translationX(0f).setDuration(250).start() + overlay.animate().alpha(1f).setDuration(250).start() + } + } + + private fun hideFilterPanel() { + val panel = binding.filterPanel.root + val overlay = binding.filterOverlay + + if (panel.visibility != View.VISIBLE) return + + panel.animate() + .translationX(panel.width.toFloat()) + .setDuration(250) + .withEndAction { panel.visibility = View.GONE } + .start() + + overlay.animate() + .alpha(0f) + .setDuration(250) + .withEndAction { overlay.visibility = View.GONE } + .start() + } + + override fun onBackPressed() { + if (viewModel.filterVisible.value == true) { + viewModel.closeFilter() + } else { + super.onBackPressed() + } + } + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, GjcQueryActivity::class.java) + context.startActivity(starter) + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/GjcQueryFilterDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/GjcQueryFilterDialogModel.kt deleted file mode 100644 index da00000..0000000 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/GjcQueryFilterDialogModel.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.lukouguoji.gjc.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.gjc.R -import com.lukouguoji.gjc.databinding.DialogGjcQueryFilterBinding -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 GjcQueryFilterDialogModel( - val spCode: MutableLiveData, // 特码 - val flightNo: MutableLiveData, // 航班号 - val dest: MutableLiveData, // 目的港 - val awbType: MutableLiveData, // 运单类型 - val businessType: MutableLiveData, // 业务类型 - val goodsCn: MutableLiveData, // 品名(中) - private val onConfirm: () -> Unit -) : BaseDialogModel(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_gjc_query_filter - - override fun onBuild(builder: XPopup.Builder) { - super.onBuild(builder) - // 设置从右边弹出 - builder.popupPosition(PopupPosition.Right) - - // 设置抽屉宽度为 Activity contentView 宽度的1/3(横屏长边) - 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(R.id.title_name)?.text = "筛选条件" - binding.root.findViewById(R.id.title_name)?.setTextColor(titleColor) - binding.root.findViewById(R.id.tool_tv_back)?.setTextColor(titleColor) - binding.root.findViewById(R.id.tool_iv_back)?.imageTintList = ColorStateList.valueOf(titleColor) - binding.root.findViewById(R.id.toolbar)?.setBackgroundColor(Color.WHITE) - - // 返回按钮 - binding.root.findViewById(R.id.tool_back)?.setOnClickListener { - dismiss() - } - } - - /** - * 重置筛选条件 - */ - fun onResetClick() { - spCode.value = "" - flightNo.value = "" - dest.value = "" - awbType.value = "" - businessType.value = "" - goodsCn.value = "" - } - - /** - * 确认筛选 - */ - fun onConfirmClick() { - dismiss() - onConfirm() - } -} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcQueryViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcQueryViewModel.kt index a6ed8fa..69034e8 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcQueryViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcQueryViewModel.kt @@ -2,9 +2,9 @@ package com.lukouguoji.gjc.viewModel import android.app.Activity import android.content.Intent +import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import com.lukouguoji.gjc.R -import com.lukouguoji.gjc.dialog.GjcQueryFilterDialogModel import com.lukouguoji.gjc.holder.GjcQueryViewHolder import com.lukouguoji.module_base.base.BasePageViewModel import com.lukouguoji.module_base.common.Constant @@ -14,6 +14,7 @@ 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 com.lukouguoji.module_base.util.DictUtils import dev.utils.app.info.KeyValue import dev.utils.common.DateUtils import com.lukouguoji.module_base.ktx.formatDate @@ -52,7 +53,22 @@ class GjcQueryViewModel : BasePageViewModel() { val totalPc = MutableLiveData("0") // 总件数 val totalWeight = MutableLiveData("0") // 总重量 - // ==================== 筛选条件(预留)==================== + // ==================== 筛选面板 ==================== + val filterVisible = MutableLiveData(false) + + // 运单类型列表(字典接口 typeCode/awb,type=IO 国际出港) + val awbTypeList = MutableLiveData>(emptyList()) + + // 业务类型列表 + val businessTypeList = MutableLiveData( + listOf( + KeyValue("全部", ""), + KeyValue("普货", "1"), + KeyValue("特货", "2") + ) + ) + + // ==================== 筛选条件 ==================== val spCode = MutableLiveData("") // 特码 val flightNo = MutableLiveData("") // 航班号 val dest = MutableLiveData("") // 目的港 @@ -60,6 +76,20 @@ class GjcQueryViewModel : BasePageViewModel() { val businessType = MutableLiveData("") // 业务类型 val goodsCn = MutableLiveData("") // 品名(中) + // 是否有筛选条件(任意一个非空则为 true,用于筛选按钮红点) + val hasFilter: MediatorLiveData = MediatorLiveData().apply { + val update = { _: Any? -> + value = listOf(spCode, flightNo, dest, awbType, businessType, goodsCn) + .any { !it.value.isNullOrEmpty() } + } + addSource(spCode, update) + addSource(flightNo, update) + addSource(dest, update) + addSource(awbType, update) + addSource(businessType, update) + addSource(goodsCn, update) + } + /////////////////////////////////////////////////////////////////////////// // 方法区 /////////////////////////////////////////////////////////////////////////// @@ -79,19 +109,50 @@ class GjcQueryViewModel : BasePageViewModel() { } /** - * 筛选按钮点击 + * 筛选按钮点击 - 打开筛选面板 */ fun filterClick() { - val filterDialog = GjcQueryFilterDialogModel( - spCode = spCode, - flightNo = flightNo, - dest = dest, - awbType = awbType, - businessType = businessType, - goodsCn = goodsCn, - onConfirm = { refresh() } - ) - filterDialog.show() + filterVisible.value = true + } + + /** + * 关闭筛选面板 + */ + fun closeFilter() { + filterVisible.value = false + } + + /** + * 重置筛选条件 + */ + fun resetFilter() { + spCode.value = "" + flightNo.value = "" + dest.value = "" + awbType.value = "" + businessType.value = "" + goodsCn.value = "" + } + + /** + * 确认筛选 - 关闭面板并刷新 + */ + fun confirmFilter() { + filterVisible.value = false + refresh() + } + + /** + * 初始化筛选下拉列表(运单类型从字典接口获取,type=IO 国际出港) + */ + fun initFilterLists() { + DictUtils.getWaybillTypeList( + type = Constant.businessType.IO, + addAll = true, + checkedValue = awbType.value + ) { + awbTypeList.postValue(it) + } } /** @@ -110,7 +171,7 @@ class GjcQueryViewModel : BasePageViewModel() { "wbNo" to waybillNo.value!!.ifEmpty { null }, // 筛选条件(暂未使用) "spCode" to spCode.value!!.ifEmpty { null }, - "flightNo" to flightNo.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 }, @@ -126,7 +187,7 @@ class GjcQueryViewModel : BasePageViewModel() { "wbNo" to waybillNo.value!!.ifEmpty { null }, // 筛选条件 "spCode" to spCode.value!!.ifEmpty { null }, - "flightNo" to flightNo.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 }, diff --git a/module_gjc/src/main/res/drawable/bg_red_dot.xml b/module_gjc/src/main/res/drawable/bg_red_dot.xml new file mode 100644 index 0000000..3291181 --- /dev/null +++ b/module_gjc/src/main/res/drawable/bg_red_dot.xml @@ -0,0 +1,5 @@ + + + + diff --git a/module_gjc/src/main/res/layout/activity_gjc_query.xml b/module_gjc/src/main/res/layout/activity_gjc_query.xml index 88a536a..1b60f63 100644 --- a/module_gjc/src/main/res/layout/activity_gjc_query.xml +++ b/module_gjc/src/main/res/layout/activity_gjc_query.xml @@ -1,187 +1,237 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/dialog_gjc_query_filter.xml b/module_gjc/src/main/res/layout/layout_gjc_query_filter.xml similarity index 72% rename from module_gjc/src/main/res/layout/dialog_gjc_query_filter.xml rename to module_gjc/src/main/res/layout/layout_gjc_query_filter.xml index 0239184..69adf3b 100644 --- a/module_gjc/src/main/res/layout/dialog_gjc_query_filter.xml +++ b/module_gjc/src/main/res/layout/layout_gjc_query_filter.xml @@ -1,158 +1,171 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +