refactor: 国际出港移库详情/编辑按最新接口文档重新对接

- 新增 GjcMoveDetail Bean 对应 /IntExpMove/detail 返回与 /IntExpMove/update 请求体
- 承运人改取 by、运单类型改取 awbTypeName,去掉文档中不存在的航班字段,新增移交状态展示
- 保存时回传完整详情对象,仅替换备注与 pic/originalPic/picNumber
- 列表 Bean 随 Intent 传入,回填 detail 返回为空的承运人、出运路径等展示字段

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 14:55:54 +08:00
parent 85fd66b005
commit efe7a1d2a9
6 changed files with 106 additions and 46 deletions

View File

@@ -0,0 +1,29 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港移库详情数据模型
* 对应接口:/IntExpMove/detail 返回的 data/IntExpMove/update 的请求体
*/
data class GjcMoveDetail(
var maWbId: Long? = null, // GJC_MAWB.MAWBID
var wbNo: String? = null, // 运单号
var pc: Long? = null, // 件数
var weight: Double? = null, // 重量
var by: String? = null, // 承运人1
var awbTypeName: String? = null, // 运单类型(中文)
var range: String? = null, // 出运路径
var spCode: String? = null, // 特码
var agentCode: String? = null, // 代理人
var moveState: Int? = null, // 交接状态0 未交接1 已交接
var goods: String? = null, // 品名
var remark: String? = null, // 备注
var pic: String? = null, // 交接图片缩略图路径(逗号分隔)
var originalPic: String? = null, // 交接图片原图路径(逗号分隔)
var picNumber: String? = null // 交接图片数量
) {
/**
* 移交状态中文(与列表项文案一致)
*/
val moveStateText: String
get() = if (moveState == 1) "已移交" else "未移交"
}

View File

@@ -37,6 +37,7 @@ import com.lukouguoji.module_base.bean.GjcHandoverSheetResponse
import com.lukouguoji.module_base.bean.GjcInspectionBean import com.lukouguoji.module_base.bean.GjcInspectionBean
import com.lukouguoji.module_base.bean.GjcMaWb import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.bean.GjcMove import com.lukouguoji.module_base.bean.GjcMove
import com.lukouguoji.module_base.bean.GjcMoveDetail
import com.lukouguoji.module_base.bean.GjcUldUseBean import com.lukouguoji.module_base.bean.GjcUldUseBean
import com.lukouguoji.module_base.bean.GjcWarehouse import com.lukouguoji.module_base.bean.GjcWarehouse
import com.lukouguoji.module_base.bean.GjcWaybillBean import com.lukouguoji.module_base.bean.GjcWaybillBean
@@ -897,7 +898,7 @@ interface Api {
* 接口路径: /IntExpMove/detail * 接口路径: /IntExpMove/detail
*/ */
@POST("IntExpMove/detail") @POST("IntExpMove/detail")
suspend fun getIntExpMoveDetail(@Query("maWbId") maWbId: Long): BaseResultBean<GjcMaWb> suspend fun getIntExpMoveDetail(@Query("maWbId") maWbId: Long): BaseResultBean<GjcMoveDetail>
/** /**
* 国际出港移库-编辑(仅更新备注与交接图片) * 国际出港移库-编辑(仅更新备注与交接图片)

View File

@@ -34,13 +34,13 @@ class IntExpMoveViewHolder(view: View) :
// 点击列表项进入移库详情 // 点击列表项进入移库详情
binding.ll.setOnClickListener { binding.ll.setOnClickListener {
IntExpMoveEditActivity.startForDetails(itemView.context, bean.maWbId) IntExpMoveEditActivity.startForDetails(itemView.context, bean)
} }
// 侧滑菜单 - 编辑按钮 // 侧滑菜单 - 编辑按钮
binding.btnEdit.setOnClickListener { binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose() binding.swipeMenu.quickClose()
IntExpMoveEditActivity.startForEdit(itemView.context, bean.maWbId) IntExpMoveEditActivity.startForEdit(itemView.context, bean)
} }
binding.executePendingBindings() binding.executePendingBindings()

View File

@@ -4,10 +4,12 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route import com.alibaba.android.arouter.facade.annotation.Route
import com.google.gson.Gson
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpMoveEditBinding import com.lukouguoji.gjc.databinding.ActivityIntExpMoveEditBinding
import com.lukouguoji.gjc.viewModel.IntExpMoveEditViewModel import com.lukouguoji.gjc.viewModel.IntExpMoveEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjcMove
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.addOnItemClickListener import com.lukouguoji.module_base.ktx.addOnItemClickListener
@@ -49,19 +51,25 @@ class IntExpMoveEditActivity :
} }
companion object { companion object {
/**
* 列表 Bean 一并传入detail 接口的承运人、出运路径等字段可能为空,
* 由 ViewModel 用列表数据回填
*/
@JvmStatic @JvmStatic
fun startForEdit(context: Context, maWbId: Long?) { fun startForEdit(context: Context, bean: GjcMove) {
val starter = Intent(context, IntExpMoveEditActivity::class.java) start(context, bean, DetailsPageType.Modify)
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Modify.name)
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "")
context.startActivity(starter)
} }
@JvmStatic @JvmStatic
fun startForDetails(context: Context, maWbId: Long?) { fun startForDetails(context: Context, bean: GjcMove) {
start(context, bean, DetailsPageType.Details)
}
private fun start(context: Context, bean: GjcMove, pageType: DetailsPageType) {
val starter = Intent(context, IntExpMoveEditActivity::class.java) val starter = Intent(context, IntExpMoveEditActivity::class.java)
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Details.name) .putExtra(Constant.Key.PAGE_TYPE, pageType.name)
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "") .putExtra(Constant.Key.ID, bean.maWbId.toString())
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
context.startActivity(starter) context.startActivity(starter)
} }
} }

View File

@@ -6,8 +6,10 @@ import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
import com.lukouguoji.module_base.base.BaseViewModel import com.lukouguoji.module_base.base.BaseViewModel
import com.google.gson.Gson
import com.lukouguoji.module_base.bean.FileBean import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.bean.GjcMaWb import com.lukouguoji.module_base.bean.GjcMove
import com.lukouguoji.module_base.bean.GjcMoveDetail
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.common.DetailsPageType import com.lukouguoji.module_base.common.DetailsPageType
@@ -25,14 +27,18 @@ import kotlinx.coroutines.launch
/** /**
* 国际出港移库编辑/详情 ViewModel * 国际出港移库编辑/详情 ViewModel
* 编辑模式仅支持修改备注与交接图片 * 详情:/IntExpMove/detail?maWbId= 返回 GjcMoveDetail
* 编辑:/IntExpMove/update 请求体为 GjcMoveDetail仅允许修改备注与交接图片
*/ */
class IntExpMoveEditViewModel : BaseViewModel(), IOnItemClickListener { class IntExpMoveEditViewModel : BaseViewModel(), IOnItemClickListener {
val pageType = MutableLiveData(DetailsPageType.Details) val pageType = MutableLiveData(DetailsPageType.Details)
private var maWbId: Long = 0L private var maWbId: Long = 0L
val dataBean = MutableLiveData(GjcMaWb()) // 列表页传入的运单数据,用于回填 detail 接口返回为空的展示字段(承运人、出运路径等)
private var listBean: GjcMove? = null
val dataBean = MutableLiveData(GjcMoveDetail())
// 备注单独用 LiveData 双向绑定,避免修改 data class 属性后需重新赋值 // 备注单独用 LiveData 双向绑定,避免修改 data class 属性后需重新赋值
val remark = MutableLiveData("") val remark = MutableLiveData("")
@@ -55,21 +61,22 @@ class IntExpMoveEditViewModel : BaseViewModel(), IOnItemClickListener {
intent.getStringExtra(Constant.Key.PAGE_TYPE) ?: DetailsPageType.Details.name intent.getStringExtra(Constant.Key.PAGE_TYPE) ?: DetailsPageType.Details.name
) )
maWbId = intent.getStringExtra(Constant.Key.ID)?.toLongOrNull() ?: 0L maWbId = intent.getStringExtra(Constant.Key.ID)?.toLongOrNull() ?: 0L
listBean = intent.getStringExtra(Constant.Key.DATA)
?.takeIf { it.isNotEmpty() }
?.let { runCatching { Gson().fromJson(it, GjcMove::class.java) }.getOrNull() }
loadData() loadData()
} }
private fun loadData() { private fun loadData() {
launchLoadingCollect({ NetApply.api.getIntExpMoveDetail(maWbId) }) { launchLoadingCollect({ NetApply.api.getIntExpMoveDetail(maWbId) }) {
onSuccess = { onSuccess = {
val bean = it.data ?: GjcMaWb() val bean = it.data ?: GjcMoveDetail()
// 详情接口 wbNo 可能为空,回退为 前缀 + 运单号 if (bean.maWbId == null) bean.maWbId = maWbId
if (bean.wbNo.isNullOrEmpty()) { fillFromListBean(bean)
bean.wbNo = (bean.prefix ?: "") + (bean.no ?: "")
}
dataBean.value = bean dataBean.value = bean
remark.value = bean.remark ?: "" remark.value = bean.remark ?: ""
// 处理图片列表(同时保留缩略图和原图信息,确保二次编辑时不丢失) // 解析图片pic 为缩略图、originalPic 为原图,二者按逗号分隔且一一对应
val picList = (bean.pic ?: "").split(",").filter { p -> p.isNotEmpty() } val picList = (bean.pic ?: "").split(",").filter { p -> p.isNotEmpty() }
val originalPicList = (bean.originalPic ?: "").split(",").filter { p -> p.isNotEmpty() } val originalPicList = (bean.originalPic ?: "").split(",").filter { p -> p.isNotEmpty() }
val images = if (picList.isNotEmpty()) { val images = if (picList.isNotEmpty()) {
@@ -101,7 +108,22 @@ class IntExpMoveEditViewModel : BaseViewModel(), IOnItemClickListener {
} }
/** /**
* 提交保存(只保存备注和图片) * detail 接口的部分展示字段(承运人 by、出运路径 range 等)在测试环境返回 null
* 列表接口有值时用列表数据回填,仅影响展示
*/
private fun fillFromListBean(bean: GjcMoveDetail) {
val src = listBean ?: return
if (bean.wbNo.isNullOrEmpty()) bean.wbNo = src.wbNo.ifEmpty { src.prefix + src.no }
if (bean.by.isNullOrEmpty()) bean.by = src.by1
if (bean.range.isNullOrEmpty()) bean.range = src.range
if (bean.spCode.isNullOrEmpty()) bean.spCode = src.spCode
if (bean.agentCode.isNullOrEmpty()) bean.agentCode = src.agentCode
if (bean.awbTypeName.isNullOrEmpty()) bean.awbTypeName = src.awbTypeName
if (bean.goods.isNullOrEmpty()) bean.goods = src.goodsCn.ifEmpty { src.goods }
}
/**
* 提交保存:按接口文档回传完整详情对象,仅备注与交接图片三字段取页面上的新值
*/ */
fun submit() { fun submit() {
// 从 adapter 实时获取所有非空图片ViewHolder 新增图片直接操作 adapter items // 从 adapter 实时获取所有非空图片ViewHolder 新增图片直接操作 adapter items
@@ -126,15 +148,15 @@ class IntExpMoveEditViewModel : BaseViewModel(), IOnItemClickListener {
} }
} }
val params = mapOf( val bean = (dataBean.value ?: GjcMoveDetail()).copy(
"maWbId" to maWbId, maWbId = maWbId,
"remark" to (remark.value ?: ""), remark = remark.value ?: "",
"picNumber" to images.size.toString(), picNumber = images.size.toString(),
"pic" to images.joinToString(",") { MediaUtil.removeUrl(it.url) }, pic = images.joinToString(",") { MediaUtil.removeUrl(it.url) },
"originalPic" to images.joinToString(",") { MediaUtil.removeUrl(it.originalPic) }, originalPic = images.joinToString(",") { MediaUtil.removeUrl(it.originalPic) }
).toRequestBody(removeEmptyOrNull = true) )
NetApply.api.updateIntExpMove(params) NetApply.api.updateIntExpMove(bean.toRequestBody())
}) { }) {
onSuccess = { onSuccess = {
showToast("保存成功") showToast("保存成功")

View File

@@ -114,27 +114,17 @@
title='@{"品名"}' title='@{"品名"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.goodsCn == null || viewModel.dataBean.goodsCn.isEmpty() ? viewModel.dataBean.goods : viewModel.dataBean.goodsCn}' /> value='@{viewModel.dataBean.goods}' />
</LinearLayout> </LinearLayout>
<!-- 第三行:出港航班、出运路径、运单类型(均只读 --> <!-- 第三行:出运路径、运单类型、承运人(均只读,字段名以 /IntExpMove/detail 文档为准 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:orientation="horizontal"> 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}"
title='@{"出港航班"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.flightInfo}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -143,7 +133,7 @@
title='@{"出运路径"}' title='@{"出运路径"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.rangeText}' /> value='@{viewModel.dataBean.range}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp" android:layout_width="0dp"
@@ -153,11 +143,21 @@
title='@{"运单类型"}' title='@{"运单类型"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.awbName}' /> value='@{viewModel.dataBean.awbTypeName}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"承运人"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.by}' />
</LinearLayout> </LinearLayout>
<!-- 第四行:承运人(只读)、备注(编辑模式可编辑) --> <!-- 第四行:移交状态(只读)、备注(编辑模式可编辑) -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -169,10 +169,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
enable="@{false}" enable="@{false}"
title='@{"承运人"}' title='@{"移交状态"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.by1}' /> value='@{viewModel.dataBean.moveStateText}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp" android:layout_width="0dp"