feat: 国际进港舱单分单新增与编辑页面

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 10:32:10 +08:00
parent a64b963d03
commit f61302a1f6
8 changed files with 510 additions and 5 deletions

View File

@@ -77,7 +77,12 @@
"Read(//tmp/**)",
"mcp__apifox__read_project_oas_3gn3lx",
"mcp__apifox__read_project_oas_ref_resources_3gn3lx",
"mcp__apifox__refresh_project_oas_3gn3lx"
"mcp__apifox__refresh_project_oas_3gn3lx",
"Bash(cp \"/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/Warp 2026-03-13 09.54.13.tiff\" /tmp/screenshot.png)",
"Read(//private/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/**)",
"mcp__apifox__read_project_oas_2s2uhx",
"mcp__apifox__read_project_oas_ref_resources_2s2uhx",
"mcp__apifox__refresh_project_oas_2s2uhx"
],
"deny": [],
"ask": []

View File

@@ -425,6 +425,13 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-进港舱单分单编辑 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpManifestSubEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-进港舱单详情 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpManifestDetailsActivity"

View File

@@ -1834,6 +1834,24 @@ interface Api {
@POST("IntImpManifest/listHaWbByManifest")
suspend fun getIntImpManifestHaWbList(@Body data: RequestBody): BaseResultBean<List<GjjHaWb>>
/**
* 国际进港舱单-新增分单
*/
@POST("IntImpManifest/addHaWb")
suspend fun intImpManifestAddHaWb(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港舱单-修改分单
*/
@POST("IntImpManifest/modifyHaWb")
suspend fun intImpManifestModifyHaWb(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港舱单-获取主单减去分单的件数重量
*/
@POST("IntImpManifest/getMaWbMinusHaWb")
suspend fun getMaWbMinusHaWb(@Body data: RequestBody): BaseResultBean<GjjHaWb>
/**
* 国际进港舱单-分拣理货(装机单)-分页查询
*/

View File

@@ -0,0 +1,59 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpManifestSubEditBinding
import com.lukouguoji.gjj.viewModel.IntImpManifestSubEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjjHaWb
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType
class IntImpManifestSubEditActivity :
BaseBindingActivity<ActivityIntImpManifestSubEditBinding, IntImpManifestSubEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_manifest_sub_edit
override fun viewModelClass() = IntImpManifestSubEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
val title = when (viewModel.pageType.value) {
DetailsPageType.Modify -> "分单编辑"
else -> "分单新增"
}
setBackArrow(title)
}
companion object {
/**
* 新增分单
*/
@JvmStatic
fun startForAdd(context: Context, manifest: GjjManifest) {
context.startActivity(
Intent(context, IntImpManifestSubEditActivity::class.java)
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Add.name)
.putExtra(Constant.Key.BEAN, manifest)
)
}
/**
* 修改分单
*/
@JvmStatic
fun startForModify(context: Context, manifest: GjjManifest, haWb: GjjHaWb) {
context.startActivity(
Intent(context, IntImpManifestSubEditActivity::class.java)
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Modify.name)
.putExtra(Constant.Key.BEAN, manifest)
.putExtra("haWb", haWb)
)
}
}
}

View File

@@ -0,0 +1,144 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjjHaWb
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
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 kotlinx.coroutines.launch
/**
* 国际进港舱单-分单编辑 ViewModel
*/
class IntImpManifestSubEditViewModel : BaseViewModel() {
// 页面类型
val pageType = MutableLiveData(DetailsPageType.Add)
// 分单ID编辑时使用
var hawbId: Long = 0
// 主单ID
var mfId: Long = 0
// 运单号前缀和编号(从主单获取,保存时需传给接口)
var prefix: String = ""
var no: String = ""
// 表单字段
val waybillNo = MutableLiveData("") // 运单号(只读)
val mainSubCheck = MutableLiveData("") // 主分校验(只读)
val subNo = MutableLiveData("") // 分单号
val pc = MutableLiveData("") // 件数
val weight = MutableLiveData("") // 重量
val goodsCn = MutableLiveData("") // 品名(中)
/**
* 初始化从Intent获取参数
*/
fun initOnCreated(intent: Intent) {
pageType.value = DetailsPageType.valueOf(
intent.getStringExtra(Constant.Key.PAGE_TYPE) ?: DetailsPageType.Add.name
)
// 获取主单信息
val manifest = intent.getSerializableExtra(Constant.Key.BEAN) as? GjjManifest
if (manifest != null) {
mfId = manifest.mfId
prefix = manifest.prefix
no = manifest.no
waybillNo.value = manifest.getWaybillNo()
}
// 编辑模式:回填分单数据
if (pageType.value == DetailsPageType.Modify) {
val haWb = intent.getSerializableExtra("haWb") as? GjjHaWb
if (haWb != null) {
hawbId = haWb.hawbId
subNo.value = haWb.hno
pc.value = if (haWb.pc > 0) haWb.pc.toString() else ""
weight.value = if (haWb.weight > 0) haWb.weight.toString() else ""
goodsCn.value = haWb.goodsCn
}
}
// 获取主分校验数据
loadMainSubCheck()
}
/**
* 获取主单减去分单的件数重量
*/
private fun loadMainSubCheck() {
if (mfId == 0L) return
val params = mapOf("mfId" to mfId).toRequestBody()
launchCollect({ NetApply.api.getMaWbMinusHaWb(params) }) {
onSuccess = { result ->
if (result.verifySuccess() && result.data != null) {
val data = result.data!!
mainSubCheck.value = "剩余件数:${data.pc} 剩余重量:${data.weight}"
}
}
}
}
/**
* 保存
*/
fun onSaveClick() {
val params = mutableMapOf<String, Any?>(
"mfId" to mfId,
"prefix" to prefix,
"no" to no,
"hno" to subNo.value,
"pc" to pc.value?.toLongOrNull(),
"weight" to weight.value?.toDoubleOrNull(),
"goodsCn" to goodsCn.value,
"goods" to goodsCn.value
)
if (pageType.value == DetailsPageType.Modify) {
params["hawbId"] = hawbId
}
launchLoadingCollect({
if (pageType.value == DetailsPageType.Modify) {
NetApply.api.intImpManifestModifyHaWb(params.toRequestBody())
} else {
NetApply.api.intImpManifestAddHaWb(params.toRequestBody())
}
}) {
onSuccess = {
if (it.verifySuccess()) {
val msg = if (pageType.value == DetailsPageType.Modify) "修改成功" else "新增成功"
showToast(msg)
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
} else {
showToast(it.msg.noNull("保存失败"))
}
}
}
}
/**
* 取消
*/
fun onCancelClick() {
getTopActivity().finish()
}
}

View File

@@ -6,6 +6,7 @@ import com.lukouguoji.gjj.R
import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.gjj.activity.GjjManifestAddActivity
import com.lukouguoji.gjj.activity.IntImpManifestSubEditActivity
import com.lukouguoji.gjj.holder.IntImpManifestViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.GjjManifest
@@ -117,6 +118,9 @@ class IntImpManifestViewModel : BasePageViewModel() {
// ========== 展开/收起 ==========
val isAllExpanded = MutableLiveData(false)
// ========== 分单管理模式 ==========
val isSubManagementMode = MutableLiveData(false)
init {
// 监听全选状态,自动更新所有列表项(联动子列表)
isAllChecked.observeForever { checked ->
@@ -342,10 +346,65 @@ class IntImpManifestViewModel : BasePageViewModel() {
}
/**
* 分单管理(暂不实现)
* 分单管理按钮点击 - 进入分单管理模式
*/
fun subManagementClick() {
showToast("分单管理功能开发中")
isSubManagementMode.value = true
}
/**
* 分单管理模式 - 返回按钮点击
*/
fun subManagementBackClick() {
isSubManagementMode.value = false
}
/**
* 新增分单 - 选中一个主单后打开新增页面
*/
fun addSubWaybillClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择一个主单")
return
}
if (selectedItems.size > 1) {
showToast("只能选择一个主单")
return
}
IntImpManifestSubEditActivity.startForAdd(getTopActivity(), selectedItems[0])
}
/**
* 修改分单 - 选中一个分单后打开编辑页面
*/
fun modifySubWaybillClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
// 收集所有已选中的分单及其所属主单
val selectedPairs = mutableListOf<Pair<GjjManifest, com.lukouguoji.module_base.bean.GjjHaWb>>()
list.forEach { manifest ->
manifest.haWbList?.forEach { haWb ->
if (haWb.isSelected) {
selectedPairs.add(manifest to haWb)
}
}
}
if (selectedPairs.isEmpty()) {
showToast("请选择一个分单")
return
}
if (selectedPairs.size > 1) {
showToast("只能选择一个分单")
return
}
val (parentManifest, selectedHaWb) = selectedPairs[0]
IntImpManifestSubEditActivity.startForModify(getTopActivity(), parentManifest, selectedHaWb)
}
/**

View File

@@ -6,6 +6,7 @@
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<import type="android.view.View" />
<variable
name="viewModel"
@@ -159,6 +160,22 @@
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- 分单管理模式 - 返回按钮(列表区域右上方) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingHorizontal="20dp"
android:visibility="@{viewModel.isSubManagementMode ? View.VISIBLE : View.GONE}">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.subManagementBackClick()}"
android:src="@drawable/img_back_action" />
</LinearLayout>
<!-- 底部统计和操作按钮 -->
<LinearLayout
android:layout_width="match_parent"
@@ -229,12 +246,28 @@
</LinearLayout>
<!-- 操作按钮 -->
<!-- 操作按钮 - 默认模式 -->
<TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.subManagementClick()}"
android:text="分单管理" />
android:text="分单管理"
android:visibility="@{viewModel.isSubManagementMode ? View.GONE : View.VISIBLE}" />
<!-- 操作按钮 - 分单管理模式 -->
<TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.addSubWaybillClick()}"
android:text="新增分单"
android:visibility="@{viewModel.isSubManagementMode ? View.VISIBLE : View.GONE}" />
<TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.modifySubWaybillClick()}"
android:text="修改分单"
android:visibility="@{viewModel.isSubManagementMode ? View.VISIBLE : View.GONE}" />
<TextView
style="@style/tv_bottom_btn"

View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
<variable
name="viewModel"
type="com.lukouguoji.gjj.viewModel.IntImpManifestSubEditViewModel" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 主内容区域 -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="8dp">
<!-- 第1行运单号只读、主分校验只读、分单号 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
hint='@{"运单号"}'
required="@{false}"
title='@{"运 单 号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.waybillNo}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
enable="@{false}"
hint='@{"主分校验"}'
required="@{false}"
title='@{"主分校验"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.mainSubCheck}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入分单号"}'
required="@{false}"
title='@{"分 单 号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.subNo}' />
</LinearLayout>
<!-- 第2行件数、重量、品名(中) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入件数"}'
required="@{false}"
title='@{"件 数"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.pc}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入重量"}'
required="@{false}"
title='@{"重 量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.weight}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入品名(中)"}'
required="@{false}"
title='@{"品名(中)"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.goodsCn}' />
</LinearLayout>
</LinearLayout>
<!-- 底部操作栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginEnd="30dp"
android:background="@drawable/bg_primary_radius_4"
android:gravity="center"
android:onClick="@{()-> viewModel.onCancelClick()}"
android:text="取消"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:background="@drawable/bg_primary_radius_4"
android:gravity="center"
android:onClick="@{()-> viewModel.onSaveClick()}"
android:text="保存"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
</FrameLayout>
</layout>