diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 240e35f..d1a9bbc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -157,6 +157,12 @@
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
+
+
{
- ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_GJC_YI_KU)
+ ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE)
.navigation()
}
// 板箱
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMove.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMove.kt
new file mode 100644
index 0000000..7ca9ce7
--- /dev/null
+++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMove.kt
@@ -0,0 +1,46 @@
+package com.lukouguoji.module_base.bean
+
+import java.io.Serializable
+
+/**
+ * 国际出港移库Bean
+ */
+data class GjcMove(
+ var no: String = "", // ID
+ var prefix: String = "", // 运单前缀
+ var wbNo: String = "", // 运单号
+ var pc: Long = 0, // 件数
+ var weight: Double = 0.0, // 重量
+ var volume: Double = 0.0, // 体积
+
+ var dep: String = "", // 起运港
+ var dest: String = "", // 目的港
+ var dest1: String = "", // 卸货站1
+ var dest2: String = "", // 卸货站2
+ var by1: String = "", // 承运人1
+ var by2: String = "", // 承运人2
+
+ var awbType: String = "", // 运单类型编码
+ var awbTypeName: String = "", // 运单类型名称
+ var businessType: String = "", // 业务类型
+ var moveState: Int = 0, // 移库状态(0-未移交,1-已移交)
+ var goods: String = "", // 品名(英文)
+ var goodsCn: String = "", // 品名(中文)
+ var agentName: String = "", // 代理人
+ var agentCode: String = "", // 代理代码
+ var spCode: String = "", // SP代码
+ var subCode: String = "", // 子代码
+ var packageType: String = "", // 包装类型
+ var cargoType: String = "", // 货物类型
+ var origin: String = "", // 始发地
+
+ var maWbId: Long = 0, // GJC_MAWB.MAWBID
+ var moveId: String = "", // 移动ID
+ var opId: String = "", // 操作人ID
+ var opdate: String = "", // 操作日期
+ var remark: String = "", // 备注
+ var likeNo: String = "", // 部分运单号no(模糊查询)
+
+ // UI扩展字段
+ var isSelected: Boolean = false // 是否被选中(用于多选)
+) : Serializable
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
index 9d81df6..94a4876 100644
--- a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
+++ b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
@@ -27,6 +27,7 @@ import com.lukouguoji.module_base.bean.GjcCheckInRecord
import com.lukouguoji.module_base.bean.GjcGoodsAddBean
import com.lukouguoji.module_base.bean.GjcGoodsBean
import com.lukouguoji.module_base.bean.GjcGoodsDetailsBean
+import com.lukouguoji.module_base.bean.GjcMove
import com.lukouguoji.module_base.bean.GjcUldUseBean
import com.lukouguoji.module_base.bean.GjcWarehouse
import com.lukouguoji.module_base.bean.GjcWaybillBean
@@ -484,6 +485,27 @@ interface Api {
@POST("IntExpAssemble/backfillWeight")
suspend fun backfillIntExpAssembleWeight(@Body data: RequestBody): BaseResultBean
+ /**
+ * 国际出港移库-分页查询
+ * 接口路径: /IntExpMove/pageQuery
+ */
+ @POST("IntExpMove/pageQuery")
+ suspend fun getIntExpMoveList(@Body data: RequestBody): BaseListBean
+
+ /**
+ * 国际出港移库-分页合计
+ * 接口路径: /IntExpMove/pageQueryTotal
+ */
+ @POST("IntExpMove/pageQueryTotal")
+ suspend fun getIntExpMoveTotal(@Body data: RequestBody): BaseResultBean
+
+ /**
+ * 国际出港移库-批量移库
+ * 接口路径: /IntExpMove/move
+ */
+ @POST("IntExpMove/move")
+ suspend fun submitIntExpMove(@Body data: RequestBody): BaseResultBean
+
/**
* 国际出港待计重-分页搜索
* 接口路径: /IntExpCheckIn/pageQuery
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt
index f25abe9..b00869c 100644
--- a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt
+++ b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt
@@ -138,6 +138,7 @@ object ARouterConstants {
const val ACTIVITY_URL_GJC_HANDOVER = "/gjc/GjcHandoverActivity" //国际出港 货物交接单
const val ACTIVITY_URL_INT_EXP_ASSEMBLE = "/gjc/IntExpAssembleActivity" //国际出港 出港组装
const val ACTIVITY_URL_INT_EXP_ASSEMBLE_START = "/gjc/IntExpAssembleStartActivity" //国际出港 开始组装
+ const val ACTIVITY_URL_INT_EXP_MOVE = "/gjc/IntExpMoveActivity" //国际出港 出港移库
///////////////// 国际进港模块
/**
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/PadSearchLayoutNew.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/PadSearchLayoutNew.kt
new file mode 100644
index 0000000..ccb728d
--- /dev/null
+++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/PadSearchLayoutNew.kt
@@ -0,0 +1,242 @@
+package com.lukouguoji.module_base.ui.weight.search.layout
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.Spinner
+import android.widget.TextView
+import androidx.core.widget.doOnTextChanged
+import androidx.databinding.InverseBindingListener
+import com.lukouguoji.module_base.R
+import com.lukouguoji.module_base.adapter.bindAdapter
+import com.lukouguoji.module_base.adapter.bindOnSelected
+import com.lukouguoji.module_base.adapter.loadImage
+import com.lukouguoji.module_base.adapter.visible
+import com.lukouguoji.module_base.interfaces.IOnFocusChangeListener
+import com.lukouguoji.module_base.interfaces.IOnSpinnerSelected
+import com.lukouguoji.module_base.ktx.formatDate
+import com.lukouguoji.module_base.ktx.getActivity
+import com.lukouguoji.module_base.ktx.loge
+import com.lukouguoji.module_base.ktx.tryCatch
+import com.lukouguoji.module_base.util.Common
+import dev.utils.app.info.KeyValue
+import java.util.Calendar
+import kotlin.properties.Delegates
+
+class PadSearchLayoutNew : LinearLayout {
+
+ constructor(context: Context?) : super(context!!)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs)
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
+ context!!,
+ attrs,
+ defStyleAttr
+ )
+
+
+ var onChangeListener: InverseBindingListener? = null
+
+ var ll: LinearLayout by Delegates.notNull()
+
+ var tvM: TextView by Delegates.notNull()
+ var tv: TextView by Delegates.notNull()
+
+ var et: EditText by Delegates.notNull()
+ var spinner: Spinner by Delegates.notNull()
+ var iv: ImageView by Delegates.notNull()
+
+ var type = SearchLayoutType.INPUT
+ set(value) {
+ field = value
+ setForType()
+ onValueSet()
+ }
+
+ var enable = true
+ set(value) {
+ field = value
+ ll.isEnabled = value
+ et.isEnabled = value
+ spinner.isEnabled = value
+ }
+
+ var value = ""
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ onValueSet()
+ onChangeListener?.onChange()
+ }
+
+ var hint = ""
+ set(value) {
+ field = value
+
+ et.hint = value
+ tv.hint = value
+ bindAdapter(spinner, list, hint)
+ }
+
+ var list = emptyList()
+ set(value) {
+ field = value
+ bindAdapter(spinner, value, hint)
+ onValueSet()
+ }
+
+ var required = false
+ set(value) {
+ field = value
+ tvM.visibility = if (value) VISIBLE else GONE
+ }
+
+ var icon: Any? = null
+ set(value) {
+ field = value
+ visible(iv, value)
+ loadImage(iv, value)
+ }
+
+ // 选择日期
+ private val dateClick: (v: View) -> Unit = {
+ if (enable) {
+ Common.onYearMonthDay(context.getActivity(), value) { year, month, day ->
+ val calendar = Calendar.getInstance()
+ calendar.set(year, month - 1, day)
+ value = calendar.time.formatDate()
+ refreshCallBack?.invoke()
+ }
+ }
+ }
+
+ /**
+ * 刷新事件回调
+ */
+ var refreshCallBack: (() -> Unit)? = {}
+
+ var listRefreshCallBack: (() -> Unit)? = {}
+
+ ///////////////////////////////////////////////////////////////////////////
+ // 方法区
+ ///////////////////////////////////////////////////////////////////////////
+
+ init {
+ val view = inflate(context, R.layout.layout_pad_search_new, this)
+
+ ll = view.findViewById(R.id.ll)
+ tvM = view.findViewById(R.id.tv_m)
+ tv = view.findViewById(R.id.tv)
+ et = view.findViewById(R.id.et)
+ spinner = view.findViewById(R.id.spinner)
+ iv = view.findViewById(R.id.iv)
+
+ et.doOnTextChanged { text, _, _, _ ->
+ value = text.toString()
+ }
+ bindOnSelected(spinner, object : IOnSpinnerSelected {
+ override fun onSelected(position: Int) {
+ value = list.getOrNull(position)?.value ?: ""
+ refreshCallBack?.invoke()
+ }
+ })
+
+ // 监听输入框焦点变化
+ com.lukouguoji.module_base.adapter.setOnFocusChangeListener(
+ et, object : IOnFocusChangeListener {
+ override fun onFocusChange(hasFocus: Boolean) {
+ if (!hasFocus) {
+ refreshCallBack?.invoke()
+ }
+ }
+ })
+
+ setForType()
+ }
+
+ private fun setForType() {
+ when (type) {
+ SearchLayoutType.INPUT -> {
+ et.visibility = VISIBLE
+ spinner.visibility = GONE
+ tv.visibility = GONE
+ setOnClickListener(null)
+ }
+ SearchLayoutType.INTEGER -> {
+ et.visibility = VISIBLE
+ spinner.visibility = GONE
+ tv.visibility = GONE
+ setOnClickListener(null)
+ }
+
+ SearchLayoutType.SPINNER -> {
+ spinner.visibility = VISIBLE
+ et.visibility = GONE
+ tv.visibility = GONE
+ setOnClickListener(null)
+ }
+
+ SearchLayoutType.DATE -> {
+ tv.visibility = VISIBLE
+ spinner.visibility = GONE
+ et.visibility = GONE
+
+ setOnClickListener(dateClick)
+ }
+ }
+ }
+
+ private fun onValueSet() {
+ when (type) {
+ SearchLayoutType.INPUT -> {
+ if (et.text.toString() != value) {
+ et.setText(value)
+ }
+ }
+
+ SearchLayoutType.INTEGER -> {
+ var stringAnInt = isStringAnInt(et.text.toString())
+ if (stringAnInt && et.text.toString() != value ) {
+ et.setText(value)
+ }
+ }
+
+ SearchLayoutType.SPINNER -> {
+ if (value.isNotEmpty()) {
+ val position = list.indexOfFirst { it.value == value }
+ if (position >= 0) {
+ spinner.setSelection(position)
+ }
+ }
+ }
+
+ SearchLayoutType.DATE -> {
+ tv.text = value
+ }
+ }
+ }
+
+ /**
+ * 判断是否是数字
+ */
+ fun isStringAnInt(str: String?): Boolean {
+ return str?.toIntOrNull() != null
+ }
+
+
+ /**
+ * 重置数据
+ */
+ fun reset() {
+ value = ""
+ if (type == SearchLayoutType.SPINNER && list.isNotEmpty()) {
+ spinner.setSelection(
+ if (hint.isEmpty()) list.size - 1 else list.size
+ )
+ }
+ }
+}
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/SearchLayoutKtx.kt b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/SearchLayoutKtx.kt
index 8b62516..287159e 100644
--- a/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/SearchLayoutKtx.kt
+++ b/module_base/src/main/java/com/lukouguoji/module_base/ui/weight/search/layout/SearchLayoutKtx.kt
@@ -138,4 +138,136 @@ fun setInputWaybill(layout: PadSearchLayout, isWaybill: Boolean) {
}
}
}
+}
+
+///////////////////////////////////////////////////////////////////////////
+// PadSearchLayoutNew 的绑定适配器
+///////////////////////////////////////////////////////////////////////////
+
+@BindingAdapter(
+ "type",
+ "hint",
+ "required",
+ "icon",
+ requireAll = false
+)
+fun setSearchLayoutNewData(
+ layout: PadSearchLayoutNew,
+ type: SearchLayoutType?,
+ hint: String?,
+ required: Boolean?,
+ icon: Any?,
+) {
+ type?.let {
+ layout.type = type
+ }
+ required?.let {
+ layout.required = required
+ }
+ hint?.let {
+ layout.hint = hint
+ }
+ icon?.let {
+ layout.icon = icon
+ }
+}
+
+@BindingAdapter(
+ "value",
+ requireAll = false
+)
+fun setSearchLayoutNewDataValue(
+ layout: PadSearchLayoutNew,
+ value: String?,
+) {
+ value?.let {
+ layout.value = value
+ }
+}
+
+@BindingAdapter(
+ "enable",
+ requireAll = false
+)
+fun setSearchLayoutNewDataEnable(
+ layout: PadSearchLayoutNew,
+ enable: Boolean?,
+) {
+ enable?.let {
+ layout.enable = enable
+ }
+}
+
+@BindingAdapter(
+ "list",
+ requireAll = false
+)
+fun setSearchLayoutNewDataList(
+ layout: PadSearchLayoutNew,
+ list: List?,
+) {
+ list?.let {
+ layout.list = list
+ }
+}
+
+@BindingAdapter(
+ "bgDrawable",
+ requireAll = false
+)
+fun setSearchLayoutNewDataBackground(
+ layout: PadSearchLayoutNew,
+ bgDrawable: Drawable,
+) {
+ layout.ll.setBackgroundDrawable(bgDrawable)
+}
+
+@InverseBindingAdapter(attribute = "value", event = "valueAttrChanged")
+fun getSearchLayoutNewValue(layout: PadSearchLayoutNew): String {
+ return layout.value
+}
+
+@BindingAdapter("valueAttrChanged", requireAll = false)
+fun setSearchLayoutNewValueAttrChanged(layout: PadSearchLayoutNew, listener: InverseBindingListener) {
+ layout.onChangeListener = listener
+}
+
+@BindingAdapter("setOnIconClickListener", requireAll = false)
+fun setSearchLayoutNewOnIconClickListener(layout: PadSearchLayoutNew, listener: View.OnClickListener?) {
+ layout.iv.setOnClickListener(listener)
+}
+
+@BindingAdapter("setRefreshCallBack", requireAll = false)
+fun setSearchLayoutNewRefreshCallBack(layout: PadSearchLayoutNew, listener: (() -> Unit)?) {
+ layout.refreshCallBack = listener
+}
+
+@BindingAdapter("setSearchListRefresh")
+fun setSearchLayoutNewListRefreshCallBack(layout: PadSearchLayoutNew, listener: (() -> Unit)?) {
+ layout.listRefreshCallBack = listener
+}
+
+@BindingAdapter("setTextAllCaps", requireAll = false)
+fun setSearchLayoutNewTextAllCaps(layout: PadSearchLayoutNew, textAllCaps: Boolean) {
+ if (textAllCaps) {
+ layout.et.filters = arrayOf(InputFilter.AllCaps())
+ } else {
+ layout.et.filters = emptyArray()
+ }
+}
+
+@BindingAdapter("setInputWaybill", requireAll = false)
+fun setSearchLayoutNewInputWaybill(layout: PadSearchLayoutNew, isWaybill: Boolean) {
+ if (isWaybill) {
+ EditTextUtils.setMaxLength(layout.et, 11)
+ EditTextUtils.setInputType(layout.et, InputType.TYPE_CLASS_NUMBER)
+ layout.et.doOnTextChanged { text, _, _, _ ->
+ if (text.toString().length == 11) {
+ layout.refreshCallBack?.invoke()
+ }
+ if (text.toString().length in 4..8){
+ layout.listRefreshCallBack?.invoke()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/module_base/src/main/res/drawable/bg_search_layout_n_new.xml b/module_base/src/main/res/drawable/bg_search_layout_n_new.xml
new file mode 100644
index 0000000..b040a1c
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_search_layout_n_new.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_search_layout_new.xml b/module_base/src/main/res/drawable/bg_search_layout_new.xml
new file mode 100644
index 0000000..bf10964
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_search_layout_new.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_search_layout_s_new.xml b/module_base/src/main/res/drawable/bg_search_layout_s_new.xml
new file mode 100644
index 0000000..8a3a7f6
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_search_layout_s_new.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/module_base/src/main/res/layout/layout_pad_search_new.xml b/module_base/src/main/res/layout/layout_pad_search_new.xml
new file mode 100644
index 0000000..069ee7d
--- /dev/null
+++ b/module_base/src/main/res/layout/layout_pad_search_new.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpMoveViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpMoveViewHolder.kt
new file mode 100644
index 0000000..77f8edd
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpMoveViewHolder.kt
@@ -0,0 +1,27 @@
+package com.lukouguoji.gjc.holder
+
+import android.view.View
+import com.lukouguoji.gjc.databinding.ItemIntExpMoveBinding
+import com.lukouguoji.module_base.base.BaseViewHolder
+import com.lukouguoji.module_base.bean.GjcMove
+
+/**
+ * 国际出港移库列表项ViewHolder
+ */
+class IntExpMoveViewHolder(view: View) :
+ BaseViewHolder(view) {
+
+ override fun onBind(item: Any?, position: Int) {
+ val bean = getItemBean(item) ?: return
+ binding.bean = bean
+ binding.position = position
+
+ // 点击整个item切换选中状态
+ binding.root.setOnClickListener {
+ bean.isSelected = !bean.isSelected
+ binding.bean = bean // 触发DataBinding更新
+ }
+
+ binding.executePendingBindings()
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/page/move/IntExpMoveActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/page/move/IntExpMoveActivity.kt
new file mode 100644
index 0000000..86398d1
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/page/move/IntExpMoveActivity.kt
@@ -0,0 +1,107 @@
+package com.lukouguoji.gjc.page.move
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AlertDialog
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.lukouguoji.gjc.R
+import com.lukouguoji.gjc.databinding.ActivityIntExpMoveBinding
+import com.lukouguoji.gjc.viewModel.IntExpMoveViewModel
+import com.lukouguoji.module_base.base.BaseBindingActivity
+import com.lukouguoji.module_base.common.Constant
+import com.lukouguoji.module_base.ktx.addOnItemClickListener
+import com.lukouguoji.module_base.ktx.showToast
+import com.lukouguoji.module_base.model.ScanModel
+import com.lukouguoji.module_base.router.ARouterConstants
+
+/**
+ * 国际出港-出港移库
+ */
+@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE)
+class IntExpMoveActivity : BaseBindingActivity() {
+
+ override fun layoutId() = R.layout.activity_int_exp_move
+ override fun viewModelClass() = IntExpMoveViewModel::class.java
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ setBackArrow("出港移库")
+ binding.viewModel = viewModel
+ binding.activity = this
+
+ initRecyclerView()
+ initListeners()
+ }
+
+ /**
+ * 初始化RecyclerView
+ */
+ private fun initRecyclerView() {
+ viewModel.pageModel.bindSmartRefreshLayout(
+ binding.srl,
+ binding.rv,
+ viewModel,
+ this
+ )
+ binding.rv.addOnItemClickListener(viewModel)
+ }
+
+ /**
+ * 初始化监听器
+ */
+ private fun initListeners() {
+ // 移库按钮
+ binding.btnMove.setOnClickListener {
+ showMoveConfirmDialog()
+ }
+ }
+
+ /**
+ * 扫码运单号
+ */
+ fun scanWaybill() {
+ ScanModel.startScan(this, Constant.RequestCode.WAYBILL)
+ }
+
+ /**
+ * 显示移库确认对话框
+ */
+ private fun showMoveConfirmDialog() {
+ val selectedItems = viewModel.getSelectedItems()
+
+ if (selectedItems.isEmpty()) {
+ showToast("请至少选择一条运单")
+ return
+ }
+
+ AlertDialog.Builder(this)
+ .setTitle("移库确认")
+ .setMessage("确定要移库选中的 ${selectedItems.size} 条记录吗?")
+ .setPositiveButton("确定") { _, _ ->
+ viewModel.submitMove()
+ }
+ .setNegativeButton("取消", null)
+ .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) {
+ val starter = Intent(context, IntExpMoveActivity::class.java)
+ context.startActivity(starter)
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt
new file mode 100644
index 0000000..b622f00
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt
@@ -0,0 +1,168 @@
+package com.lukouguoji.gjc.viewModel
+
+import androidx.lifecycle.MutableLiveData
+import com.lukouguoji.gjc.R
+import com.lukouguoji.gjc.holder.IntExpMoveViewHolder
+import com.lukouguoji.module_base.base.BasePageViewModel
+import com.lukouguoji.module_base.bean.GjcMove
+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 dev.utils.app.info.KeyValue
+
+/**
+ * 国际出港移库ViewModel
+ */
+class IntExpMoveViewModel : BasePageViewModel(), IOnItemClickListener {
+
+ // ========== 搜索字段 ==========
+ val awbType = MutableLiveData("") // 运单类型
+ val by1 = MutableLiveData("") // 承运人
+ val dest1 = MutableLiveData("") // 卸货站
+ val moveState = MutableLiveData("") // 移库状态
+ val waybillNo = MutableLiveData("") // 运单号
+
+ // ========== 运单类型下拉数据 ==========
+ val awbTypeList = MutableLiveData>().apply {
+ value = listOf(
+ KeyValue("", "全部"),
+ KeyValue("IOCO", "国际出港(经国内航班出境)"),
+ KeyValue("IOSO", "国际出港(国际航班出境)")
+ )
+ }
+
+ // ========== 移库状态下拉数据 ==========
+ val moveStateList = MutableLiveData>().apply {
+ value = listOf(
+ KeyValue("", "全部"),
+ KeyValue("0", "未移交"),
+ KeyValue("1", "已移交")
+ )
+ }
+
+ // ========== 底部统计 ==========
+ val totalCount = MutableLiveData("0") // 合计票数
+ val totalPieces = MutableLiveData("0") // 总件数
+ val totalWeight = MutableLiveData("0") // 总重量
+
+ // ========== 适配器配置 ==========
+ val itemViewHolder = IntExpMoveViewHolder::class.java
+ val itemLayoutId = R.layout.item_int_exp_move
+
+ /**
+ * 搜索按钮点击
+ */
+ fun searchClick() {
+ refresh()
+ }
+
+ /**
+ * 扫码运单号(在Activity中实现)
+ */
+ fun scanWaybill() {
+ // 由Activity处理扫码逻辑
+ }
+
+ /**
+ * 全选/取消全选
+ */
+ fun toggleSelectAll() {
+ val adapter = pageModel.rv?.commonAdapter() ?: return
+ val list = adapter.items.filterIsInstance()
+ val allSelected = list.all { it.isSelected }
+
+ list.forEach { it.isSelected = !allSelected }
+ adapter.notifyDataSetChanged()
+ }
+
+ /**
+ * 获取选中的运单
+ */
+ fun getSelectedItems(): List {
+ val adapter = pageModel.rv?.commonAdapter() ?: return emptyList()
+ return adapter.items.filterIsInstance().filter { it.isSelected }
+ }
+
+ /**
+ * 提交移库(在Activity中显示确认对话框后调用)
+ */
+ fun submitMove() {
+ val selectedItems = getSelectedItems()
+
+ if (selectedItems.isEmpty()) {
+ showToast("请至少选择一条运单")
+ return
+ }
+
+ val params = selectedItems.toRequestBody()
+
+ launchLoadingCollect({ NetApply.api.submitIntExpMove(params) }) {
+ onSuccess = {
+ showToast("移库成功")
+ refresh() // 刷新列表
+ }
+ onFailed = { _, msg ->
+ showToast(msg.noNull("移库失败"))
+ }
+ }
+ }
+
+ /**
+ * 获取列表数据
+ */
+ override fun getData() {
+ // 构建筛选参数
+ val filterParams = mapOf(
+ "awbType" to awbType.value.noNull(),
+ "by1" to by1.value.noNull(),
+ "dest1" to dest1.value.noNull(),
+ "moveState" to moveState.value.noNull(),
+ "likeNo" to waybillNo.value.noNull()
+ )
+
+ // 列表参数(含分页)
+ val listParams = (filterParams + mapOf(
+ "pageNum" to pageModel.page,
+ "pageSize" to pageModel.limit
+ )).toRequestBody()
+
+ // 统计参数(无分页)
+ val totalParams = filterParams.toRequestBody()
+
+ // 获取列表(显示loading)
+ launchLoadingCollect({ NetApply.api.getIntExpMoveList(listParams) }) {
+ onSuccess = { pageModel.handleListBean(it) }
+ }
+
+ // 获取统计(后台调用)
+ getTotalData(totalParams)
+ }
+
+ /**
+ * 获取统计数据(无Loading)
+ */
+ private fun getTotalData(params: okhttp3.RequestBody) {
+ launchCollect({ NetApply.api.getIntExpMoveTotal(params) }) {
+ onSuccess = { result ->
+ val data = result.data
+ totalCount.value = (data?.wbNumber ?: 0).toString()
+ totalPieces.value = (data?.totalPc ?: 0L).toString()
+ totalWeight.value = (data?.totalWeight ?: 0.0).toString()
+ }
+ }
+ }
+
+ /**
+ * Item点击事件处理(用于单选CheckBox)
+ */
+ override fun onItemClick(position: Int, type: Int) {
+ val bean = pageModel.rv?.commonAdapter()?.getItem(position) as? GjcMove ?: return
+ bean.isSelected = !bean.isSelected
+ pageModel.rv?.commonAdapter()?.notifyItemChanged(position)
+ }
+}
diff --git a/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml b/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml
index 8cdf28f..f4d627c 100644
--- a/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml
+++ b/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml
@@ -33,16 +33,14 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
- android:layout_marginEnd="8dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical">
-
@@ -53,7 +51,7 @@
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
- android:padding="16dp">
+ android:padding="8dp">
@@ -116,23 +114,24 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.4"
- android:layout_marginBottom="16dp"
+ android:layout_marginBottom="8dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
- android:padding="16dp">
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="8dp">
-
+
+ android:layout_margin="4dp"
+ hint='@{"请输入搜索内容"}'
+ type="@{SearchLayoutType.INPUT}"
+ value="@={viewModel.searchText}" />
@@ -147,10 +146,10 @@
+ android:padding="8dp">
+ android:padding="8dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/item_int_exp_move.xml b/module_gjc/src/main/res/layout/item_int_exp_move.xml
new file mode 100644
index 0000000..f6b0ca9
--- /dev/null
+++ b/module_gjc/src/main/res/layout/item_int_exp_move.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+