This commit is contained in:
2025-11-27 21:13:22 +08:00
parent f797767919
commit 35a9ee145a
17 changed files with 1189 additions and 19 deletions

View File

@@ -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

View File

@@ -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<SimpleResultBean>
/**
* 国际出港移库-分页查询
* 接口路径: /IntExpMove/pageQuery
*/
@POST("IntExpMove/pageQuery")
suspend fun getIntExpMoveList(@Body data: RequestBody): BaseListBean<GjcMove>
/**
* 国际出港移库-分页合计
* 接口路径: /IntExpMove/pageQueryTotal
*/
@POST("IntExpMove/pageQueryTotal")
suspend fun getIntExpMoveTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际出港移库-批量移库
* 接口路径: /IntExpMove/move
*/
@POST("IntExpMove/move")
suspend fun submitIntExpMove(@Body data: RequestBody): BaseResultBean<SimpleResultBean>
/**
* 国际出港待计重-分页搜索
* 接口路径: /IntExpCheckIn/pageQuery

View File

@@ -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" //国际出港 出港移库
///////////////// 国际进港模块
/**

View File

@@ -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<KeyValue>()
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
)
}
}
}

View File

@@ -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<KeyValue>?,
) {
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>(InputFilter.AllCaps())
} else {
layout.et.filters = emptyArray<InputFilter>()
}
}
@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()
}
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#E0E0E0" />
<corners android:radius="8dp" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_search_layout_s_new" android:state_enabled="true" />
<item android:drawable="@drawable/bg_search_layout_n_new" android:state_enabled="false" />
</selector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_f2" />
<corners android:radius="20dp" />
</shape>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="5dp"
android:background="@drawable/bg_search_layout_new"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/et"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:paddingStart="10dp"
android:singleLine="true"
android:textColor="@color/text_normal"
android:textColorHint="@color/text_gray_l"
android:textSize="14sp"
tools:text="edittext" />
<Spinner
android:id="@+id/spinner"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_spinner_pda_new"
android:overlapAnchor="false"
android:spinnerMode="dropdown" />
<TextView
android:id="@+id/tv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:textColor="@color/text_normal"
android:textColorHint="@color/text_gray_l"
android:textSize="14sp"
tools:text="textView" />
<ImageView
android:id="@+id/iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
android:src="@mipmap/scan_code"
android:visibility="gone" />
<TextView
android:id="@+id/tv_m"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="*"
android:textColor="@color/red"
android:textSize="16sp"
android:visibility="gone" />
</LinearLayout>