diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryConfig.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryConfig.kt
new file mode 100644
index 0000000..f764c49
--- /dev/null
+++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryConfig.kt
@@ -0,0 +1,48 @@
+package com.lukouguoji.module_base.ui.weight.data.layout
+
+/**
+ * 自动查询配置类
+ * 用于在 XML 中配置 PadDataLayoutNew 的自动查询功能
+ *
+ * 使用示例:
+ * ```xml
+ *
+ * ```
+ */
+data class AutoQueryConfig(
+ /** 是否启用自动查询 */
+ var enabled: Boolean = false,
+
+ /** 查询接口地址(必需) */
+ var url: String = "",
+
+ /** 查询参数的 key 名称(默认 "value") */
+ var paramKey: String = "value",
+
+ /** 触发查询的最小长度(默认 4) */
+ var minLength: Int = 4,
+
+ /** 触发查询的最大长度(默认 8) */
+ var maxLength: Int = 8,
+
+ /** 弹框标题(默认 "请选择") */
+ var title: String = "请选择",
+
+ /** 防抖延迟(毫秒,默认 300ms) */
+ var debounceMillis: Long = 300L
+) {
+ /**
+ * 验证配置是否有效
+ * @return true 如果配置有效,false 否则
+ */
+ fun isValid(): Boolean {
+ return enabled && url.isNotBlank() && minLength > 0 && maxLength >= minLength
+ }
+}
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryManager.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryManager.kt
new file mode 100644
index 0000000..f95b662
--- /dev/null
+++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/AutoQueryManager.kt
@@ -0,0 +1,175 @@
+package com.lukouguoji.module_base.ui.weight.data.layout
+
+import android.text.Editable
+import android.text.TextWatcher
+import androidx.lifecycle.ViewTreeLifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import com.alibaba.fastjson.JSONArray
+import com.lukouguoji.module_base.http.net.NetApply
+import com.lukouguoji.module_base.ktx.getActivity
+import com.lukouguoji.module_base.ktx.launchCollect
+import com.lukouguoji.module_base.ktx.toRequestBody
+import com.lukouguoji.module_base.ktx.toJson
+import com.lukouguoji.module_base.util.Common
+import kotlinx.coroutines.*
+
+/**
+ * 自动查询管理器
+ * 负责处理输入监听、防抖、查询请求、结果处理
+ *
+ * 功能:
+ * 1. 监听 EditText 输入变化
+ * 2. 防抖延迟(避免频繁请求)
+ * 3. 防重复查询(相同值不重复请求)
+ * 4. 调用接口查询数据
+ * 5. 处理查询结果(单条填充、多条弹框)
+ * 6. 自动管理协程生命周期
+ */
+class AutoQueryManager(
+ private val layout: PadDataLayoutNew,
+ private val config: AutoQueryConfig
+) {
+
+ /** 协程作用域(从 ViewTree 获取) */
+ private var scope: CoroutineScope? = null
+
+ /** 上次查询的值(防重复查询) */
+ private var lastQueriedValue: String = ""
+
+ /** 防抖任务 */
+ private var debounceJob: Job? = null
+
+ /** 文本监听器 */
+ private var textWatcher: TextWatcher? = null
+
+ /**
+ * 绑定到视图(添加文本监听)
+ */
+ fun attach() {
+ // 获取协程作用域(从 ViewTree 获取 LifecycleOwner)
+ val lifecycleOwner = ViewTreeLifecycleOwner.get(layout)
+ if (lifecycleOwner == null) {
+ // 延迟绑定(等待 ViewTree 附加)
+ layout.post { attach() }
+ return
+ }
+ scope = lifecycleOwner.lifecycleScope
+
+ // 添加文本监听
+ textWatcher = object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(s: Editable?) {
+ val text = s?.toString() ?: ""
+ handleTextChanged(text)
+ }
+ }
+
+ layout.et.addTextChangedListener(textWatcher)
+ }
+
+ /**
+ * 解绑(移除监听、取消协程)
+ */
+ fun detach() {
+ textWatcher?.let { layout.et.removeTextChangedListener(it) }
+ textWatcher = null
+ debounceJob?.cancel()
+ debounceJob = null
+ scope = null
+ }
+
+ /**
+ * 处理文本变化
+ */
+ private fun handleTextChanged(text: String) {
+ val trimmedText = text.trim()
+ val length = trimmedText.length
+
+ // 取消之前的防抖任务
+ debounceJob?.cancel()
+
+ // 判断是否需要触发查询
+ if (length in config.minLength..config.maxLength) {
+ // 防抖延迟
+ debounceJob = scope?.launch {
+ delay(config.debounceMillis)
+ performQuery(trimmedText)
+ }
+ } else {
+ // 长度不符合,清空上次查询记录
+ lastQueriedValue = ""
+ }
+ }
+
+ /**
+ * 执行查询
+ */
+ private fun performQuery(value: String) {
+ // 防重复查询
+ if (value == lastQueriedValue) {
+ return
+ }
+ lastQueriedValue = value
+
+ // 构建查询参数
+ val params = mapOf(config.paramKey to value).toRequestBody()
+
+ // 发起网络请求
+ scope?.launchCollect({ NetApply.api.getWbNoList(config.url, params) }) {
+ onSuccess = { result ->
+ val results = result.data ?: emptyList()
+ handleQueryResults(results)
+ }
+ onFailed = { code, msg ->
+ // 查询失败,清空记录(允许重试)
+ lastQueriedValue = ""
+ }
+ }
+ }
+
+ /**
+ * 处理查询结果
+ */
+ private fun handleQueryResults(results: List) {
+ when {
+ // 1 条结果:直接填充
+ results.size == 1 -> {
+ layout.value = results[0]
+ }
+
+ // 多条结果:显示弹框选择
+ results.size > 1 -> {
+ showSelectionDialog(results)
+ }
+
+ // 0 条结果:不做处理
+ else -> {
+ // 可选:showToast("未找到匹配数据")
+ }
+ }
+ }
+
+ /**
+ * 显示选择弹框
+ */
+ private fun showSelectionDialog(results: List) {
+ val activity = layout.context.getActivity()
+
+ // 转换为 Common.singleSelect 需要的格式
+ val jsonArray = JSONArray.parseArray(
+ results.map { mapOf("name" to it, "code" to it) }.toJson(false)
+ )
+
+ Common.singleSelect(
+ activity,
+ config.title,
+ jsonArray,
+ null
+ ) { position, _ ->
+ // 用户选择后更新值
+ layout.value = results[position]
+ }
+ }
+}
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/DataLayoutKtx.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/DataLayoutKtx.kt
index 7bec010..647a989 100644
--- a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/DataLayoutKtx.kt
+++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/data/layout/DataLayoutKtx.kt
@@ -293,4 +293,108 @@ fun setTextAllCapsNew(layout: PadDataLayoutNew, textAllCaps: Boolean) {
} else {
layout.et.filters = emptyArray()
}
-}
\ No newline at end of file
+}
+// ========== 自动查询功能 BindingAdapter(新增) ==========
+
+/**
+ * 启用自动查询功能
+ * @param enabled 是否启用
+ */
+@BindingAdapter("autoQueryEnabled")
+fun setAutoQueryEnabled(layout: PadDataLayoutNew, enabled: Boolean) {
+ layout.autoQueryConfig.enabled = enabled
+}
+
+/**
+ * 设置查询接口地址
+ * @param url 接口地址(如:/IntExpCheckIn/checked/queryWbNoList)
+ */
+@BindingAdapter("autoQueryUrl")
+fun setAutoQueryUrl(layout: PadDataLayoutNew, url: String?) {
+ layout.autoQueryConfig.url = url ?: ""
+}
+
+/**
+ * 设置查询参数的 key 名称
+ * @param paramKey 参数名(默认 "value")
+ */
+@BindingAdapter("autoQueryParamKey")
+fun setAutoQueryParamKey(layout: PadDataLayoutNew, paramKey: String?) {
+ layout.autoQueryConfig.paramKey = paramKey ?: "value"
+}
+
+/**
+ * 设置触发查询的最小长度
+ * @param minLength 最小长度(默认 4)
+ */
+@BindingAdapter("autoQueryMinLength")
+fun setAutoQueryMinLength(layout: PadDataLayoutNew, minLength: Int?) {
+ layout.autoQueryConfig.minLength = minLength ?: 4
+}
+
+/**
+ * 设置触发查询的最大长度
+ * @param maxLength 最大长度(默认 8)
+ */
+@BindingAdapter("autoQueryMaxLength")
+fun setAutoQueryMaxLength(layout: PadDataLayoutNew, maxLength: Int?) {
+ layout.autoQueryConfig.maxLength = maxLength ?: 8
+}
+
+/**
+ * 设置弹框标题
+ * @param title 标题(默认 "请选择")
+ */
+@BindingAdapter("autoQueryTitle")
+fun setAutoQueryTitle(layout: PadDataLayoutNew, title: String?) {
+ layout.autoQueryConfig.title = title ?: "请选择"
+}
+
+/**
+ * 设置防抖延迟
+ * @param debounceMillis 延迟毫秒数(默认 300ms)
+ */
+@BindingAdapter("autoQueryDebounce")
+fun setAutoQueryDebounce(layout: PadDataLayoutNew, debounceMillis: Long?) {
+ layout.autoQueryConfig.debounceMillis = debounceMillis ?: 300L
+}
+
+/**
+ * 统一配置自动查询(所有属性设置完成后调用)
+ *
+ * ⚠️ 重要:必须在所有 autoQuery* 属性之后绑定,使用 requireAll = false
+ */
+@BindingAdapter(
+ "autoQueryEnabled",
+ "autoQueryUrl",
+ "autoQueryParamKey",
+ "autoQueryMinLength",
+ "autoQueryMaxLength",
+ "autoQueryTitle",
+ "autoQueryDebounce",
+ requireAll = false
+)
+fun configureAutoQuery(
+ layout: PadDataLayoutNew,
+ enabled: Boolean?,
+ url: String?,
+ paramKey: String?,
+ minLength: Int?,
+ maxLength: Int?,
+ title: String?,
+ debounceMillis: Long?
+) {
+ // 应用所有配置
+ enabled?.let { layout.autoQueryConfig.enabled = it }
+ url?.let { layout.autoQueryConfig.url = it }
+ paramKey?.let { layout.autoQueryConfig.paramKey = it }
+ minLength?.let { layout.autoQueryConfig.minLength = it }
+ maxLength?.let { layout.autoQueryConfig.maxLength = it }
+ title?.let { layout.autoQueryConfig.title = it }
+ debounceMillis?.let { layout.autoQueryConfig.debounceMillis = it }
+
+ // 验证并启用自动查询
+ if (layout.autoQueryConfig.isValid()) {
+ layout.enableAutoQuery(layout.autoQueryConfig)
+ }
+}
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 43b6094..b4d8fda 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
@@ -139,6 +139,18 @@ class PadDataLayoutNew : FrameLayout {
*/
var refreshCallBack: (() -> Unit)? = {}
+ // ========== 自动查询相关属性(新增) ==========
+
+ /**
+ * 自动查询配置
+ */
+ var autoQueryConfig: AutoQueryConfig = AutoQueryConfig()
+
+ /**
+ * 自动查询管理器(延迟初始化)
+ */
+ private var autoQueryManager: AutoQueryManager? = null
+
// 选择日期
private val dateClick: (v: View) -> Unit = {
if (enable) {
@@ -258,4 +270,26 @@ class PadDataLayoutNew : FrameLayout {
this.onChangeListener = listener
}
}
+
+ /**
+ * 启用自动查询功能
+ * @param config 查询配置
+ */
+ fun enableAutoQuery(config: AutoQueryConfig) {
+ this.autoQueryConfig = config
+ if (config.isValid()) {
+ // 初始化查询管理器
+ autoQueryManager = AutoQueryManager(this, config)
+ autoQueryManager?.attach()
+ }
+ }
+
+ /**
+ * 销毁时清理资源
+ */
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ autoQueryManager?.detach()
+ autoQueryManager = null
+ }
}
diff --git a/module_gjc/src/main/res/layout/activity_gjc_weighing_start.xml b/module_gjc/src/main/res/layout/activity_gjc_weighing_start.xml
index 2d56ca6..004c647 100644
--- a/module_gjc/src/main/res/layout/activity_gjc_weighing_start.xml
+++ b/module_gjc/src/main/res/layout/activity_gjc_weighing_start.xml
@@ -68,6 +68,12 @@
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.maWbBean.wbNo}'
+ autoQueryEnabled="@{true}"
+ autoQueryUrl="@{`/IntExpCheckIn/checked/queryWbNoList`}"
+ autoQueryParamKey="@{`wbNo`}"
+ autoQueryMinLength="@{4}"
+ autoQueryMaxLength="@{8}"
+ autoQueryTitle="@{`选择运单号`}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />