Compare commits

...

4 Commits

Author SHA1 Message Date
b994f43bc7 feat: command & mcp 2026-03-08 15:24:46 +08:00
be3d633301 feat: opt claude config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:24:10 +08:00
ad6b7d17a5 feat: 国际进港装机单添加航班级联查询和入库/修改库位功能
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:23:23 +08:00
7413a8d159 feat: 国际进港舱单添加分单子列表展开/收起功能
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:05:36 +08:00
16 changed files with 1012 additions and 319 deletions

14
.claude/commands/run.md Normal file
View File

@@ -0,0 +1,14 @@
清理构建缓存,重新打包 Debug 版本,安装到 Android 设备并启动应用
先检查是否有已连接的设备,然后执行清理、构建、安装并启动应用。
```bash
# 检查设备连接
adb devices -l
# 清理 + 安装
./gradlew clean installDebug
# 启动应用(通过 Launcher Intent
adb shell monkey -p com.lukouguoji.aerologic -c android.intent.category.LAUNCHER 1
```

View File

@@ -1,14 +1,14 @@
{ {
"mcpServers": { "mcpServers": {
"空港集团 - API 文档": { "空港集团 - API 文档": {
"command": "npx", "command": "/Users/kid/.version-fox/sdks/nodejs/bin/npx",
"args": [ "args": [
"-y", "-y",
"apifox-mcp-server@latest", "apifox-mcp-server@latest",
"--project-id=7382863" "--project-id=7382863"
], ],
"env": { "env": {
"APIFOX_ACCESS_TOKEN": "ogr6p7RaNJa4GgIOSuUMJRSVLfDE" "APIFOX_ACCESS_TOKEN": "APS-S2aVVwqasbdByzPLgSqryRC8BB0ZFqhQ"
} }
} }
} }

View File

@@ -63,9 +63,19 @@
"Bash(curl:*)", "Bash(curl:*)",
"Bash(git:*)", "Bash(git:*)",
"WebFetch(domain:app.apifox.com)", "WebFetch(domain:app.apifox.com)",
"WebFetch(domain:apifox.com)" "WebFetch(domain:apifox.com)",
"Bash(npx:*)",
"Bash(claude mcp:*)",
"Bash(python3:*)",
"mcp__apifox__read_project_oas_ukz3j4",
"mcp__apifox__read_project_oas_ref_resources_ukz3j4",
"mcp__apifox__refresh_project_oas_ukz3j4"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []
} },
"enabledMcpjsonServers": [
"空港集团 - API 文档",
"apifox"
]
} }

15
.mcp.json Normal file
View File

@@ -0,0 +1,15 @@
{
"mcpServers": {
"apifox": {
"command": "npx",
"args": [
"-y",
"apifox-mcp-server@latest",
"--project-id=7382863"
],
"env": {
"APIFOX_ACCESS_TOKEN": "APS-S2aVVwqasbdByzPLgSqryRC8BB0ZFqhQ"
}
}
}
}

View File

@@ -0,0 +1,39 @@
package com.lukouguoji.module_base.bean
import androidx.databinding.ObservableBoolean
import java.io.Serializable
/**
* 国际进港舱单-分单Bean
*/
data class GjjHaWb(
var hawbId: Long = 0,
var hno: String = "",
var no: String = "",
var prefix: String = "",
var pc: Long = 0,
var weight: Double = 0.0,
var volume: Double = 0.0,
var cashWeight: Double = 0.0,
var goods: String = "",
var spCode: String = "",
var mftStatus: String = "",
var lastMftStatus: String = "",
var mftMsgId: String = "",
var lastMftMsgId: String = "",
var declareCount: Int = 0,
var checkInType: String = "",
var activeId: Long = 0,
var opId: String = "",
var opDate: String = "",
var billsNo: String = "",
var remark: String = "",
var response: String = ""
) : Serializable {
@Transient
val checked: ObservableBoolean = ObservableBoolean(false)
var isSelected: Boolean
get() = checked.get()
set(value) = checked.set(value)
}

View File

@@ -56,6 +56,13 @@ data class GjjManifest(
var unNumber: String = "", // 危险品编号 var unNumber: String = "", // 危险品编号
var activeId: Long = 0 // 活动ID var activeId: Long = 0 // 活动ID
) : Serializable { ) : Serializable {
// 分单列表
var haWbList: List<GjjHaWb>? = null
// 展开/收起状态
@Transient
val showMore: ObservableBoolean = ObservableBoolean(false)
// 选中状态(用于多选功能)- 不参与序列化 // 选中状态(用于多选功能)- 不参与序列化
@Transient @Transient
val checked: ObservableBoolean = ObservableBoolean(false) val checked: ObservableBoolean = ObservableBoolean(false)

View File

@@ -44,6 +44,7 @@ import com.lukouguoji.module_base.bean.GjcWeighingBean
import com.lukouguoji.module_base.bean.GjcWeighingRecordBean import com.lukouguoji.module_base.bean.GjcWeighingRecordBean
import com.lukouguoji.module_base.bean.GjcWeighingStatisticsBean import com.lukouguoji.module_base.bean.GjcWeighingStatisticsBean
import com.lukouguoji.module_base.bean.GjjAirManifest import com.lukouguoji.module_base.bean.GjjAirManifest
import com.lukouguoji.module_base.bean.GjjHaWb
import com.lukouguoji.module_base.bean.GjjGoodsBean import com.lukouguoji.module_base.bean.GjjGoodsBean
import com.lukouguoji.module_base.bean.GjjGoodsDetailsBean import com.lukouguoji.module_base.bean.GjjGoodsDetailsBean
import com.lukouguoji.module_base.bean.GjjGoodsTypeBean import com.lukouguoji.module_base.bean.GjjGoodsTypeBean
@@ -1775,6 +1776,12 @@ interface Api {
@POST("IntImpManifest/pageQueryTotal") @POST("IntImpManifest/pageQueryTotal")
suspend fun getIntImpManifestTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto> suspend fun getIntImpManifestTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港舱单-获取主单下分单
*/
@POST("IntImpManifest/listHaWbByManifest")
suspend fun getIntImpManifestHaWbList(@Body data: RequestBody): BaseResultBean<List<GjjHaWb>>
/** /**
* 国际进港舱单-分拣理货(装机单)-分页查询 * 国际进港舱单-分拣理货(装机单)-分页查询
*/ */

View File

@@ -6,13 +6,18 @@ import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpLoadingListBinding import com.lukouguoji.gjj.databinding.ActivityIntImpLoadingListBinding
import com.lukouguoji.gjj.dialog.IntImpInStorageDialogModel
import com.lukouguoji.gjj.dialog.IntImpModifyStorageDialogModel
import com.lukouguoji.gjj.viewModel.IntImpLoadingListViewModel import com.lukouguoji.gjj.viewModel.IntImpLoadingListViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.impl.FlowBus import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.observe import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.ktx.addOnItemClickListener import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.router.ARouterConstants import com.lukouguoji.module_base.router.ARouterConstants
/** /**
@@ -28,6 +33,7 @@ class IntImpLoadingListActivity :
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港装机单") setBackArrow("国际进港装机单")
binding.viewModel = viewModel binding.viewModel = viewModel
binding.activity = this
// 观察全选状态,更新图标透明度 // 观察全选状态,更新图标透明度
viewModel.isAllChecked.observe(this) { isAllChecked -> viewModel.isAllChecked.observe(this) { isAllChecked ->
@@ -45,10 +51,61 @@ class IntImpLoadingListActivity :
viewModel.refresh() viewModel.refresh()
} }
// 接收从进港舱单传递的参数
intent.getStringExtra("fdate")?.let { if (it.isNotEmpty()) viewModel.flightDate.value = it }
intent.getStringExtra("fno")?.let { if (it.isNotEmpty()) viewModel.flightNo.value = it }
intent.getStringExtra("sendAddress")?.let { if (it.isNotEmpty()) viewModel.sendAddress.value = it }
intent.getStringExtra("fdest")?.let { if (it.isNotEmpty()) viewModel.fdest.value = it }
// 如果收到了航班号和日期参数,触发航班查询来构建始发站下拉列表
val fdate = intent.getStringExtra("fdate")
val fno = intent.getStringExtra("fno")
if (!fdate.isNullOrEmpty() && !fno.isNullOrEmpty()) {
viewModel.onFlightNoInputComplete()
}
// 初始加载数据 // 初始加载数据
viewModel.refresh() viewModel.refresh()
} }
/**
* 显示入库操作对话框
*/
fun showInStorageDialog() {
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val selectedItems = list.filterIsInstance<GjjManifest>().filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要入库的记录")
return
}
IntImpInStorageDialogModel { dialog ->
val locationName = dialog.locationName
val locationId = dialog.locationId
viewModel.performInStorage(locationName, locationId, selectedItems)
}.show(this)
}
/**
* 显示修改库位对话框
*/
fun showModifyStorageDialog() {
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val selectedItems = list.filterIsInstance<GjjManifest>().filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要修改库位的记录")
return
}
IntImpModifyStorageDialogModel { dialog ->
val locationName = dialog.locationName
val locationId = dialog.locationId
viewModel.performModifyStorage(locationName, locationId, selectedItems)
}.show(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) { if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {

View File

@@ -0,0 +1,36 @@
package com.lukouguoji.gjj.holder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjj.databinding.ItemIntImpManifestSubBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjHaWb
import com.lukouguoji.module_base.bean.GjjManifest
/**
* 国际进港舱单 - 分单子列表 ViewHolder
*/
class IntImpManifestSubViewHolder(view: View) :
BaseViewHolder<GjjHaWb, ItemIntImpManifestSubBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
// 单选框点击切换选择状态
binding.ivCheckbox.setOnClickListener {
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
binding.executePendingBindings()
// 反向联动主列表项(勾选子项时自动勾选父项)
if (newCheckedState) {
val recyclerView = itemView.parent as? RecyclerView ?: return@setOnClickListener
val parentBean = recyclerView.tag as? GjjManifest ?: return@setOnClickListener
parentBean.checked.set(true)
}
}
}
}

View File

@@ -1,9 +1,12 @@
package com.lukouguoji.gjj.holder package com.lukouguoji.gjj.holder
import android.view.View import android.view.View
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ItemIntImpManifestBinding import com.lukouguoji.gjj.databinding.ItemIntImpManifestBinding
import com.lukouguoji.module_base.adapter.setCommonAdapter
import com.lukouguoji.module_base.base.BaseViewHolder import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjManifest import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.ktx.refresh
/** /**
* 国际进港舱单 ViewHolder * 国际进港舱单 ViewHolder
@@ -17,10 +20,14 @@ class IntImpManifestViewHolder(view: View) :
binding.position = position binding.position = position
binding.executePendingBindings() binding.executePendingBindings()
// 选中图标点击 - 切换选择状态 // 选中图标点击 - 切换选择状态(联动子列表)
binding.ivIcon.setOnClickListener { binding.ivIcon.setOnClickListener {
bean.checked.set(!bean.checked.get()) val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
// 联动子列表选中状态
bean.haWbList?.forEach { sub -> sub.checked.set(newCheckedState) }
binding.executePendingBindings() binding.executePendingBindings()
binding.rvSub.adapter?.notifyDataSetChanged()
} }
// 编辑按钮点击 // 编辑按钮点击
@@ -32,5 +39,21 @@ class IntImpManifestViewHolder(view: View) :
binding.btnDelete.setOnClickListener { binding.btnDelete.setOnClickListener {
clickListener?.onItemClick(position, 102) // 102=删除 clickListener?.onItemClick(position, 102) // 102=删除
} }
// 展开按钮点击事件
binding.ivShow.setOnClickListener {
bean.showMore.set(!bean.showMore.get())
}
// 初始化分单子列表 RecyclerView
setCommonAdapter(
binding.rvSub,
IntImpManifestSubViewHolder::class.java,
R.layout.item_int_imp_manifest_sub
)
// 设置父Bean引用用于子列表反向联动
binding.rvSub.tag = bean
binding.rvSub.refresh(bean.haWbList ?: emptyList())
} }
} }

View File

@@ -1,18 +1,24 @@
package com.lukouguoji.gjj.viewModel package com.lukouguoji.gjj.viewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjj.R import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.holder.IntImpLoadingListViewHolder import com.lukouguoji.gjj.holder.IntImpLoadingListViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.GjjManifest import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant 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.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.commonAdapter import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.launchCollect import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect 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.showToast
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/** /**
* 国际进港装机单 ViewModel * 国际进港装机单 ViewModel
@@ -22,10 +28,75 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
// ========== 搜索条件 ========== // ========== 搜索条件 ==========
val flightDate = MutableLiveData("") // 航班日期 val flightDate = MutableLiveData("") // 航班日期
val flightNo = MutableLiveData("") // 航班号 val flightNo = MutableLiveData("") // 航班号
val fdep = MutableLiveData("") // 始发站 val sendAddress = MutableLiveData("") // 始发站(选中值)
val sendAddressList = MutableLiveData<List<KeyValue>>(emptyList()) // 始发站下拉列表
val fdest = MutableLiveData("") // 目的站 val fdest = MutableLiveData("") // 目的站
val waybillNo = MutableLiveData("") // 运单号 val waybillNo = MutableLiveData("") // 运单号
// ========== 航班级联查询 ==========
private var lastQueriedFlight = ""
private var fid = ""
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
queryFlightIfReady()
}
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
private fun queryFlightIfReady() {
val fdate = flightDate.value
val fno = flightNo.value
if (fdate.isNullOrEmpty() || fno.isNullOrEmpty()) return
val key = "$fdate-$fno"
if (key == lastQueriedFlight) return
lastQueriedFlight = key
launchCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
fid = flight.fid.noNull()
fdest.value = flight.fdest.noNull()
// 构建始发站下拉列表fdep + jtz经停港
val list = mutableListOf(
KeyValue(flight.fdep.noNull(), flight.fdep.noNull()),
)
if (!flight.jtz.isNullOrEmpty()) {
list.add(KeyValue(flight.jtz.noNull(), flight.jtz.noNull()))
}
sendAddressList.value = list
sendAddress.value = flight.fdep.noNull()
} else {
fid = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
showToast(it.msg.noNull("获取航班信息失败"))
}
}
onFailed = { _, _ ->
fid = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
}
}
}
// ========== 统计信息 ========== // ========== 统计信息 ==========
val totalCount = MutableLiveData("0") // 合计票数 val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数 val totalPc = MutableLiveData("0") // 总件数
@@ -76,33 +147,74 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
} }
/** /**
* 修改库位按钮点击 * 修改库位(由 Activity 调用 Dialog 后回调)
*/ */
fun modifyLocationClick() { fun performModifyStorage(
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return locationName: String,
val selectedItems = list.filter { it.isSelected } locationId: String,
selectedItems: List<GjjManifest>
if (selectedItems.isEmpty()) { ) {
showToast("请选择要修改库位的记录") if (locationName.isEmpty() || locationId.isEmpty()) {
showToast("请选择库位")
return return
} }
showToast("修改库位功能开发中") val params = mapOf(
"location" to locationName,
"locationId" to locationId.toLongOrNull(),
"manifestList" to selectedItems
).toRequestBody()
launchLoadingCollect({ NetApply.api.modifyIntImpStorage(params) }) {
onSuccess = {
showToast("修改库位成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
onFailed = { _, msg ->
showToast(msg ?: "修改库位失败")
}
}
} }
/** /**
* 入库按钮点击 * 入库(由 Activity 调用 Dialog 后回调)
*/ */
fun inboundClick() { fun performInStorage(
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return locationName: String,
val selectedItems = list.filter { it.isSelected } locationId: String,
selectedItems: List<GjjManifest>
) {
if (selectedItems.isEmpty()) { if (selectedItems.isEmpty()) {
showToast("选择要入库的记录") showToast("至少选择一个单据")
return return
} }
showToast("入库功能开发中") if (locationName.isEmpty() || locationId.isEmpty()) {
showToast("请选择库位")
return
}
val params = mapOf(
"location" to locationName,
"locationId" to locationId.toLongOrNull(),
"manifestList" to selectedItems
).toRequestBody()
launchLoadingCollect({ NetApply.api.inIntImpStorage(params) }) {
onSuccess = {
showToast("入库成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
onFailed = { _, msg ->
showToast(msg ?: "入库失败")
}
}
} }
/** /**
@@ -113,7 +225,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
val filterParams = mapOf( val filterParams = mapOf(
"fdate" to flightDate.value?.ifEmpty { null }, "fdate" to flightDate.value?.ifEmpty { null },
"fno" to flightNo.value?.ifEmpty { null }, "fno" to flightNo.value?.ifEmpty { null },
"fdep" to fdep.value?.ifEmpty { null }, "sendAddress" to sendAddress.value?.ifEmpty { null },
"fdest" to fdest.value?.ifEmpty { null }, "fdest" to fdest.value?.ifEmpty { null },
"wbNo" to waybillNo.value?.ifEmpty { null } "wbNo" to waybillNo.value?.ifEmpty { null }
) )

View File

@@ -37,6 +37,70 @@ class IntImpManifestViewModel : BasePageViewModel() {
val fdep = MutableLiveData("") // 目的站 val fdep = MutableLiveData("") // 目的站
val waybillNo = MutableLiveData("") // 运单号 val waybillNo = MutableLiveData("") // 运单号
// ========== 航班级联查询 ==========
private var lastQueriedFlight = ""
private var fid = ""
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
queryFlightIfReady()
}
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
private fun queryFlightIfReady() {
val fdate = flightDate.value
val fno = flightNo.value
if (fdate.isNullOrEmpty() || fno.isNullOrEmpty()) return
val key = "$fdate-$fno"
if (key == lastQueriedFlight) return
lastQueriedFlight = key
launchCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
fid = flight.fid.noNull()
fdep.value = flight.fdest.noNull()
// 构建始发站下拉列表fdep + jtz经停港
val list = mutableListOf(
KeyValue(flight.fdep.noNull(), flight.fdep.noNull()),
)
if (!flight.jtz.isNullOrEmpty()) {
list.add(KeyValue(flight.jtz.noNull(), flight.jtz.noNull()))
}
sendAddressList.value = list
sendAddress.value = flight.fdep.noNull()
} else {
fid = ""
fdep.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
showToast(it.msg.noNull("获取航班信息失败"))
}
}
onFailed = { _, _ ->
fid = ""
fdep.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
}
}
}
// ========== 统计信息 ========== // ========== 统计信息 ==========
val totalCount = MutableLiveData("0") // 合计票数 val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数 val totalPc = MutableLiveData("0") // 总件数
@@ -45,11 +109,17 @@ class IntImpManifestViewModel : BasePageViewModel() {
// ========== 全选状态 ========== // ========== 全选状态 ==========
val isAllChecked = MutableLiveData(false) val isAllChecked = MutableLiveData(false)
// ========== 展开/收起 ==========
val isAllExpanded = MutableLiveData(false)
init { init {
// 监听全选状态,自动更新所有列表项 // 监听全选状态,自动更新所有列表项(联动子列表)
isAllChecked.observeForever { checked -> isAllChecked.observeForever { checked ->
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return@observeForever val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return@observeForever
list.forEach { it.checked.set(checked) } list.forEach {
it.checked.set(checked)
it.haWbList?.forEach { sub -> sub.checked.set(checked) }
}
pageModel.rv?.commonAdapter()?.notifyDataSetChanged() pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
} }
} }
@@ -66,19 +136,37 @@ class IntImpManifestViewModel : BasePageViewModel() {
} }
/** /**
* 全选按钮点击(切换全选状态) * 全选按钮点击(切换全选状态,联动子列表
*/ */
fun checkAllClick() { fun checkAllClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
// 切换全选状态 // 切换全选状态
val shouldCheckAll = !isAllChecked.value!! val shouldCheckAll = !isAllChecked.value!!
list.forEach { it.checked.set(shouldCheckAll) } list.forEach {
it.checked.set(shouldCheckAll)
it.haWbList?.forEach { sub -> sub.checked.set(shouldCheckAll) }
}
isAllChecked.value = shouldCheckAll isAllChecked.value = shouldCheckAll
pageModel.rv?.commonAdapter()?.notifyDataSetChanged() pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
} }
/**
* 全部展开/收起
*/
fun toggleAllExpand() {
val shouldExpand = !isAllExpanded.value!!
isAllExpanded.value = shouldExpand
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
list.forEach {
if (!it.haWbList.isNullOrEmpty()) {
it.showMore.set(shouldExpand)
}
}
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
/** /**
* 扫码运单号 * 扫码运单号
*/ */
@@ -90,25 +178,14 @@ class IntImpManifestViewModel : BasePageViewModel() {
* 新增按钮点击 * 新增按钮点击
*/ */
fun onAddClick() { fun onAddClick() {
// 获取当前航班信息
val fid = getCurrentFlightId()
GjjManifestAddActivity.start( GjjManifestAddActivity.start(
context = getTopActivity(), context = getTopActivity(),
fid = fid, fid = fid,
dep = fdep.value ?: "", dep = sendAddress.value ?: "",
dest = "" // 目的站暂时留空 dest = fdep.value ?: ""
) )
} }
/**
* 获取当前航班ID从列表第一项获取
*/
private fun getCurrentFlightId(): String {
val firstItem = pageModel.rv?.commonAdapter()?.items?.firstOrNull() as? GjjManifest
return firstItem?.fid?.toString() ?: ""
}
/** /**
* Item点击处理侧滑按钮 * Item点击处理侧滑按钮
*/ */
@@ -181,6 +258,10 @@ class IntImpManifestViewModel : BasePageViewModel() {
fun sortingTallyClick() { fun sortingTallyClick() {
com.alibaba.android.arouter.launcher.ARouter.getInstance() com.alibaba.android.arouter.launcher.ARouter.getInstance()
.build(com.lukouguoji.module_base.router.ARouterConstants.ACTIVITY_URL_INT_IMP_LOADING_LIST) .build(com.lukouguoji.module_base.router.ARouterConstants.ACTIVITY_URL_INT_IMP_LOADING_LIST)
.withString("fdate", flightDate.value ?: "")
.withString("fno", flightNo.value ?: "")
.withString("sendAddress", sendAddress.value ?: "")
.withString("fdest", fdep.value ?: "")
.navigation() .navigation()
} }
@@ -217,6 +298,14 @@ class IntImpManifestViewModel : BasePageViewModel() {
launchLoadingCollect({ NetApply.api.getIntImpManifestList(listParams) }) { launchLoadingCollect({ NetApply.api.getIntImpManifestList(listParams) }) {
onSuccess = { result -> onSuccess = { result ->
pageModel.handleListBean(result.data?.toBaseListBean()) pageModel.handleListBean(result.data?.toBaseListBean())
// 列表加载完成后,加载分单数据
val items = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest>
items?.forEach { bean ->
if (bean.haWbNum > 0) {
loadHaWbList(bean)
}
}
} }
} }
@@ -230,4 +319,22 @@ class IntImpManifestViewModel : BasePageViewModel() {
} }
} }
} }
/**
* 加载主单下的分单列表
*/
private fun loadHaWbList(bean: GjjManifest) {
val params = mapOf(
"mfId" to bean.mfId
).toRequestBody()
launchCollect({ NetApply.api.getIntImpManifestHaWbList(params) }) {
onSuccess = { result ->
if (result.verifySuccess() && !result.data.isNullOrEmpty()) {
bean.haWbList = result.data
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
}
}
}
} }

View File

@@ -10,6 +10,10 @@
<variable <variable
name="viewModel" name="viewModel"
type="com.lukouguoji.gjj.viewModel.IntImpLoadingListViewModel" /> type="com.lukouguoji.gjj.viewModel.IntImpLoadingListViewModel" />
<variable
name="activity"
type="com.lukouguoji.gjj.activity.IntImpLoadingListActivity" />
</data> </data>
<LinearLayout <LinearLayout
@@ -33,6 +37,7 @@
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期"}' hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}" icon="@{@drawable/img_date}"
setRefreshCallBack="@{viewModel::onFlightDateInputComplete}"
type="@{SearchLayoutType.DATE}" type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}" value="@={viewModel.flightDate}"
android:layout_width="0dp" android:layout_width="0dp"
@@ -42,24 +47,28 @@
<!-- 航班号 --> <!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入航班号"}' hint='@{"请输入航班号"}'
setRefreshCallBack="@{viewModel::onFlightNoInputComplete}"
setUpperCaseAlphanumeric="@{true}"
type="@{SearchLayoutType.INPUT}" type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}" value="@={viewModel.flightNo}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1" />
<!-- 始发站 --> <!-- 始发站(下拉列表) -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择始发站"}' hint='@{"请选择始发站"}'
type="@{SearchLayoutType.INPUT}" list="@{viewModel.sendAddressList}"
value="@={viewModel.fdep}" type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.sendAddress}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1" />
<!-- 目的站 --> <!-- 目的站(只读) -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"HFE"}' enable="@{false}"
hint='@{"目的站"}'
type="@{SearchLayoutType.INPUT}" type="@{SearchLayoutType.INPUT}"
value="@={viewModel.fdest}" value="@={viewModel.fdest}"
android:layout_width="0dp" android:layout_width="0dp"
@@ -198,7 +207,7 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:background="@drawable/bg_btn_bottom" android:background="@drawable/bg_btn_bottom"
android:gravity="center" android:gravity="center"
android:onClick="@{()-> viewModel.modifyLocationClick()}" android:onClick="@{()-> activity.showModifyStorageDialog()}"
android:text="修改库位" android:text="修改库位"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />
@@ -210,7 +219,7 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:background="@drawable/bg_btn_bottom" android:background="@drawable/bg_btn_bottom"
android:gravity="center" android:gravity="center"
android:onClick="@{()-> viewModel.inboundClick()}" android:onClick="@{()-> activity.showInStorageDialog()}"
android:text="入库" android:text="入库"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />

View File

@@ -33,6 +33,7 @@
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期"}' hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}" icon="@{@drawable/img_date}"
setRefreshCallBack="@{viewModel::onFlightDateInputComplete}"
type="@{SearchLayoutType.DATE}" type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}" value="@={viewModel.flightDate}"
android:layout_width="0dp" android:layout_width="0dp"
@@ -42,6 +43,7 @@
<!-- 航班号 --> <!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入航班号"}' hint='@{"请输入航班号"}'
setRefreshCallBack="@{viewModel::onFlightNoInputComplete}"
type="@{SearchLayoutType.INPUT}" type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}" value="@={viewModel.flightNo}"
setUpperCaseAlphanumeric="@{true}" setUpperCaseAlphanumeric="@{true}"
@@ -59,9 +61,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1" />
<!-- 目的站(固定HFE --> <!-- 目的站(航班查询自动填充 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"HFE"}' hint='@{"目的站"}'
enable="@{false}"
type="@{SearchLayoutType.INPUT}" type="@{SearchLayoutType.INPUT}"
value="@={viewModel.fdep}" value="@={viewModel.fdep}"
android:layout_width="0dp" android:layout_width="0dp"
@@ -114,6 +117,15 @@
android:padding="4dp" android:padding="4dp"
android:src="@drawable/img_delete" /> android:src="@drawable/img_delete" />
<!-- 展开/收起全部子列表 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:onClick="@{()-> viewModel.toggleAllExpand()}"
android:padding="4dp"
android:src="@drawable/ic_new_expand" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -15,19 +15,25 @@
type="Integer" /> type="Integer" />
</data> </data>
<com.mcxtzhang.swipemenulib.SwipeMenuLayout <!-- 主列表项容器 -->
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp"> android:layout_marginBottom="10dp"
android:orientation="vertical">
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 主内容区 --> <!-- 主内容区 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8" android:background="@drawable/bg_white_radius_8"
android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="15dp" android:padding="15dp">
android:gravity="center_vertical">
<!-- 选中图标(飞机图标,根据选择状态切换图片) --> <!-- 选中图标(飞机图标,根据选择状态切换图片) -->
<ImageView <ImageView
@@ -181,7 +187,7 @@
</LinearLayout> </LinearLayout>
<!-- 第三行:实到重量、计费重量、代理、特码、分单数 --> <!-- 第三行:实到重量、计费重量、代理、特码 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -362,4 +368,131 @@
</com.mcxtzhang.swipemenulib.SwipeMenuLayout> </com.mcxtzhang.swipemenulib.SwipeMenuLayout>
<!-- 展开/折叠按钮(仅当有分单时显示) -->
<ImageView
android:id="@+id/iv_show"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:padding="5dp"
android:src="@mipmap/img_down"
visible="@{bean.haWbList != null &amp;&amp; !bean.haWbList.empty}" />
<!-- 分单子列表容器(淡绿色背景) -->
<LinearLayout
visible="@{bean.showMore}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="#e3f6e0"
android:orientation="vertical"
android:visibility="gone">
<!-- 表头 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:orientation="horizontal"
android:paddingHorizontal="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:gravity="center"
android:text="选项"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center"
android:text="运单号"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center"
android:text="分单号"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="件数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="重量"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="原始舱单"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="理货报告"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center"
android:text="品名(中)"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/c999999" />
<!-- 子列表 RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_sub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
</layout> </layout>

View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:loadImage="http://schemas.android.com/tools">
<data>
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjjHaWb" />
<variable
name="position"
type="Integer" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="10dp"
android:paddingVertical="8dp">
<!-- 选项(单选框) -->
<ImageView
android:id="@+id/iv_checkbox"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:layout_weight="0.5"
loadImage="@{bean.checked.get() ? @drawable/radiobtn_checked_gray : @drawable/radiobtn_unchecked_gray}"
android:src="@drawable/radiobtn_unchecked_gray" />
<!-- 运单号 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:gravity="center"
android:text='@{bean.prefix + bean.no}'
android:textColor="@color/text_normal"
android:textSize="14sp" />
<!-- 分单号 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:gravity="center"
android:text="@{bean.hno ?? ``}"
android:textColor="@color/text_normal"
android:textSize="14sp" />
<!-- 件数 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:gravity="center"
android:text="@{String.valueOf((int)bean.pc)}"
android:textColor="@color/text_normal"
android:textSize="14sp" />
<!-- 重量 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:gravity="center"
android:text="@{String.valueOf((int)bean.weight)}"
android:textColor="@color/text_normal"
android:textSize="14sp" />
<!-- 原始舱单 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:gravity="center"
android:text="@{bean.mftStatus ?? ``}"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
<!-- 理货报告 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:gravity="center"
android:text="@{bean.lastMftStatus ?? ``}"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
<!-- 品名(中) -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:gravity="center"
android:text="@{bean.goods ?? ``}"
android:textColor="@color/text_normal"
android:textSize="14sp" />
</LinearLayout>
</layout>