From 6b79433557c2097df5f0ecb955ff596cc138967b Mon Sep 17 00:00:00 2001 From: YANGJIANKUAN Date: Fri, 12 Dec 2025 13:12:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=87=BA=E6=B8=AF=E7=90=86=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 6 + .../aerologic/ui/fragment/HomeFragment.kt | 14 + .../lukouguoji/module_base/common/Constant.kt | 1 + .../lukouguoji/module_base/http/net/Api.kt | 32 +++ .../module_base/router/ARouterConstants.kt | 1 + .../gjc/activity/IntExpTallyActivity.kt | 69 +++++ .../gjc/holder/IntExpTallyViewHolder.kt | 26 ++ .../gjc/viewModel/IntExpTallyViewModel.kt | 187 +++++++++++++ .../res/layout/activity_int_exp_tally.xml | 215 +++++++++++++++ .../main/res/layout/item_int_exp_tally.xml | 256 ++++++++++++++++++ 10 files changed, 807 insertions(+) create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpTallyActivity.kt create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt create mode 100644 module_gjc/src/main/res/layout/activity_int_exp_tally.xml create mode 100644 module_gjc/src/main/res/layout/item_int_exp_tally.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 43669c2..36cc6f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -121,6 +121,12 @@ android:configChanges="orientation|keyboardHidden" android:exported="false" android:screenOrientation="userLandscape" /> + + { + ARouter.getInstance() + .build(ARouterConstants.ACTIVITY_URL_INT_EXP_TALLY) + .navigation() + } // 出港运抵 Constant.AuthName.GjcIntExpArrive -> { ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE) @@ -703,6 +709,14 @@ class HomeFragment : Fragment() { ) ) + list.add( + RightMenu( + Constant.AuthName.GjcIntExpTally, + com.lukouguoji.module_base.R.drawable.img_gjc_banxiangzuzhuang, + "出港理货" + ) + ) + list.add( RightMenu( Constant.AuthName.GjcIntExpArrive, diff --git a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt index 938ee22..6bdc902 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt @@ -248,6 +248,7 @@ interface Constant { const val GjcAssembleAllocateActivity = "AppIntExpAssembleAllocate" //组装分配 const val GjcIntExpOutHandover = "AppIntExpOutHandover" //出库交接 const val GjcIntExpLoad = "AppIntExpLoad" //出港装载 + const val GjcIntExpTally = "AppIntExpTally" //出港理货 const val GjcIntExpArrive = "AppIntExpArrive" //出港运抵 /** 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 20a680c..2f9388e 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 @@ -669,6 +669,38 @@ interface Api { @POST("IntExpArrive/declare") suspend fun arriveDeclare(@Body data: RequestBody): BaseResultBean + /** + * 国际出港-出港理货-列表查询 + * 接口路径: /IntExpTally/pageQuery + * 返回: PageInfo + */ + @POST("IntExpTally/pageQuery") + suspend fun getIntExpTallyList(@Body data: RequestBody): BaseListBean + + /** + * 国际出港-出港理货-统计查询 + * 接口路径: /IntExpTally/pageQueryTotal + * 返回: ManifestTotalDto(合计票数、总件数、总重量) + */ + @POST("IntExpTally/pageQueryTotal") + suspend fun getIntExpTallyTotal(@Body data: RequestBody): BaseResultBean + + /** + * 国际出港-出港理货-理货申报 + * 接口路径: /IntExpTally/declare + * @param data 请求参数:选中的GjcMaWb列表 + */ + @POST("IntExpTally/declare") + suspend fun declareTally(@Body data: RequestBody): BaseResultBean + + /** + * 国际出港-出港理货-状态重置 + * 接口路径: /IntExpTally/resetDeclare + * @param data 请求参数:选中的GjcMaWb列表 + */ + @POST("IntExpTally/resetDeclare") + suspend fun resetTallyDeclare(@Body data: RequestBody): BaseResultBean + /** * 国际出港移库-分页查询 * 接口路径: /IntExpMove/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 cbf9752..5fda4ff 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 @@ -144,6 +144,7 @@ object ARouterConstants { const val ACTIVITY_URL_GJC_ASSEMBLE_ALLOCATE = "/gjc/GjcAssembleAllocateActivity" //国际出港 组装分配 const val ACTIVITY_URL_INT_EXP_OUT_HANDOVER = "/gjc/IntExpOutHandoverActivity" //国际出港 出库交接 const val ACTIVITY_URL_INT_EXP_LOAD = "/gjc/IntExpLoadActivity" //国际出港 出港装载 + const val ACTIVITY_URL_INT_EXP_TALLY = "/gjc/IntExpTallyActivity" //国际出港 出港理货 const val ACTIVITY_URL_INT_EXP_ARRIVE = "/gjc/IntExpArriveActivity" //国际出港 出港运抵 ///////////////// 国际进港模块 diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpTallyActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpTallyActivity.kt new file mode 100644 index 0000000..792d12f --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpTallyActivity.kt @@ -0,0 +1,69 @@ +package com.lukouguoji.gjc.activity + +import android.app.Activity +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.ActivityIntExpTallyBinding +import com.lukouguoji.gjc.viewModel.IntExpTallyViewModel +import com.lukouguoji.module_base.base.BaseBindingActivity +import com.lukouguoji.module_base.common.Constant +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.interfaces.IOnItemClickListener +import com.lukouguoji.module_base.ktx.addOnItemClickListener +import com.lukouguoji.module_base.router.ARouterConstants + +/** + * 国际出港-出港理货 + */ +@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_TALLY) +class IntExpTallyActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_int_exp_tally + override fun viewModelClass() = IntExpTallyViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("出港理货") + binding.viewModel = viewModel + + // 观察全选状态,动态调整图标透明度 + viewModel.isAllChecked.observe(this) { isAllChecked -> + binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f + } + + // 绑定分页 + viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this) + + // 设置item点击监听 + binding.rv.addOnItemClickListener(viewModel) + + // 监听刷新事件 + FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { + viewModel.refresh() + } + + // 初始加载数据 + viewModel.refresh() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + val codedContent = data?.getStringExtra(Constant.Result.CODED_CONTENT) ?: return + when (requestCode) { + Constant.RequestCode.WAYBILL -> { // 运单号 + viewModel.waybillNo.value = codedContent + viewModel.searchClick() + } + Constant.RequestCode.CODE -> { // 分单号 + viewModel.houseWaybillNo.value = codedContent + viewModel.searchClick() + } + } + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt new file mode 100644 index 0000000..a45ccd7 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt @@ -0,0 +1,26 @@ +package com.lukouguoji.gjc.holder + +import android.view.View +import com.lukouguoji.gjc.databinding.ItemIntExpTallyBinding +import com.lukouguoji.module_base.base.BaseViewHolder +import com.lukouguoji.module_base.bean.GjcMaWb + +/** + * 国际出港-出港理货 ViewHolder + */ +class IntExpTallyViewHolder(view: View) : + BaseViewHolder(view) { + + override fun onBind(item: Any?, position: Int) { + val bean = getItemBean(item) ?: return + binding.bean = bean + binding.position = position + binding.executePendingBindings() + + // 图标点击切换选择状态 + binding.ivIcon.setOnClickListener { + bean.checked.set(!bean.checked.get()) + binding.executePendingBindings() + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt new file mode 100644 index 0000000..fbc1af5 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt @@ -0,0 +1,187 @@ +package com.lukouguoji.gjc.viewModel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.holder.IntExpTallyViewHolder +import com.lukouguoji.module_base.base.BasePageViewModel +import com.lukouguoji.module_base.bean.GjcCheckInPage +import com.lukouguoji.module_base.bean.GjcMaWb +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.impl.FlowBus +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.showToast +import com.lukouguoji.module_base.ktx.toRequestBody +import com.lukouguoji.module_base.model.ScanModel +import kotlinx.coroutines.launch + +/** + * 国际出港-出港理货 ViewModel + */ +class IntExpTallyViewModel : BasePageViewModel() { + + // ========== 搜索条件 ========== + val flightDate = MutableLiveData("") // 航班日期 + val flightNo = MutableLiveData("") // 航班号 + val waybillNo = MutableLiveData("") // 运单号 + val houseWaybillNo = MutableLiveData("") // 分单号 + + // ========== 统计信息 ========== + val totalCount = MutableLiveData("0") // 合计票数 + val totalPc = MutableLiveData("0") // 总件数 + val totalWeight = MutableLiveData("0") // 总重量 + + // ========== 全选状态 ========== + val isAllChecked = MutableLiveData(false) + + init { + // 监听全选状态,自动更新所有列表项 + isAllChecked.observeForever { checked -> + val list = pageModel.rv?.commonAdapter()?.items as? List ?: return@observeForever + list.forEach { it.checked.set(checked) } + pageModel.rv?.commonAdapter()?.notifyDataSetChanged() + } + } + + // ========== 适配器配置 ========== + val itemViewHolder = IntExpTallyViewHolder::class.java + val itemLayoutId = R.layout.item_int_exp_tally + + /** + * 搜索按钮点击 + */ + fun searchClick() { + refresh() + } + + /** + * 全选按钮点击 (切换全选状态) + */ + fun checkAllClick() { + val list = pageModel.rv?.commonAdapter()?.items as? List ?: return + + // 切换全选状态 + val shouldCheckAll = !isAllChecked.value!! + list.forEach { it.checked.set(shouldCheckAll) } + isAllChecked.value = shouldCheckAll + + pageModel.rv?.commonAdapter()?.notifyDataSetChanged() + } + + /** + * 扫码运单号 + */ + fun scanWaybill() { + ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL) + } + + /** + * 扫码分单号 + */ + fun scanHouseWaybill() { + ScanModel.startScan(getTopActivity(), Constant.RequestCode.CODE) + } + + /** + * 状态重置 (批量操作) + */ + fun resetDeclare() { + val list = pageModel.rv?.commonAdapter()?.items as? List ?: return + val selectedItems = list.filter { it.isSelected } + + if (selectedItems.isEmpty()) { + showToast("请选择要重置的记录") + return + } + + val requestData = selectedItems.toRequestBody() + + launchLoadingCollect({ NetApply.api.resetTallyDeclare(requestData) }) { + onSuccess = { + showToast("状态重置成功") + viewModelScope.launch { + FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() + } + } + } + + /** + * 理货申报 (批量操作) + */ + fun declareTally() { + val list = pageModel.rv?.commonAdapter()?.items as? List ?: return + val selectedItems = list.filter { it.isSelected } + + if (selectedItems.isEmpty()) { + showToast("请选择要理货的记录") + return + } + + val requestData = selectedItems.toRequestBody() + + launchLoadingCollect({ NetApply.api.declareTally(requestData) }) { + onSuccess = { + showToast("理货申报成功") + viewModelScope.launch { + FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() + } + } + } + + /** + * 删除申报 (批量操作) + * TODO: 待实现 + */ + fun deleteTally() { + // 暂不实现,预留接口 + } + + /** + * 获取数据 (重写BasePageViewModel) + */ + override fun getData() { + // 构建查询参数对象 + val pageParams = GjcCheckInPage( + fdate = flightDate.value?.ifEmpty { null }, + fno = flightNo.value?.ifEmpty { null }, + no = waybillNo.value?.ifEmpty { null }, + hno = houseWaybillNo.value?.ifEmpty { null }, + pageNum = pageModel.page, + pageSize = pageModel.limit + ) + + // 列表参数 (含分页) + val listParams = pageParams.toRequestBody() + + // 统计参数 (无分页) + val totalParams = GjcCheckInPage( + fdate = flightDate.value?.ifEmpty { null }, + fno = flightNo.value?.ifEmpty { null }, + no = waybillNo.value?.ifEmpty { null }, + hno = houseWaybillNo.value?.ifEmpty { null } + ).toRequestBody() + + // 获取列表 (带Loading) + launchLoadingCollect({ NetApply.api.getIntExpTallyList(listParams) }) { + onSuccess = { pageModel.handleListBean(it) } + } + + // 获取统计信息 (后台请求,不阻塞列表) + launchCollect({ NetApply.api.getIntExpTallyTotal(totalParams) }) { + onSuccess = { result -> + val data = result.data + totalCount.value = (data?.wbNumber ?: 0).toString() + totalPc.value = (data?.totalPc ?: 0).toString() + totalWeight.value = (data?.totalWeight ?: 0.0).toString() + } + } + } +} diff --git a/module_gjc/src/main/res/layout/activity_int_exp_tally.xml b/module_gjc/src/main/res/layout/activity_int_exp_tally.xml new file mode 100644 index 0000000..9bbd0c0 --- /dev/null +++ b/module_gjc/src/main/res/layout/activity_int_exp_tally.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_int_exp_tally.xml b/module_gjc/src/main/res/layout/item_int_exp_tally.xml new file mode 100644 index 0000000..6aa6dda --- /dev/null +++ b/module_gjc/src/main/res/layout/item_int_exp_tally.xml @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +