Compare commits

...

56 Commits

Author SHA1 Message Date
c6fe8f5310 feat: 开始组装 opt 2025-12-19 11:42:21 +08:00
b8fbc304f1 feat: opt 开始装载 2025-12-18 16:34:06 +08:00
3df9a9f73f feat: opt 开始装载 2025-12-18 15:28:37 +08:00
222ae8a0f5 feat: opt 开始组装 tree 2025-12-18 11:34:06 +08:00
1906e7ce65 feat: 出港组装 开始组装 status color 2025-12-18 10:59:03 +08:00
01306d1302 feat: 出港组装 开始组装 卸货、装货 api 2025-12-18 10:10:04 +08:00
e208d54a3c feat: 开始组装 opt 2025-12-18 09:52:13 +08:00
2664cc7c69 feat: 开始组装 opt 2025-12-16 15:58:37 +08:00
644c937476 feat: 开始组装 2025-12-16 15:36:13 +08:00
ced24685ee feat: opt 编码输入 2025-12-16 15:27:06 +08:00
fafe092b3c feat: opt 板箱过磅 print 2025-12-16 15:12:17 +08:00
eb1d356bd2 feat: opt 板箱过磅 auto calc 2025-12-16 14:07:11 +08:00
f3056d3807 feat: opt 板箱过磅 add 2025-12-16 11:00:44 +08:00
1eadb9043e feat: 国际出港 收运检查 退回 list 2025-12-16 10:31:54 +08:00
bd8d6f683a feat: 国际出港 收运检查 退回 2025-12-16 10:21:05 +08:00
1cfcb3fe97 feat: opt 出港计重 开始计重 floatButton 2025-12-16 10:10:42 +08:00
b4238a04d0 feat: opt 出港计重 计重明细 update 2025-12-16 09:36:36 +08:00
d1ed050c76 feat: opt 出港计重 完成计重 2025-12-16 09:17:20 +08:00
d600cbe4f1 feat: opt 出港计重 完成计重 2025-12-16 09:06:38 +08:00
20bab628ee feat: opt 出港组装 组装人 2025-12-15 17:47:02 +08:00
7fb91d29b2 feat: opt 收货交接单 2025-12-15 17:17:45 +08:00
746e4cce03 feat: opt handover ui 2025-12-15 17:11:08 +08:00
54ea9dbe75 feat: opt 货物交接单 2025-12-15 16:53:35 +08:00
7650a835f2 feat: opt ui 2025-12-15 15:59:12 +08:00
0531f5e0c4 feat: opt 出库交接 2025-12-15 14:25:11 +08:00
2fa567f2d2 feat: opt del reason 2025-12-15 14:10:08 +08:00
23185616d1 feat: 删除原因 2025-12-15 12:34:00 +08:00
5c7284e617 feat: opt 收运检查 列表 2025-12-15 11:09:57 +08:00
2721e36dc1 feat: auto login in dev 2025-12-15 10:38:30 +08:00
9129ccfb88 feat: opt 国际出港 出港运抵 item 2025-12-15 09:58:36 +08:00
fa79b7d9f3 feat: opt 国际出港 出港理货 item 2025-12-15 09:42:13 +08:00
77d79c4251 feat: 删除原因 dialog for 出港运抵/理货/装载 2025-12-12 13:41:01 +08:00
6b79433557 feat: 出港理货 2025-12-12 13:12:50 +08:00
d9fb950b79 feat: opt action icon 2025-12-12 12:15:20 +08:00
d1e54b540c feat: 出港装载 2025-12-12 11:51:47 +08:00
9e0cae4321 feat: opt 板箱过磅 list 2025-12-12 10:59:58 +08:00
38e336842a feat: opt 板箱过磅 list 2025-12-12 10:48:19 +08:00
48abc944f0 feat: opt layout 2025-12-12 10:39:45 +08:00
82fc593497 feat: 国际出港 组装分配 2025-12-11 19:06:06 +08:00
a81567f10b feat: 国际出港 出港组装 开始组装 2025-12-09 20:44:01 +08:00
7d39cbf70f feat: 国际出港 出港组装 开始组装 2025-12-09 17:58:25 +08:00
2871cbf784 feat: 开始组装 ui 2025-12-09 16:37:49 +08:00
249b5a4e87 feat: dev 2025-12-09 14:19:30 +08:00
6ebedc7366 feat: passageWay for api 2025-12-08 19:15:22 +08:00
a3b8746264 feat: 出港计重 已计重 2025-12-08 17:17:40 +08:00
424755298a feat: 开始计重 calc vol 2025-12-08 16:14:27 +08:00
ee2bfe02a7 feat: 开始计重 业务类型 2025-12-08 16:04:28 +08:00
37ffc539c9 feat: 国际出港 出港计重 分托 2025-12-08 15:48:32 +08:00
9149d1ad35 feat: 国际出港 开始计重 通道 2025-12-08 15:02:06 +08:00
5fc51e7af3 feat: 出港计重 开始计重 2025-12-08 14:14:47 +08:00
2be3cf5251 feat: 出港计重 优化时间显示 2025-12-08 11:26:26 +08:00
7752954d1b feat: 出港计重 特码 filter 2025-12-08 10:58:50 +08:00
ccd93a14bb feat: 出港计重 代理 filter 2025-12-08 10:45:11 +08:00
d401f849c8 feat: 出港计重 ui 2025-12-08 10:31:20 +08:00
09d04cf539 Merge branch 'main' of ssh://git.njcqit.com:2222/eric/aerologic-app 2025-12-06 15:43:05 +08:00
21e0857790 feat: 收运检查-交接单 2025-12-06 15:42:56 +08:00
118 changed files with 6718 additions and 830 deletions

View File

@@ -35,7 +35,9 @@
"Bash(grep:*)",
"Bash(sort:*)",
"Bash(ls:*)",
"Bash(xargs rm:*)"
"Bash(xargs rm:*)",
"Bash(git -C /Users/kid/Development/Fusion/Projects/aerologic-app stash)",
"WebFetch(domain:api.apifox.cn)"
],
"deny": [],
"ask": []

View File

@@ -0,0 +1,246 @@
# 大写字母数字输入过滤器使用指南
## 功能说明
为 EditText 提供输入过滤功能:
- ✅ 只允许输入大写字母(A-Z)和数字(0-9)
- ✅ 小写字母自动转为大写
- ✅ 自动过滤中文、特殊符号、空格等所有非法字符
## 核心实现
**位置**: `module_base/src/main/java/com/lukouguoji/module_base/ktx/EditTextKtx.kt`
```kotlin
/**
* 大写字母和数字输入过滤器
*/
class UpperCaseAlphanumericInputFilter : InputFilter {
// 实现细节...
}
/**
* 为 EditText 设置大写字母和数字输入过滤器
*/
fun EditText.setUpperCaseAlphanumericFilter() {
this.filters = arrayOf(UpperCaseAlphanumericInputFilter())
}
```
## 使用方式
### 方式一:直接为 EditText 设置(最简单)
```kotlin
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
// Activity 中
override fun initOnCreate(savedInstanceState: Bundle?) {
// 为普通 EditText 设置
binding.editText.setUpperCaseAlphanumericFilter()
}
```
### 方式二:为 PadDataLayoutNew 内部的 EditText 设置
```kotlin
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
// Activity 中
override fun initOnCreate(savedInstanceState: Bundle?) {
// PadDataLayoutNew 内部有一个 et 属性,是 EditText
binding.carIdInput.et.setUpperCaseAlphanumericFilter()
binding.uldNoInput.et.setUpperCaseAlphanumericFilter()
binding.impCodeInput.et.setUpperCaseAlphanumericFilter()
}
```
### 方式三:在自定义 View 中设置
```kotlin
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
class CustomView : FrameLayout {
private val editText: EditText
init {
// 初始化后设置
editText.setUpperCaseAlphanumericFilter()
}
}
```
## 实际应用案例
### 案例1板箱过磅页面GjcBoxWeighingAddActivity
**需求**: 架子车号、ULD编码、IMP代码只允许输入大写字母和数字
**实现**:
```kotlin
// GjcBoxWeighingAddActivity.kt
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("板箱过磅")
binding.viewModel = viewModel
viewModel.initOnCreated(this)
// 为架子车号、ULD编码、IMP代码添加大写字母和数字的输入限制
binding.carIdInput.et.setUpperCaseAlphanumericFilter()
binding.uldNoInput.et.setUpperCaseAlphanumericFilter()
binding.impCodeInput.et.setUpperCaseAlphanumericFilter()
}
```
**效果**:
- 输入 `abc123` → 自动变成 `ABC123`
- 输入 `板箱_88` → 自动变成 `88`
- 输入 `test@#456` → 自动变成 `TEST456`
### 案例2其他可能需要的场景
**航班号输入框**:
```kotlin
binding.flightNoInput.et.setUpperCaseAlphanumericFilter()
```
**运单号输入框**:
```kotlin
binding.waybillNoInput.et.setUpperCaseAlphanumericFilter()
```
**任何需要大写字母+数字的输入框**:
```kotlin
binding.anyInput.et.setUpperCaseAlphanumericFilter()
```
## 注意事项
### 1. Import 路径
```kotlin
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
```
### 2. 调用时机
必须在 View 初始化完成后调用,通常在 Activity 的 `initOnCreate` 或 Fragment 的 `onViewCreated` 中。
### 3. 与其他 Filter 组合使用
如果需要同时使用多个 Filter
```kotlin
val filters = arrayOf(
UpperCaseAlphanumericInputFilter(),
InputFilter.LengthFilter(20) // 同时限制长度
)
editText.filters = filters
```
### 4. 覆盖已有 Filter
调用 `setUpperCaseAlphanumericFilter()` 会覆盖已有的 Filter。如果需要保留原有 Filter请手动组合
```kotlin
val existingFilters = editText.filters
val newFilters = existingFilters + UpperCaseAlphanumericInputFilter()
editText.filters = newFilters
```
## 扩展建议
如果需要其他类型的输入过滤器,可以参考 `UpperCaseAlphanumericInputFilter` 的实现:
### 示例1只允许数字
```kotlin
class DigitsOnlyInputFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
if (source.isNullOrEmpty()) return null
val filtered = StringBuilder()
for (i in start until end) {
val char = source[i]
if (char in '0'..'9') {
filtered.append(char)
}
}
return if (filtered.toString() == source.subSequence(start, end).toString()) {
null
} else {
filtered.toString()
}
}
}
fun EditText.setDigitsOnlyFilter() {
this.filters = arrayOf(DigitsOnlyInputFilter())
}
```
### 示例2只允许小写字母和数字
```kotlin
class LowerCaseAlphanumericInputFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
if (source.isNullOrEmpty()) return null
val filtered = StringBuilder()
for (i in start until end) {
val char = source[i]
if (char in 'A'..'Z' || char in 'a'..'z' || char in '0'..'9') {
filtered.append(char.lowercaseChar())
}
}
return if (filtered.toString() == source.subSequence(start, end).toString()) {
null
} else {
filtered.toString()
}
}
}
fun EditText.setLowerCaseAlphanumericFilter() {
this.filters = arrayOf(LowerCaseAlphanumericInputFilter())
}
```
## 测试建议
在使用前建议测试以下场景:
1. 输入小写字母是否自动转大写
2. 输入中文是否被过滤
3. 输入特殊符号是否被过滤
4. 输入空格是否被过滤
5. 粘贴文本是否正确处理
6. 与软键盘的兼容性
## 相关文件
- **核心实现**: `module_base/src/main/java/com/lukouguoji/module_base/ktx/EditTextKtx.kt`
- **使用示例**: `module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcBoxWeighingAddActivity.kt`
---
**最后更新**: 2025-12-16
**维护人员**: 开发团队

View File

@@ -505,6 +505,69 @@ dataBean.value = bean
**类型**: `INPUT` / `SPINNER` / `DATE`
**注意**: 使用 PadDataLayout 时,`titleLength` 通常设置为 5
#### PadDataLayoutNew - 输入完成回调
**使用场景**: 当需要在用户完成输入(失去焦点)时触发自动查询或其他操作
**正确用法**: 使用方法引用语法 `viewModel::methodName`
```xml
<!-- 输入完成后自动查询 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/carIdInput"
hint='@{"请输入架子车号"}'
setRefreshCallBack="@{viewModel::onCarIdInputComplete}"
title='@{"架子车号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.carId}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 日期选择完成后触发回调 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
setRefreshCallBack="@{viewModel::onFlightDateInputComplete}"
title='@{"航班日期"}'
titleLength="@{5}"
type="@{DataLayoutType.DATE}"
value='@={viewModel.flightDate}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
```
**ViewModel 中的实现**:
```kotlin
/**
* 架子车号输入完成时调用
*/
fun onCarIdInputComplete() {
val id = carId.value
if (!id.isNullOrEmpty() && id != lastQueriedCarId) {
lastQueriedCarId = id
queryFlatcarInfo(id)
}
}
/**
* 航班日期选择完成时调用
*/
fun onFlightDateInputComplete() {
// 清除查询标记,以便重新查询
lastQueriedFlight = ""
queryFlightIfReady()
}
```
**关键要点**:
-**正确**: `setRefreshCallBack="@{viewModel::methodName}"` - 使用方法引用
-**错误**: `setRefreshCallBack="@{() -> viewModel.methodName()}"` - Lambda 表达式会导致编译错误
- 回调在输入框失去焦点时触发 (INPUT/SPINNER 类型)
- 回调在日期选择完成后触发 (DATE 类型)
- 适合实现输入完成后的自动查询功能
### 开发检查清单
#### ⚠️ 重要提醒

View File

@@ -115,6 +115,18 @@
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际出港装载 -->
<activity
android:name="com.lukouguoji.gjc.activity.IntExpLoadActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际出港理货 -->
<activity
android:name="com.lukouguoji.gjc.activity.IntExpTallyActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际出港运抵 -->
<activity
android:name="com.lukouguoji.gjc.activity.IntExpArriveActivity"

View File

@@ -51,6 +51,14 @@ class HomeFragment : Fragment() {
private val TAG: String = HomeFragment::class.java.simpleName
/**
* ========== 开发调试开关 ==========
* TODO: 正式发布前务必设置为 false
*/
companion object {
private const val DEV_AUTO_SELECT_INT_EXP = true // 自动选择国际出港开关
}
private var rvLeft: RecyclerView by Delegates.notNull()
private var rvRight: RecyclerView by Delegates.notNull()
@@ -70,6 +78,10 @@ class HomeFragment : Fragment() {
val leftMenuList = initLeftMenuData()
rvLeft.adapter = HomeLeftAdapt(leftMenuList)
rvRight.adapter = HomeRightAdapt(getRightMenu4Id(leftMenuList.first().id))
// ========== 开发调试:自动选择"国际出港"菜单 ==========
// TODO: 正式发布前删除此行
autoSelectIntExpForDev()
}
/////////// 左边的list循环
@@ -155,6 +167,31 @@ class HomeFragment : Fragment() {
}
override fun getItemCount() = leftMenuList.size
/**
* 开发调试:模拟点击菜单项
* TODO: 正式发布前删除此方法
*/
fun simulateClick(position: Int) {
if (position < 0 || position >= leftMenuList.size) return
val leftMenuTemp = leftMenuList[position]
// 跳过特殊菜单(航班查询、货物查询)
if (Constant.AuthName.Flight == leftMenuTemp.id ||
Constant.AuthName.CargoStatus == leftMenuTemp.id) {
return
}
// 更新选中位置
mPosition = position
// 刷新右侧菜单
refreshRight(leftMenuList[mPosition].id)
// 更新菜单状态
notifyDataSetChanged()
}
}
inner class LeftMenu(val id: String, val img: Int, val text: String)
@@ -370,6 +407,18 @@ class HomeFragment : Fragment() {
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_OUT_HANDOVER)
.navigation()
}
// 出港装载
Constant.AuthName.GjcIntExpLoad -> {
ARouter.getInstance()
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_LOAD)
.navigation()
}
// 出港理货
Constant.AuthName.GjcIntExpTally -> {
ARouter.getInstance()
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_TALLY)
.navigation()
}
// 出港运抵
Constant.AuthName.GjcIntExpArrive -> {
ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE)
@@ -689,6 +738,22 @@ class HomeFragment : Fragment() {
)
)
list.add(
RightMenu(
Constant.AuthName.GjcIntExpLoad,
com.lukouguoji.module_base.R.drawable.img_gjc_banxiangzuzhuang,
"出港装载"
)
)
list.add(
RightMenu(
Constant.AuthName.GjcIntExpTally,
com.lukouguoji.module_base.R.drawable.img_gjc_banxiangzuzhuang,
"出港理货"
)
)
list.add(
RightMenu(
Constant.AuthName.GjcIntExpArrive,
@@ -878,4 +943,26 @@ class HomeFragment : Fragment() {
private fun refreshRight(id: String) {
(rvRight.adapter as? HomeRightAdapt)?.refresh(getRightMenu4Id(id))
}
/**
* 开发调试:自动选择"国际出港"菜单
* TODO: 正式发布前删除此方法或将 DEV_AUTO_SELECT_INT_EXP 设置为 false
*/
private fun autoSelectIntExpForDev() {
if (!DEV_AUTO_SELECT_INT_EXP) return
// 延迟执行,确保适配器已初始化
rvLeft.postDelayed({
val leftAdapter = rvLeft.adapter as? HomeLeftAdapt ?: return@postDelayed
// 查找"国际出港"在左侧菜单的位置
val leftMenuList = initLeftMenuData()
val intExpIndex = leftMenuList.indexOfFirst { it.id == Constant.AuthName.IntExp }
if (intExpIndex >= 0) {
// 模拟点击左侧"国际出港"菜单项
leftAdapter.simulateClick(intExpIndex)
}
}, 300) // 延迟300ms确保适配器已绑定数据
}
}

View File

@@ -37,6 +37,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.jessyan.autosize.internal.CustomAdapt
/**
* ========== 开发调试开关 ==========
* TODO: 正式发布前务必设置为 false
*/
private const val DEV_AUTO_LOGIN = true // 自动登录开关
@Route(path = ARouterConstants.ACTIVITY_URL_LOGIN)
class LoginActivity : BaseActivity(),
@@ -100,6 +105,15 @@ class LoginActivity : BaseActivity(),
spinner.setSelection(index)
}
}
// ========== 开发调试:角色信息获取成功后自动登录 ==========
// TODO: 正式发布前删除此代码块
if (DEV_AUTO_LOGIN && user.text.toString() == "ADMIN") {
loginButton.postDelayed({
val encodedPassword = "$2a$10$02ZpVb/bymrybmPE2Mu2C.O.JcMXTB..gkssaNn8q2EC.kUAfJP0S"
viewModel.login(user.text.toString(), encodedPassword)
}, 200) // 短暂延迟确保spinner更新完成
}
}
bindOnSelected(spinner, object : IOnSpinnerSelected {
override fun onSelected(position: Int) {
@@ -183,6 +197,28 @@ class LoginActivity : BaseActivity(),
bindAdapter(spinner, viewModel.roleList, "请选择角色", R.layout.item_spinner_list_18sp)
setEnable(spinner, false)
// ========== 开发调试:自动登录 ==========
// TODO: 正式发布前删除此行
autoLoginForDev()
}
/**
* 开发调试:自动登录
* TODO: 正式发布前删除此方法或将 DEV_AUTO_LOGIN 设置为 false
*/
private fun autoLoginForDev() {
if (!DEV_AUTO_LOGIN) return
// 延迟执行确保UI初始化完成
loginButton.postDelayed({
// 设置用户名
user.setText("ADMIN")
// 手动触发获取角色信息
// 角色信息获取成功后会在userRoleBean.observe中自动执行登录
viewModel.getUserRole("ADMIN")
}, 500) // 延迟500ms确保ViewModel已初始化
}

View File

@@ -0,0 +1,19 @@
package com.lukouguoji.module_base.bean
import dev.utils.app.info.KeyValue
/**
* 组装公司Bean
* 用于组装分配时选择分配人
*/
data class AssembleCompanyBean(
val code: String = "", // 公司代码,例如 "ATR"
val name: String = "" // 公司名称,例如 "ATR:马道"
) {
/**
* 转换为 KeyValue 用于下拉列表
* @return KeyValue(显示文本, 实际值)
* 例如: KeyValue("ATR:马道", "ATR")
*/
fun toKeyValue() = KeyValue(name, code)
}

View File

@@ -1,12 +1,53 @@
package com.lukouguoji.module_base.bean
import androidx.databinding.ObservableBoolean
/**
* 组装信息Bean(左侧列表)
* 组装信息Bean(左侧折叠列表)
* 支持两种行类型:
* 1. 一级ULD行: 显示ULD编号、总件数、总重量
* 2. 二级运单行: 显示运单号、件数、重量
*/
class AssembleInfoBean {
// ========== 层级类型 ==========
enum class ItemType {
ULD_HEADER, // 一级ULD行
WAYBILL_DETAIL // 二级运单行
}
var itemType: ItemType = ItemType.ULD_HEADER // 行类型
// ========== 一级ULD行字段 ==========
var uldNo: String = "" // ULD编号
var weightInfo: String = "" // 重量信息(如100/290kg)
var hasArrow: Boolean = false // 是否显示箭头(可点击)
var isOrange: Boolean = false // 是否橙色文字
var showIndex: Boolean = true // 是否显示序号圆圈
var uldIndex: Int = 0 // ULD序号用于显示1、2、3...
var totalPieces: Int = 0 // 总件数(二级运单件数求和)
var totalWeight: Double = 0.0 // 总重量(二级运单重量求和)
// 展开/折叠状态使用ObservableBoolean支持DataBinding
val isExpanded: ObservableBoolean = ObservableBoolean(false)
// 子运单列表(用于数据管理,不直接显示)
var waybillChildren: MutableList<AssembleInfoBean> = mutableListOf()
// ========== 二级运单行字段 ==========
var parentUldNo: String = "" // 父级ULD编号用于关联
var wbNo: String = "" // 运单号(直接使用后端字段名)
var waybillPieces: Int = 0 // 运单件数
var waybillWeight: Double = 0.0 // 运单重量
// 原始运单数据(用于同步更新和填充表单)
var waybillData: AssembleWaybillBean? = null
// 关联的原始数据用于存储GjcUldUseBean等对象
var tag: Any? = null
// ========== 视觉样式字段 ==========
var hasArrow: Boolean = false // 是否显示箭头一级ULD行为true
var isOrange: Boolean = false // 是否橙色文字(暂保留)
var showIndex: Boolean = false // 是否显示序号圆圈改为false不再显示序号
var showIndent: Boolean = false // 是否显示缩进二级运单行为true
// 保留原有的weightInfo字段兼容性但不再使用
var weightInfo: String = ""
}

View File

@@ -1,11 +1,28 @@
package com.lukouguoji.module_base.bean
import androidx.databinding.ObservableBoolean
/**
* 运单列表Bean右侧运单列表
*/
class AssembleWaybillBean {
var waybillNo: String = "" // 运单号
var pieces: String = "" // 件数
var weight: String = "" // 重量
var pieces: String = "" // 件数(累积的组装件数)
var weight: String = "" // 重量(累积的组装重量)
var flight: String = "" // 配载航班
var isMarked: Boolean = false // 是否标记(红色显示)
var fno: String = ""
var fdate: String = ""
var whId: Long = 0 // 运单ID用于接口调用
// ========== 原始运单信息(用于编辑模式回显) ==========
var originalPieces: String = "" // 原始运单件数
var originalWeight: String = "" // 原始运单重量
val fLightInfo: String
get() = "$fno/${fdate.replace("-", "")}"
// ========== UI扩展字段 ==========
val isSelected: ObservableBoolean = ObservableBoolean(false) // 选中状态
}

View File

@@ -0,0 +1,17 @@
package com.lukouguoji.module_base.bean
import dev.utils.app.info.KeyValue
/**
* 字典-Location接口返回数据Bean
*/
data class DictLocationBean(
var code: String = "", // 编码值 (例如: "18")
var name: String = "" // 显示名称 (例如: "国际出港通道01")
) {
/**
* 转换为KeyValue
* KeyValue(显示名称, 编码值)
*/
fun toKeyValue() = KeyValue(name, code)
}

View File

@@ -0,0 +1,10 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港组装记录Bean
* 对应API: /IntExpAssemble/queryAssembled
*/
class GjcAssembled {
var uldUse: GjcUldUseBean? = null // ULD信息
var warehouseList: MutableList<GjcWarehouse>? = null // 运单列表
}

View File

@@ -0,0 +1,14 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港-分页查询请求参数
* 用于出港装载、检入记录等列表查询
*/
data class GjcCheckInPage(
var fdate: String? = null, // 航班日期
var fno: String? = null, // 航班号
var no: String? = null, // 运单号
var hno: String? = null, // 分单号
var pageNum: Int = 1, // 页码
var pageSize: Int = 10 // 每页条数
)

View File

@@ -1,5 +1,9 @@
package com.lukouguoji.module_base.bean
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import androidx.databinding.library.baseAdapters.BR
/**
* 国际出港计重记录明细Bean
* 用于:加载运单的所有计重记录 + 批量更新
@@ -18,18 +22,34 @@ data class GjcCheckInRecord(
var weight: Double = 0.0, // 运抵重量
var volume: Double = 0.0, // 运抵体积
var whId: Long = 0 // GJC_WAREHOUSE.ID
) {
) : BaseObservable() {
// 数据变化回调
var onDataChanged: (() -> Unit)? = null
// 件数的字符串表示(用于双向绑定)
@get:Bindable
var pcStr: String
get() = if (pc == 0L) "" else pc.toString()
set(value) {
pc = value.toLongOrNull() ?: 0L
val newPc = value.toLongOrNull() ?: 0L
if (pc != newPc) {
pc = newPc
notifyPropertyChanged(BR.pcStr)
onDataChanged?.invoke()
}
}
// 重量的字符串表示(用于双向绑定)
@get:Bindable
var weightStr: String
get() = if (weight == 0.0) "" else weight.toString()
set(value) {
weight = value.toDoubleOrNull() ?: 0.0
val newWeight = value.toDoubleOrNull() ?: 0.0
if (weight != newWeight) {
weight = newWeight
notifyPropertyChanged(BR.weightStr)
onDataChanged?.invoke()
}
}
}

View File

@@ -0,0 +1,13 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港-装载申报/状态重置/删除申报 请求参数
*/
data class GjcDeclareParam(
var dcode: String? = null, // 变更原因代码
var dcontactsName: String? = null, // 联系人姓名
var dcontactsTel: String? = null, // 联系人电话
var maWbList: List<GjcMaWb>? = null, // 主单列表
var haWbList: List<GjcHaWb>? = null, // 分单列表
var loadList: List<GjcExportLoad>? = null // 装载记录列表
)

View File

@@ -0,0 +1,63 @@
package com.lukouguoji.module_base.bean
import androidx.databinding.ObservableBoolean
/**
* 国际出港-出港装载Bean
* 对应API: IntExpLoad/pageQuery
*/
class GjcExportLoad {
var activeId: String = "" // 运单活跃号
var by1: String = "" // 第一承运人
var dep: String = "" // 始发港
var fdate: String = "" // 申报航班日期
var fid: String = "" // 航班主键id
var fno: String = "" // 申报航班号
var goods: String = "" // 品名
var lastLoadMsgId: String = "" // 上一次装载申报编号
var lastLoadStatus: String = "" // 上一次装载状态
var loadMsgId: String = "" // 报文申报编号
var loadStatus: String = "" // 装载申报状态("01"等状态码)
var loaddCount: Int = 0 // 装载删除计次
var loaddRate: Double = 0.0 // 装载删除费率
var loadsCount: Int = 0 // 装载申报计次
var loadsRate: Double = 0.0 // 装载申报费率
var no: String = "" // 主运单号
var packageType: String = "" // 包装类型代码
var pc: Int = 0 // 件数
var prefix: String = "" // 主运单前缀
var response: String = "" // 海关业务回执
var spCode: String = "" // 特码
var splitFlag: String = "" // 分批标志
var sysId: String = "" // 系统ID
var tallyStatus: String = "" // 理货状态
var weight: Double = 0.0 // 重量
// ========== UI扩展字段 ==========
val checked: ObservableBoolean = ObservableBoolean(false) // 选中状态
// 兼容现有API的isSelected属性
var isSelected: Boolean
get() = checked.get()
set(value) = checked.set(value)
/**
* 获取格式化的运单号prefix + no
*/
fun getFullWaybillNo(): String {
return if (prefix.isNotEmpty()) "$prefix$no" else no
}
/**
* 获取装载状态显示文字
*/
fun getLoadStatusText(): String {
return when (loadStatus) {
"01" -> "已申报"
"02" -> "申报中"
"03" -> "申报失败"
"04" -> "已删除"
else -> loadStatus
}
}
}

View File

@@ -0,0 +1,41 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港货物交接单Bean
*/
data class GjcHandoverSheetBean(
// ========== API文档字段 ==========
var id: Long? = null, // 主键id
var maWbId: Long? = null, // 运单主键id
var no: String? = null, // 编号
var prefix: String? = null, // 前缀
var chargeWeight: Double? = null, // 计费重量
var saleAgentCode: String? = null, // 销售代理人
var expressName: String? = null, // 平台或快递企业名称
var cbEcFlag: String? = null, // 是否为跨境电商货物(0:否;1:是)
var opName: String? = null, // 经办人签名
var opCardId: String? = null, // 经办人身份证号
// ========== 防止隐含危险品检查单 ==========
var goodsName: String? = null, // 申报货物的品名为确指品名(0/1)
var danger: String? = null, // 确认货物内不含未申报的危险品(0/1)
var fish: String? = null, // 是否非观赏鱼类货物(0/1)
var packaging: String? = null, // 包装件没有油渍或液体渗漏(0/1)
var labels: String? = null, // 清除或涂去无关标记或标签(0/1)
// ========== 高风险货物检查单 ==========
var appearance: String? = null, // 航空货物外观显现异常(0/1)
var threat: String? = null, // 有具体情报显示威胁(0/1)
var highRisk: String? = null, // 结论:是否可以判定为高风险货物(0/1)
// ========== 跨境电商检查单 ==========
var submitStatement: String? = null, // 是否已提交声明(0/1/2: 是/否/不适用)
// ========== 货站收运人员 ==========
var staOpName: String? = null, // 货站收运人员签名
// ========== 安检信息(用户手动填写) ==========
var securityChannel: String? = null, // 安检机通道号
var securityStartTime: String? = null, // 开始过机时间
var securityEndTime: String? = null // 结束过机时间
)

View File

@@ -0,0 +1,9 @@
package com.lukouguoji.module_base.bean
/**
* 国际出港货物交接单查询接口返回Bean
*/
data class GjcHandoverSheetResponse(
var maWb: GjcMaWb? = null, // 主单信息
var handoverSheet: GjcHandoverSheetBean? = null // 交接单信息(可能为null)
)

View File

@@ -2,6 +2,9 @@ package com.lukouguoji.module_base.bean
import androidx.databinding.ObservableBoolean
import com.lukouguoji.module_base.interfaces.ICheck
import com.lukouguoji.module_base.ktx.noNull
import dev.utils.DevFinal
import dev.utils.common.DateUtils
/**
* 国际出港收运检查数据Bean
@@ -74,4 +77,32 @@ class GjcInspectionBean : ICheck {
else -> "#9E9E9E" // 灰色-未审核
}
}
/**
* 预计起飞时间 - 仅时分格式 (HH:mm)
*/
val scheduledTackOffHM: String
get() {
return DateUtils.parseString(
scheduledTackOff,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(scheduledTackOff)
}
/**
* 验证预计起飞时间是否为次日
*/
fun verifyScheduledTackOffNextDay(): Boolean {
if (fdate.isEmpty() || scheduledTackOff.isEmpty()) {
return false
}
return try {
val calendarFDate = DateUtils.getCalendar(fdate, DevFinal.TIME.yyyyMMdd_HYPHEN)
val calendarTakeOff = DateUtils.getCalendar(scheduledTackOff, DevFinal.TIME.yyyyMMddHHmmss_HYPHEN)
DateUtils.getDay(calendarTakeOff) > DateUtils.getDay(calendarFDate)
} catch (e: Exception) {
false
}
}
}

View File

@@ -21,7 +21,7 @@ data class GjcMaWb(
var fno: String? = null, // 航班号
var fdate: Date? = null, // 航班日期
var flight: String? = null, // 航班: 航班日期/航班号
var fclose: Date? = null, // 航班关闭时间
var fclose: String? = null, // 航班关闭时间
var scheduledTackOff: Date? = null, // 计划起飞时间
var scheduledArrival: Date? = null, // 预计到达时间
@@ -71,6 +71,7 @@ data class GjcMaWb(
// ==================== 车辆信息 ====================
var carId: String? = null, // 平板车号
var carNumber: String? = null, // 车牌号
var passageWay: String? = null, // 通道号
// ==================== 状态信息 ====================
var checkIn: String? = null, // 收运状态。0待收运1已收运2收运中
@@ -79,7 +80,7 @@ data class GjcMaWb(
var tranFlag: String? = null, // 转运标志
// ==================== 操作信息 ====================
var opDate: Date? = null, // 操作时间(入库时间)
var opDate: String? = null, // 操作时间(入库时间)
var opId: String? = null, // 操作员id
var paperTime: Date? = null, // 单证时间
@@ -115,6 +116,30 @@ data class GjcMaWb(
var isSelected: Boolean
get() = checked.get()
set(value) = checked.set(value)
// ==================== 状态转换扩展属性 ====================
/**
* 计重状态中文
* 0-待收运1-已计重2-计重中
*/
val checkInText: String
get() = when (checkIn) {
"0" -> "待收运"
"1" -> "已计重"
"2" -> "计重中"
else -> checkIn ?: ""
}
/**
* 运抵状态中文
* 0-正常运抵1-提前运抵
*/
val arriveFlagText: String
get() = when (arriveFlag) {
"0" -> "正常运抵"
"1" -> "提前运抵"
else -> arriveFlag ?: ""
}
}
/**

View File

@@ -16,6 +16,7 @@ class GjcUldUseBean {
var netWeight: Double = 0.0 // 装机重量
var totalWeight: Double = 0.0 // 总重
var uldWeight: Double = 0.0 // uld重量
var consumeWeight: Double = 0.0 // 耗材重量
var volume: Double = 0.0 // 体积
var maxVolume: Double = 0.0 // uld最大容积
var maxWeight: Double = 0.0 // uld最大载重
@@ -26,6 +27,10 @@ class GjcUldUseBean {
var fdest: String = "" // 目的港
var fClose: String = "" // 航班关闭时间
// 格式化后的航班日期(只保留年月日)
val fdateFormatted: String
get() = if (fdate.contains(" ")) fdate.split(" ")[0] else fdate
var wtId: String = "" // 过磅人ID
var wtUsername: String = "" // 过磅人
var wtDate: String = "" // 过磅时间

View File

@@ -1,5 +1,9 @@
package com.lukouguoji.module_base.bean
import com.lukouguoji.module_base.ktx.noNull
import dev.utils.DevFinal
import dev.utils.common.DateUtils
/**
* 国际出港待计重-列表数据Bean
* 对应API: IntExpCheckIn/pageQuery
@@ -91,4 +95,32 @@ class GjcWeighingBean {
var haWbList: List<Any>? = null // 分单列表
var storageUseList: List<Any>? = null // 库位使用列表
var attachList: List<Any>? = null // 附件列表
/**
* 预计起飞时间 - 仅时分格式 (HH:mm)
*/
val scheduledTackOffHM: String
get() {
return DateUtils.parseString(
scheduledTackOff,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(scheduledTackOff)
}
/**
* 验证预计起飞时间是否为次日
*/
fun verifyScheduledTackOffNextDay(): Boolean {
if (fdate.isEmpty() || scheduledTackOff.isEmpty()) {
return false
}
return try {
val calendarFDate = DateUtils.getCalendar(fdate, DevFinal.TIME.yyyyMMdd_HYPHEN)
val calendarTakeOff = DateUtils.getCalendar(scheduledTackOff, DevFinal.TIME.yyyyMMddHHmmss_HYPHEN)
DateUtils.getDay(calendarTakeOff) > DateUtils.getDay(calendarFDate)
} catch (e: Exception) {
false
}
}
}

View File

@@ -247,6 +247,8 @@ interface Constant {
const val GjcIntExpAssembleActivity = "AppIntExpAssemble" //出港组装
const val GjcAssembleAllocateActivity = "AppIntExpAssembleAllocate" //组装分配
const val GjcIntExpOutHandover = "AppIntExpOutHandover" //出库交接
const val GjcIntExpLoad = "AppIntExpLoad" //出港装载
const val GjcIntExpTally = "AppIntExpTally" //出港理货
const val GjcIntExpArrive = "AppIntExpArrive" //出港运抵
/**

View File

@@ -5,28 +5,34 @@ import com.lukouguoji.module_base.bean.AccidentVisaBean
import com.lukouguoji.module_base.bean.AirportBean
import com.lukouguoji.module_base.bean.AppUpdateResponse
import com.lukouguoji.module_base.bean.AppUpdateResponseInfo
import com.lukouguoji.module_base.bean.AssembleCompanyBean
import com.lukouguoji.module_base.bean.BaseListBean
import com.lukouguoji.module_base.bean.BaseResultBean
import com.lukouguoji.module_base.bean.BoxDetailsForCarIdBean
import com.lukouguoji.module_base.bean.CarBarBean
import com.lukouguoji.module_base.bean.CarOrUldBean
import com.lukouguoji.module_base.bean.DiBangChannelBean
import com.lukouguoji.module_base.bean.DictBean
import com.lukouguoji.module_base.bean.DictIdValueBean
import com.lukouguoji.module_base.bean.DictListBean
import com.lukouguoji.module_base.bean.DictLocationBean
import com.lukouguoji.module_base.bean.DocumentHandoverBean
import com.lukouguoji.module_base.bean.FlatcarBean
import com.lukouguoji.module_base.bean.FlightBean
import com.lukouguoji.module_base.bean.FlightFilterBean
import com.lukouguoji.module_base.bean.GbCarOrUldBean
import com.lukouguoji.module_base.bean.GjcAssembleAllocate
import com.lukouguoji.module_base.bean.GjcAssembled
import com.lukouguoji.module_base.bean.GjcBoxAddInsertBean
import com.lukouguoji.module_base.bean.GjcBoxAssembleBean
import com.lukouguoji.module_base.bean.GjcBoxDetailsBean
import com.lukouguoji.module_base.bean.GjcBoxWeighingStatisticsBean
import com.lukouguoji.module_base.bean.GjcCheckInRecord
import com.lukouguoji.module_base.bean.GjcExportLoad
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.GjcHandoverSheetResponse
import com.lukouguoji.module_base.bean.GjcInspectionBean
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.bean.GjcMove
@@ -86,7 +92,15 @@ import com.lukouguoji.module_base.ktx.toRequestBody
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.http.*
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part
import retrofit2.http.PartMap
import retrofit2.http.Query
import retrofit2.http.Streaming
import retrofit2.http.Url
/**
* @author孟凡华
@@ -148,6 +162,11 @@ interface Api {
@GET("typeCode/searchDateType")
suspend fun getDictList(@Query("code") code: String): BaseResultBean<List<DictIdValueBean>>
/**
* 获取字典列表 - location接口
*/
@GET("typeCode/locationByCode")
suspend fun getDictListByLocation(@Query("code") code: String): BaseResultBean<List<DictLocationBean>>
/**
* 获取字典列表----根据用户角色选择转运类型
@@ -280,6 +299,12 @@ interface Api {
@POST("eqm/uld/queryUld")
suspend fun getUldDetails(@Query("id") id: String): BaseResultBean<ULDBean>
/**
* 根据ULD编号查询ULD信息新接口
*/
@GET("eqm/uld/queryUld")
suspend fun queryUldByCode(@Query("uld") uld: String): BaseResultBean<ULDBean>
/**
* 获取运单信息 - 国际出
*/
@@ -409,7 +434,10 @@ interface Api {
* 接口路径: /IntExpCheckInCheck/back
*/
@POST("IntExpCheckInCheck/back")
suspend fun backGjcInspection(@Query("reason") reason: String, @Body data: RequestBody): BaseResultBean<Boolean>
suspend fun backGjcInspection(
@Query("reason") reason: String,
@Body data: RequestBody
): BaseResultBean<Boolean>
/**
* 条件查询-国际出港-收运审核-统计数据(总件数、总重量、运单总数)
@@ -418,6 +446,23 @@ interface Api {
@POST("IntExpCheckInCheck/pageQueryTotal")
suspend fun getGjcInspectionTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际出港收运审核-交接单-获取交接单内容
* 接口路径: /IntExpCheckInCheck/queryHandoverSheet
*/
@GET("IntExpCheckInCheck/queryHandoverSheet")
suspend fun queryHandoverSheet(@Query("maWbId") maWbId: Long): BaseResultBean<GjcHandoverSheetResponse>
/**
* 国际出港收运审核-交接单-保存
* 接口路径: /IntExpCheckInCheck/saveHandoverSheet
*/
@POST("IntExpCheckInCheck/saveHandoverSheet")
suspend fun saveHandoverSheet(@Body data: RequestBody): BaseResultBean<Long>
///////////////////////////////////////////////////////////////////////////
// 国际出 - 查询
///////////////////////////////////////////////////////////////////////////
/**
* 国际出港查询-分页查询
* 接口路径: /IntExpSearch/pageQuery
@@ -468,6 +513,13 @@ interface Api {
@POST("IntExpAssemble/allocate")
suspend fun allocateAssemble(@Body params: RequestBody): BaseResultBean<Boolean>
/**
* 获取组装公司下拉列表
* 接口路径: /typeCode/assembleCompany
*/
@POST("typeCode/assembleCompany")
suspend fun getAssembleCompanyList(): BaseResultBean<List<AssembleCompanyBean>>
/**
* 国际出港板箱过磅-分页搜索
* 接口路径: /IntExpWeighting/pageQuery
@@ -536,6 +588,66 @@ interface Api {
@POST("IntExpAssemble/backfillWeight")
suspend fun backfillIntExpAssembleWeight(@Body data: RequestBody): BaseResultBean<SimpleResultBean>
/**
* 国际出港组装 - 获取组装人列表
* 接口路径: /IntExpAssemble/pageQueryAssembler
*/
@GET("IntExpAssemble/pageQueryAssembler")
suspend fun getIntExpAssemblerList(): BaseResultBean<List<String>>
/**
* 国际出港组装 - 查询待组装运单列表
* 接口路径: /IntExpAssemble/queryWaitingAssemble
*/
@GET("IntExpAssemble/queryWaitingAssemble")
suspend fun queryWaitingAssemble(@Query("wbNo") wbNo: String): BaseResultBean<MutableList<GjcWarehouse>>
/**
* 国际出港组装 - 根据全ULD查询ULD状态和耗材重量
* 接口路径: /IntExpAssemble/getUld
* @param uld ULD编号
* @return ULD信息包含status0正常1故障和consumeWeight耗材重量
*/
@GET("IntExpAssemble/getUld")
suspend fun getUldWithConsumeWeight(@Query("uld") uld: String): BaseResultBean<GjcUldUseBean>
/**
* 国际出港组装 - 卸货
* 接口路径: /IntExpAssemble/drop
* @param data 请求参数abPc组装件数、abWeight组装重量、consumeWeight耗材重量
* ldId组装人、loadArea组装区、useInfoULD信息、wbInfo运单信息、userId用户ID
*/
@POST("IntExpAssemble/drop")
suspend fun assembleDropCargo(@Body data: RequestBody): BaseResultBean<GjcWarehouse>
/**
* 国际出港组装 - 装货
* 接口路径: /IntExpAssemble/assemble
* @param data 请求参数abPc组装件数、abWeight组装重量、consumeWeight耗材重量
* ldId组装人、loadArea组装区、useInfoULD信息、wbInfo运单信息、userId用户ID
*/
@POST("IntExpAssemble/assemble")
suspend fun assembleLoadCargo(@Body data: RequestBody): BaseResultBean<GjcWarehouse>
/**
* 国际出港组装 - 查询已组装的ULD列表
* 接口路径: /IntExpAssemble/queryAssembled
* @param data 请求参数fno航班号必填、fdate航班日期必填
* loadArea组装位置必填、uldULD编号可选
* @return 返回已组装的ULD列表包含ULD信息和运单列表
*/
@POST("IntExpAssemble/queryAssembled")
suspend fun getAssembledList(@Body data: RequestBody): BaseResultBean<List<GjcAssembled>>
/**
* 国际出港组装 - 根据ULD查询已组装的运单列表
* 接口路径: /IntExpAssemble/queryAssembledByUld
* @param data 请求参数GjcUldUseBean对象包含useId、uld等信息
* @return 返回该ULD下的运单列表
*/
@POST("IntExpAssemble/queryAssembledByUld")
suspend fun getAssembledWaybillsByUld(@Body data: RequestBody): BaseResultBean<List<GjcWarehouse>>
/**
* 国际出港出库交接-分页查询
* 接口路径: /IntExpOutHandover/pageQuery
@@ -558,6 +670,34 @@ interface Api {
@POST("IntExpOutHandover/handover")
suspend fun completeHandover(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港装载 分页查询
* 接口路径: /IntExpLoad/pageQuery
*/
@POST("IntExpLoad/pageQuery")
suspend fun getIntExpLoadList(@Body data: RequestBody): BaseListBean<GjcExportLoad>
/**
* 国际出港-出港装载 分页合计
* 接口路径: /IntExpLoad/pageQueryTotal
*/
@POST("IntExpLoad/pageQueryTotal")
suspend fun getIntExpLoadTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际出港-出港装载 状态重置
* 接口路径: /IntExpLoad/resetDeclare
*/
@POST("IntExpLoad/resetDeclare")
suspend fun resetDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港装载 装载申报
* 接口路径: /IntExpLoad/declare
*/
@POST("IntExpLoad/declare")
suspend fun declareLoad(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港运抵-分页列表
* 接口路径: /IntExpArrive/pageQuery
@@ -588,6 +728,62 @@ interface Api {
@POST("IntExpArrive/declare")
suspend fun arriveDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港理货-列表查询
* 接口路径: /IntExpTally/pageQuery
* 返回: PageInfo<GjcMaWb>
*/
@POST("IntExpTally/pageQuery")
suspend fun getIntExpTallyList(@Body data: RequestBody): BaseListBean<GjcMaWb>
/**
* 国际出港-出港理货-统计查询
* 接口路径: /IntExpTally/pageQueryTotal
* 返回: ManifestTotalDto合计票数、总件数、总重量
*/
@POST("IntExpTally/pageQueryTotal")
suspend fun getIntExpTallyTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际出港-出港理货-理货申报
* 接口路径: /IntExpTally/declare
* @param data 请求参数选中的GjcMaWb列表
*/
@POST("IntExpTally/declare")
suspend fun declareTally(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港理货-状态重置
* 接口路径: /IntExpTally/resetDeclare
* @param data 请求参数选中的GjcMaWb列表
*/
@POST("IntExpTally/resetDeclare")
suspend fun resetTallyDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港理货-删除理货申报
* 接口路径: /IntExpTally/deleteDeclare
* @param data 请求参数GjcDeclareParam
*/
@POST("IntExpTally/deleteDeclare")
suspend fun deleteTallyDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港装载-删除装载申报
* 接口路径: /IntExpLoad/deleteDeclare
* @param data 请求参数GjcDeclareParam
*/
@POST("IntExpLoad/deleteDeclare")
suspend fun deleteLoadDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港-出港运抵-删除运抵申报
* 接口路径: /IntExpArrive/deleteDeclare
* @param data 请求参数GjcDeclareParam
*/
@POST("IntExpArrive/deleteDeclare")
suspend fun deleteArriveDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港移库-分页查询
* 接口路径: /IntExpMove/pageQuery
@@ -623,6 +819,23 @@ interface Api {
@POST("IntExpCheckIn/pageQueryTotal")
suspend fun getGjcWeighingStatistics(@Body data: RequestBody): BaseResultBean<GjcWeighingStatisticsBean>
/**
* 国际出港待计重-开始计重-根据wbId查询详情
* 接口路径: /IntExpCheckIn/queryWbById
* @param maWbId 运单主键ID
*/
@POST("IntExpCheckIn/queryWbById")
suspend fun getIntExpCheckInWbById(@Query("maWbId") maWbId: Long): BaseResultBean<GjcMaWb>
/**
* 国际出港待计重-开始计重-根据运单id查询实时计重数据
* 接口路径: /IntExpCheckIn/queryRecordByWh
* @param maWbId 运单主键ID
* @return 返回GjcCheckInRecord,包含实时的pc、weight、volume
*/
@POST("IntExpCheckIn/queryRecordByWh")
suspend fun getIntExpRealTimeRecord(@Query("maWbId") maWbId: Long): BaseResultBean<GjcCheckInRecord>
/**
* 国际出港计重记录-分页搜索
* 接口路径: /IntExpCheckIn/checked/pageQuery
@@ -644,6 +857,13 @@ interface Api {
@POST("IntExpCheckIn/completeCheckIn")
suspend fun completeCheckIn(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港待计重-开始计重-分托计重
* 接口路径: /IntExpCheckIn/splitCheckIn
*/
@POST("IntExpCheckIn/splitCheckIn")
suspend fun splitCheckIn(@Body data: RequestBody): BaseResultBean<Long>
/**
* 国际出港计重明细-根据运单号查询所有计重记录
* 接口路径: /IntExpCheckIn/listRecordByWh
@@ -875,6 +1095,12 @@ interface Api {
@POST("flt/queryFlightById")
suspend fun getFlightDetails(@Query("id") id: String): BaseResultBean<FlightBean>
/**
* 根据航班日期和航班号查询航班
*/
@POST("flt/queryFlight")
suspend fun queryFlightByDateAndNo(@Body data: RequestBody): BaseResultBean<FlightBean>
/**
* 获取航班目的站、经停站
*/
@@ -1152,6 +1378,7 @@ interface Api {
*/
@POST
suspend fun getWbNoList(@Url url: String, @Body data: RequestBody): BaseResultBean<List<String>>
/**
* 获取-国内出港-分配-列表
*/
@@ -1170,6 +1397,7 @@ interface Api {
*/
@POST("flt/searchHandoverByFid")
suspend fun getHandover(@Query("fid") fid: String): BaseResultBean<FlightBean>
/**
* 获取-国内出港-存放-列表
*/
@@ -1226,7 +1454,6 @@ interface Api {
fun queryWbDetailById(@Query("wbId") wbId: Int): BaseResultBean<GncShouYunBean>
/**
* 获取-货物转运-列表
*/
@@ -1274,13 +1501,19 @@ interface Api {
*/
@POST("DomTransportLog/search")
suspend fun getTransportLogList(@Body data: RequestBody): BaseListBean<TransportLogBean>
/**
* 国内 单证交接 列表
*/
@POST("flt/searchHandoverPage")
suspend fun getDocumentHandoverList(@Body data: RequestBody): BaseListBean<DocumentHandoverBean>
/**
* 获取删除原因列表
*/
@POST("typeCode/delReason")
suspend fun getDelReasonList(@Query("needFormat") needFormat: Boolean = true): BaseResultBean<List<DictBean>>
@GET("file/verifyVersion")
suspend fun getAppUpdate(@Query("versionCode") versionCode : Int): AppUpdateResponse<AppUpdateResponseInfo>
suspend fun getAppUpdate(@Query("versionCode") versionCode: Int): AppUpdateResponse<AppUpdateResponseInfo>
}

View File

@@ -1,6 +1,7 @@
package com.lukouguoji.module_base.ktx
import android.text.InputFilter
import android.text.Spanned
import android.widget.EditText
import androidx.databinding.BindingAdapter
@@ -12,4 +13,47 @@ fun setTextAllCaps(et: EditText, allCaps: Boolean) {
} else {
et.filters = emptyArray<InputFilter>()
}
}
/**
* 大写字母和数字输入过滤器
* 只允许输入大写字母(A-Z)和数字(0-9),小写字母自动转为大写
*/
class UpperCaseAlphanumericInputFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
if (source.isNullOrEmpty()) return null
val filtered = StringBuilder()
for (i in start until end) {
val char = source[i]
// 只允许ASCII字母(A-Z, a-z)和数字(0-9)
if (char in 'A'..'Z' || char in 'a'..'z' || char in '0'..'9') {
// 自动转为大写
filtered.append(char.uppercaseChar())
}
}
// 如果过滤后的内容与原内容相同,返回null表示不修改
// 否则返回过滤后的内容
return if (filtered.toString() == source.subSequence(start, end).toString()) {
null
} else {
filtered.toString()
}
}
}
/**
* 为 EditText 设置大写字母和数字输入过滤器
* 使用方式: editText.setUpperCaseAlphanumericFilter()
*/
fun EditText.setUpperCaseAlphanumericFilter() {
this.filters = arrayOf(UpperCaseAlphanumericInputFilter())
}

View File

@@ -143,6 +143,8 @@ object ARouterConstants {
const val ACTIVITY_URL_INT_EXP_MOVE = "/gjc/IntExpMoveActivity" //国际出港 出港移库
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" //国际出港 出港运抵
///////////////// 国际进港模块

View File

@@ -205,7 +205,6 @@ fun setSearchLayoutDataValueNew(
layout.value = value
}
}
@BindingAdapter(
"enable",
requireAll = false

View File

@@ -125,6 +125,15 @@ class PadDataLayoutNew : FrameLayout {
et.inputType = value
}
var valueTextColor: Int = 0
set(value) {
field = value
if (value != 0) {
tv.setTextColor(value)
et.setTextColor(value)
}
}
/**
* 刷新事件回调
*/

View File

@@ -2,7 +2,9 @@ package com.lukouguoji.module_base.ui.weight.search.layout
import android.content.Context
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
@@ -121,6 +123,11 @@ class PadSearchLayoutNew : LinearLayout {
var listRefreshCallBack: (() -> Unit)? = {}
/**
* 搜索事件回调(回车键或搜索按钮触发)
*/
var searchCallBack: (() -> Unit)? = null
///////////////////////////////////////////////////////////////////////////
// 方法区
///////////////////////////////////////////////////////////////////////////
@@ -138,6 +145,20 @@ class PadSearchLayoutNew : LinearLayout {
et.doOnTextChanged { text, _, _, _ ->
value = text.toString()
}
// 回车键监听 - 触发搜索
et.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_DONE ||
(event?.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN)) {
// 优先调用searchCallBack如果没有则调用refreshCallBack
searchCallBack?.invoke() ?: refreshCallBack?.invoke()
true
} else {
false
}
}
bindOnSelected(spinner, object : IOnSpinnerSelected {
override fun onSelected(position: Int) {
value = list.getOrNull(position)?.value ?: ""

View File

@@ -140,6 +140,24 @@ fun setInputWaybill(layout: PadSearchLayout, isWaybill: Boolean) {
}
}
/**
* 设置搜索监听器(回车键或搜索按钮触发)
*/
@BindingAdapter("setOnSearchListener", requireAll = false)
fun setSearchLayoutNewOnSearchListener(layout: PadSearchLayoutNew, listener: (() -> Unit)?) {
layout.searchCallBack = listener
}
/**
* 设置搜索图标点击为搜索功能
*/
@BindingAdapter("setSearchIconClickListener", requireAll = false)
fun setSearchLayoutNewSearchIconClickListener(layout: PadSearchLayoutNew, listener: (() -> Unit)?) {
layout.iv.setOnClickListener {
listener?.invoke()
}
}
///////////////////////////////////////////////////////////////////////////
// PadSearchLayoutNew 的绑定适配器
///////////////////////////////////////////////////////////////////////////

View File

@@ -1,12 +1,9 @@
package com.lukouguoji.module_base.util
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.module_base.bean.DictBean
import com.lukouguoji.module_base.bean.DictListBean
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.toMap
import com.lukouguoji.module_base.ktx.toRequestBody
import dev.utils.app.info.KeyValue
import java.util.Collections.emptyList
@@ -179,7 +176,7 @@ object DictUtils {
) {
launchCollect({
NetApply.api
.getSpecialCodeList(flag, ieFlag,parentcode)
.getSpecialCodeList(flag, ieFlag, parentcode)
}) {
onSuccess = {
handleCallBack(it, checkedValue, addAll, callBack)
@@ -404,6 +401,22 @@ object DictUtils {
}
}
/**
* 国际出港通道号列表
*/
fun getGjcChannelList(
callBack: (List<KeyValue>) -> Unit
) {
launchCollect({
NetApply.api
.getDictListByLocation("GJCPASSAGEWAY")
}) {
onSuccess = {
callBack((it.data ?: emptyList()).map { b -> b.toKeyValue() })
}
}
}
/**
* 货物类型
@@ -510,7 +523,7 @@ object DictUtils {
.getDictList("DGRDETAIL")
}) {
onSuccess = {
callBack((it.data ?: emptyList()).map { b -> KeyValue(b.value,b.value) })
callBack((it.data ?: emptyList()).map { b -> KeyValue(b.value, b.value) })
}
}
}
@@ -629,12 +642,14 @@ object DictUtils {
NetApply.api.getUserByRoleId("6")
}) {
onSuccess = {
val jbDrivers = (it.data ?: emptyList()).map { b -> KeyValue(b.username, b.username) }
val jbDrivers =
(it.data ?: emptyList()).map { b -> KeyValue(b.username, b.username) }
launchCollect({
NetApply.api.getUserByRoleId("7")
}) {
onSuccess = {iit ->
val shDrivers = (iit.data ?: emptyList()).map { b -> KeyValue(b.username, b.username) }
onSuccess = { iit ->
val shDrivers =
(iit.data ?: emptyList()).map { b -> KeyValue(b.username, b.username) }
callBack(jbDrivers + shDrivers)
}
}

View File

@@ -2,7 +2,6 @@ package com.lukouguoji.module_base.util
import android.Manifest
import android.graphics.Typeface
import android.util.Log
import com.gainscha.sdk2.ConnectType
import com.gainscha.sdk2.ConnectionListener
import com.gainscha.sdk2.Printer
@@ -18,23 +17,39 @@ import com.gprinter.io.PortManager
import com.gprinter.utils.CallbackListener
import com.gprinter.utils.Command
import com.gprinter.utils.ConnMethod
import com.lukouguoji.module_base.bean.FlatcarBean
import com.lukouguoji.module_base.bean.GjcUldUseBean
import com.lukouguoji.module_base.bean.GncFuBangBean
import com.lukouguoji.module_base.bean.GncShouYunBean
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.ktx.permission
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.model.LoadingModel
import dev.DevUtils
import dev.utils.app.SizeUtils
import okio.internal.commonToUtf8String
object PrinterUtils {
/**
* 打印单元格数据
*/
private data class CellData(
val title: String, // 中文标签(大字)
val subtitle: String, // 英文标签(小字)
val value: String // 值(大字,垂直居中)
)
/**
* 打印表格行数据
*/
private data class GridRow(
val left: CellData? = null,
val right: CellData? = null,
val merged: CellData? = null // 合并单元格数据
)
private val loading by lazy {
LoadingModel()
}
@@ -133,7 +148,8 @@ object PrinterUtils {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
) {
finder.searchPrinters(ConnectType.BLUETOOTH,
finder.searchPrinters(
ConnectType.BLUETOOTH,
object : PrinterFinder.SimpleSearchPrinterResultListener() {
override fun onSearchBluetoothPrinter(device: BluetoothPrinterDevice?) {
if (device == null) return
@@ -218,28 +234,28 @@ object PrinterUtils {
var fDestinationCn = ""
launchCollect({
NetApply.api.getAirportByCode(bean.dest1)
}){
}) {
onSuccess = {
destinationCn = it.data?.nameCn ?: ""
rowItem.add(listOf("日期", "航班号", "目的站"))
rowItem.add(listOf( bean.fdate, bean.fno, bean.dest1 + destinationCn ))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf( bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf( "", "", ""))
rowItem.add(listOf("监装监卸", "中转信息","备注"))
rowItem.add(listOf(bean.fdate, bean.fno, bean.dest1 + destinationCn))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf(bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf("", "", ""))
rowItem.add(listOf("监装监卸", "中转信息", "备注"))
if (bean.dest2 != "") {
launchCollect({
NetApply.api.getAirportByCode(bean.dest2)
}){
}) {
onSuccess = { it2 ->
fDestinationCn = it2.data?.nameCn ?: ""
rowItem.add(listOf( "", bean.dest2 + fDestinationCn, ""))
rowItem.add(listOf("", bean.dest2 + fDestinationCn, ""))
printCommonGridNew(rowItem)
}
}
} else {
rowItem.add(listOf( "", "", ""))
rowItem.add(listOf("", "", ""))
printCommonGridNew(rowItem)
}
}
@@ -259,35 +275,35 @@ object PrinterUtils {
var fDestinationCn = ""
launchCollect({
NetApply.api.getAirportByCode(bean.fdest)
}){
}) {
onSuccess = {
fDestinationCn = it.data?.nameCn ?: ""
if (bean.dest != "") {
launchCollect({
NetApply.api.getAirportByCode(bean.dest)
}){
}) {
onSuccess = { it2 ->
destinationCn = it2.data?.nameCn ?: ""
rowItem.add(listOf("日期", "航班号", "目的站"))
rowItem.add(listOf( bean.fdate, bean.fno, bean.fdest + fDestinationCn ))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf( bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf( "", "", ""))
rowItem.add(listOf("监装监卸", "中转信息","备注"))
rowItem.add(listOf( "", bean.dest + destinationCn, ""))
rowItem.add(listOf(bean.fdate, bean.fno, bean.fdest + fDestinationCn))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf(bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf("", "", ""))
rowItem.add(listOf("监装监卸", "中转信息", "备注"))
rowItem.add(listOf("", bean.dest + destinationCn, ""))
printCommonGridNew(rowItem)
}
}
} else {
rowItem.add(listOf("日期", "航班号", "目的站"))
rowItem.add(listOf( bean.fdate, bean.fno, bean.fdest + fDestinationCn ))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf( bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf( "", "", ""))
rowItem.add(listOf("监装监卸", "中转信息","备注"))
rowItem.add(listOf( "", "", ""))
rowItem.add(listOf(bean.fdate, bean.fno, bean.fdest + fDestinationCn))
rowItem.add(listOf("斗号", "计重", "仓管"))
rowItem.add(listOf(bean.location, bean.username, ""))
rowItem.add(listOf("装机仓位", "机位", "特车司机"))
rowItem.add(listOf("", "", ""))
rowItem.add(listOf("监装监卸", "中转信息", "备注"))
rowItem.add(listOf("", "", ""))
printCommonGridNew(rowItem)
}
@@ -295,6 +311,43 @@ object PrinterUtils {
}
}
/**
* 打印国际出港板箱过磅挂签2列布局支持合并单元格
*/
fun printGjcBoxWeighing(bean: GjcUldUseBean) {
val rows = arrayListOf<GridRow>()
// 第1行日期 | 航班号
rows.add(GridRow(
left = CellData("日期:", "DATA:", bean.fdate),
right = CellData("航班号:", "FLIGHT NO.:", bean.fno)
))
// 第2行目的站 | 板型
rows.add(GridRow(
left = CellData("目的站:", "DESTINATION:", bean.fdest),
right = CellData("板型:", "PALLET TYPE:", bean.boardType)
))
// 第3行集装器编号合并两列
rows.add(GridRow(
merged = CellData("集装器编号:", "ULD NO.:", bean.uld)
))
// 第4行件数 | 重量
rows.add(GridRow(
left = CellData("件数:", "PIECES:", bean.pieces.ifEmpty { "0" }),
right = CellData("重量:", "GROSS WEIGHT:", bean.totalWeight.toInt().toString())
))
// 第5行备注合并两列
rows.add(GridRow(
merged = CellData("备注:", "NOTES:", bean.remark)
))
printMergedGrid(rows)
}
private fun printCommonGrid(rowItem: ArrayList<List<String>>) {
val gridStartX = 80
val gridStartY = 300
@@ -370,10 +423,10 @@ object PrinterUtils {
if (index % 2 == 0) {
padding = 15
}
if (str.length == 2){
if (str.length == 2) {
padding += 60
}
if (str.length == 3){
if (str.length == 3) {
padding += 30
}
if (str.length == 7) {
@@ -391,6 +444,127 @@ object PrinterUtils {
portManager?.writeDataImmediately(bytes)
}
/**
* 打印支持合并单元格的表格
*/
private fun printMergedGrid(rows: ArrayList<GridRow>) {
val gridStartX = 30
val gridStartY = 250
val columnWidth = 570
val rowHeight = 240
val gridWidth = columnWidth * 2
val gridHeight = rowHeight * rows.size
val bytes = Tspl().apply {
addSize(100, 100)
addGap(3)
addCls()
addTextByBitmap(80, 80, 0, 130, "扬州泰州机场", Typeface.DEFAULT)
// 绘制表格横线
for (i in 0..rows.size) {
addBar(gridStartX, gridStartY + (i * rowHeight), gridWidth, 2)
}
// 绘制表格竖线(需要根据是否合并单元格决定)
rows.forEachIndexed { rowIndex, row ->
val yTop = gridStartY + (rowIndex * rowHeight)
// 左边线(总是绘制)
addBar(gridStartX, yTop, 2, rowHeight)
// 中间分隔线(非合并单元格才绘制)
if (row.merged == null) {
addBar(gridStartX + columnWidth, yTop, 2, rowHeight)
}
// 右边线(总是绘制)
if (rowIndex == rows.size - 1) {
addBar(gridStartX + gridWidth, yTop, 2, rowHeight)
}
}
// 填充单元格内容
rows.forEachIndexed { rowIndex, row ->
val yBase = gridStartY + (rowIndex * rowHeight)
if (row.merged != null) {
// 合并单元格
renderCell(
cell = row.merged,
x = gridStartX + 30,
y = yBase,
cellWidth = gridWidth,
cellHeight = rowHeight
)
} else {
// 左列单元格
row.left?.let { cell ->
renderCell(
cell = cell,
x = gridStartX + 30,
y = yBase,
cellWidth = columnWidth,
cellHeight = rowHeight
)
}
// 右列单元格
row.right?.let { cell ->
renderCell(
cell = cell,
x = gridStartX + columnWidth + 30,
y = yBase,
cellWidth = columnWidth,
cellHeight = rowHeight
)
}
}
}
addPrint(1)
}.bytes
portManager?.writeDataImmediately(bytes)
}
/**
* 渲染单元格内容
* @param cell 单元格数据
* @param x 起始X坐标
* @param y 起始Y坐标
* @param cellWidth 单元格宽度(用于计算右侧对齐)
* @param cellHeight 单元格高度(用于计算垂直居中)
*/
private fun Tspl.renderCell(
cell: CellData,
x: Int,
y: Int,
cellWidth: Int,
cellHeight: Int
) {
// 左上角:中文标签和英文标签
val titleY = y + 30 // 中文标签Y位置
val subtitleY = y + 80 // 英文标签Y位置中文下方
// 中文标签(大字,左上)
addText(x, titleY, Tspl.FONT_TSS24, 0, 3, 3, cell.title)
// 英文标签(小字,左上)
addText(x, subtitleY, Tspl.FONT_TSS24, 0, 2, 2, cell.subtitle)
// 右侧:值(大字,垂直居中)
// 计算垂直居中的Y坐标y + (cellHeight / 2) - (文字高度 / 2)
// 假设size=3的文字高度约为80像素
val valueY = y + (cellHeight / 2) - 40 // 垂直居中
// 计算右侧X坐标中文标签宽度 + 间距
// 假设"目的站:"宽度约为180像素"DESTINATION:"宽度约为240像素
val valueX = x + 280 // 右侧偏移量
// 值(大字,垂直居中,右侧)
addText(valueX, valueY, Tspl.FONT_TSS24, 0, 3, 3, cell.value)
}
fun printTest() {
getConnectedPrinters().forEach {
val bytes = v(Instruction.TSC.toString(), null).bytes

View File

@@ -2,6 +2,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#999999" />
<solid android:color="@color/color_f2" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorPrimary" />
</shape>

View File

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

View File

@@ -3,8 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll_container"
android:layout_width="match_parent"
android:layout_height="42dp"
android:layout_margin="5dp"
android:layout_height="40dp"
android:layout_margin="4dp"
android:focusableInTouchMode="false"
android:focusable="false"
android:clickable="false"

View File

@@ -52,6 +52,9 @@ class GjcAssembleAllocateActivity :
binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f
}
// 初始化:获取分配人列表
viewModel.getAssembleCompanyList()
// 初始加载
viewModel.refresh()
}

View File

@@ -7,6 +7,7 @@ import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityGjcBoxWeighingAddBinding
import com.lukouguoji.gjc.viewModel.GjcBoxWeighingAddViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
/**
* 国际出港板箱过磅添加页面
@@ -22,6 +23,11 @@ class GjcBoxWeighingAddActivity :
setBackArrow("板箱过磅")
binding.viewModel = viewModel
viewModel.initOnCreated(this)
// 为架子车号、ULD编码、IMP代码添加大写字母和数字的输入限制
binding.carIdInput.et.setUpperCaseAlphanumericFilter()
binding.uldNoInput.et.setUpperCaseAlphanumericFilter()
binding.impCodeInput.et.setUpperCaseAlphanumericFilter()
}
companion object {

View File

@@ -8,6 +8,7 @@ import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityGjcHandoverBinding
import com.lukouguoji.gjc.viewModel.GjcHandoverViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -25,12 +26,16 @@ class GjcHandoverActivity :
setBackArrow("货物交接单")
binding.viewModel = viewModel
// 初始化数据
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context) {
fun start(context: Context, maWbId: Long) {
val starter = Intent(context, GjcHandoverActivity::class.java)
.putExtra(Constant.Key.MAWB_ID, maWbId)
context.startActivity(starter)
}
}

View File

@@ -38,7 +38,8 @@ class GjcInspectionDetailsActivity :
// 右侧文档按钮点击事件
findViewById<android.widget.ImageView>(R.id.ivDocument).setOnClickListener {
GjcHandoverActivity.start(this)
val maWbId = viewModel.dataBean.value?.maWbId ?: 0L
GjcHandoverActivity.start(this, maWbId)
}
binding.viewModel = viewModel

View File

@@ -30,6 +30,12 @@ class GjcWeighingListActivity :
binding.viewModel = viewModel
// 初始化代理人列表从API获取
viewModel.initAgentList()
// 初始化特码列表从API获取
viewModel.initSpecialCodeList()
// 绑定分页逻辑
viewModel.pageModel
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())

View File

@@ -3,6 +3,7 @@ package com.lukouguoji.gjc.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjc.R
@@ -24,6 +25,9 @@ class GjcWeighingRecordDetailsActivity :
private lateinit var adapter: CommonAdapter
// 当前编辑模式供ViewHolder获取
var currentEditMode = false
override fun layoutId() = R.layout.activity_gjc_weighing_record_details
override fun viewModelClass() = GjcWeighingRecordDetailsViewModel::class.java
@@ -34,7 +38,13 @@ class GjcWeighingRecordDetailsActivity :
binding.viewModel = viewModel
// 初始化RecyclerView
binding.recyclerView.layoutManager = LinearLayoutManager(this)
val layoutManager = LinearLayoutManager(this)
binding.recyclerView.layoutManager = layoutManager
// 添加分割线
val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
binding.recyclerView.addItemDecoration(divider)
adapter = CommonAdapter(
this,
R.layout.item_gjc_check_in_record,
@@ -47,17 +57,13 @@ class GjcWeighingRecordDetailsActivity :
adapter.refresh(records)
}
// 监听编辑模式变化,更新所有ViewHolder的编辑状态
// 监听编辑模式变化,更新当前编辑模式并刷新列表
viewModel.isEditMode.observe(this) { isEditMode ->
val layoutManager = binding.recyclerView.layoutManager as? LinearLayoutManager
layoutManager?.let {
for (i in 0 until adapter.itemCount) {
val holder = binding.recyclerView.findViewHolderForAdapterPosition(i)
as? GjcCheckInRecordViewHolder
holder?.updateEditMode(isEditMode)
adapter.notifyItemChanged(i)
}
}
// 更新当前编辑模式状态
currentEditMode = isEditMode
// 刷新所有可见的 ViewHolder
adapter.notifyDataSetChanged()
}
// 初始化数据

View File

@@ -30,6 +30,12 @@ class GjcWeighingRecordListActivity :
binding.viewModel = viewModel
// 初始化代理人列表
viewModel.initAgentList()
// 初始化特码列表
viewModel.initSpecialCodeList()
// 绑定分页逻辑
viewModel.pageModel
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())

View File

@@ -1,8 +1,13 @@
package com.lukouguoji.gjc.activity
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingStartBinding
@@ -18,6 +23,8 @@ import com.lukouguoji.module_base.router.ARouterConstants
class GjcWeighingStartActivity :
BaseBindingActivity<ActivityGjcWeighingStartBinding, GjcWeighingStartViewModel>() {
private var isExpanded = false
override fun layoutId() = R.layout.activity_gjc_weighing_start
override fun viewModelClass() = GjcWeighingStartViewModel::class.java
@@ -26,16 +33,163 @@ class GjcWeighingStartActivity :
setBackArrow("开始计重")
binding.viewModel = viewModel
viewModel.initOnCreated(this, intent)
setupFloatButtons()
}
private fun setupFloatButtons() {
// 主按钮点击事件
binding.mainFloatButton.setOnClickListener {
if (!isExpanded) {
expandButtons()
}
}
// 遮罩层点击事件
binding.maskView.setOnClickListener {
collapseButtons()
}
// 子按钮1点击事件 - 跳转到出港运抵页面
binding.subButton1.setOnClickListener {
com.alibaba.android.arouter.launcher.ARouter.getInstance()
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE)
.navigation()
collapseButtons()
}
// 子按钮2点击事件 - 跳转到计重记录
binding.subButton2.setOnClickListener {
com.alibaba.android.arouter.launcher.ARouter.getInstance()
.build(ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_LIST)
.navigation()
collapseButtons()
}
}
/**
* 展开子按钮
*/
private fun expandButtons() {
isExpanded = true
// 显示遮罩层
binding.maskView.visibility = View.VISIBLE
binding.maskView.alpha = 0f
binding.maskView.animate().alpha(0.3f).setDuration(200).start()
// 显示子按钮
binding.subButton1.visibility = View.VISIBLE
binding.subButton2.visibility = View.VISIBLE
// 子按钮1动画向左上方移动: 左移15dp, 上移55dp
val sub1TransX = ObjectAnimator.ofFloat(binding.subButton1, "translationX", 0f, -5f)
val sub1TransY = ObjectAnimator.ofFloat(binding.subButton1, "translationY", 0f, -25f)
val sub1Alpha = ObjectAnimator.ofFloat(binding.subButton1, "alpha", 0f, 1f)
val sub1Scale = ObjectAnimator.ofFloat(binding.subButton1, "scaleX", 0f, 1f)
val sub1ScaleY = ObjectAnimator.ofFloat(binding.subButton1, "scaleY", 0f, 1f)
val animSet1 = AnimatorSet()
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
animSet1.duration = 200
// 子按钮2动画向左下方移动: 左移55dp, 下移15dp
val sub2TransX = ObjectAnimator.ofFloat(binding.subButton2, "translationX", 0f, -25f)
val sub2TransY = ObjectAnimator.ofFloat(binding.subButton2, "translationY", 0f, -5f)
val sub2Alpha = ObjectAnimator.ofFloat(binding.subButton2, "alpha", 0f, 1f)
val sub2Scale = ObjectAnimator.ofFloat(binding.subButton2, "scaleX", 0f, 1f)
val sub2ScaleY = ObjectAnimator.ofFloat(binding.subButton2, "scaleY", 0f, 1f)
val animSet2 = AnimatorSet()
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
animSet2.duration = 200
animSet2.startDelay = 50
// 主按钮隐藏动画
binding.mainFloatButton.animate()
.scaleX(0f)
.scaleY(0f)
.alpha(0f)
.setDuration(150)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
binding.mainFloatButton.visibility = View.GONE
}
})
.start()
animSet1.start()
animSet2.start()
}
/**
* 收起子按钮
*/
private fun collapseButtons() {
isExpanded = false
// 隐藏遮罩层
binding.maskView.animate().alpha(0f).setDuration(200).withEndAction {
binding.maskView.visibility = View.GONE
}.start()
// 子按钮1动画回到原位
val sub1TransX = ObjectAnimator.ofFloat(binding.subButton1, "translationX", binding.subButton1.translationX, 0f)
val sub1TransY = ObjectAnimator.ofFloat(binding.subButton1, "translationY", binding.subButton1.translationY, 0f)
val sub1Alpha = ObjectAnimator.ofFloat(binding.subButton1, "alpha", 1f, 0f)
val sub1Scale = ObjectAnimator.ofFloat(binding.subButton1, "scaleX", 1f, 0f)
val sub1ScaleY = ObjectAnimator.ofFloat(binding.subButton1, "scaleY", 1f, 0f)
val animSet1 = AnimatorSet()
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
animSet1.duration = 200
// 子按钮2动画回到原位
val sub2TransX = ObjectAnimator.ofFloat(binding.subButton2, "translationX", binding.subButton2.translationX, 0f)
val sub2TransY = ObjectAnimator.ofFloat(binding.subButton2, "translationY", binding.subButton2.translationY, 0f)
val sub2Alpha = ObjectAnimator.ofFloat(binding.subButton2, "alpha", 1f, 0f)
val sub2Scale = ObjectAnimator.ofFloat(binding.subButton2, "scaleX", 1f, 0f)
val sub2ScaleY = ObjectAnimator.ofFloat(binding.subButton2, "scaleY", 1f, 0f)
val animSet2 = AnimatorSet()
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
animSet2.duration = 200
animSet1.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
binding.subButton1.visibility = View.GONE
}
})
animSet2.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
binding.subButton2.visibility = View.GONE
}
})
// 主按钮显示动画
binding.mainFloatButton.visibility = View.VISIBLE
binding.mainFloatButton.animate()
.scaleX(1f)
.scaleY(1f)
.alpha(1f)
.setDuration(200)
.setStartDelay(100)
.setListener(null)
.start()
animSet1.start()
animSet2.start()
}
companion object {
/**
* 启动开始计重页面
* @param context 上下文
* @param maWbId 运单ID
* @param maWbId 运单ID默认为0新增模式
*/
@JvmStatic
fun startForAdd(context: Context, maWbId: Long) {
fun startForAdd(context: Context, maWbId: Long = 0) {
val starter = Intent(context, GjcWeighingStartActivity::class.java)
.putExtra(Constant.Key.MAWB_ID, maWbId)
context.startActivity(starter)

View File

@@ -0,0 +1,70 @@
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.ActivityIntExpLoadBinding
import com.lukouguoji.gjc.viewModel.IntExpLoadViewModel
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.ktx.addOnItemClickListener
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际出港-出港装载页面
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_LOAD)
class IntExpLoadActivity :
BaseBindingActivity<ActivityIntExpLoadBinding, IntExpLoadViewModel>() {
override fun layoutId() = R.layout.activity_int_exp_load
override fun viewModelClass() = IntExpLoadViewModel::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<String>(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()
}
}
}
}
}

View File

@@ -0,0 +1,68 @@
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.ktx.addOnItemClickListener
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际出港-出港理货
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_TALLY)
class IntExpTallyActivity :
BaseBindingActivity<ActivityIntExpTallyBinding, IntExpTallyViewModel>() {
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<String>(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()
}
}
}
}
}

View File

@@ -0,0 +1,41 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogGjcAssembleAllocateBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港组装分配 - 分配人选择对话框
*/
class GjcAssembleAllocateDialogModel(
val flightInfo: String, // 航班信息(用于显示)
val assembleCompanyList: List<KeyValue>, // 分配人列表
private val callback: (GjcAssembleAllocateDialogModel) -> Unit
) : BaseDialogModel<DialogGjcAssembleAllocateBinding>(DIALOG_TYPE_CENTER) {
// 选中的分配人(存储的是 code例如 "ATR"
val allocator = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_gjc_assemble_allocate
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 确认按钮点击
*/
fun onConfirmClick() {
if (allocator.value.verifyNullOrEmpty("请选择分配人")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -0,0 +1,40 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogGjcInspectionRejectBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
/**
* 国际出港收运检查 - 退回原因对话框
*/
class GjcInspectionRejectDialogModel(
private val callback: (String) -> Unit // 回调传递退回原因
) : BaseDialogModel<DialogGjcInspectionRejectBinding>(DIALOG_TYPE_CENTER) {
// 退回原因
val rejectReason = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_gjc_inspection_reject
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 保存按钮点击
*/
fun onConfirmClick() {
// 验证退回原因
if (rejectReason.value.verifyNullOrEmpty("请输入退回原因")) {
return
}
dismiss()
callback(rejectReason.value!!)
}
}

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpArriveDeleteBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港运抵 - 删除申报对话框
*/
class IntExpArriveDeleteDialogModel(
val changeReasonList: List<KeyValue>, // 变更原因列表
private val callback: (IntExpArriveDeleteDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpArriveDeleteBinding>(DIALOG_TYPE_CENTER) {
// 变更原因代码(存储的是 code
val changeReason = MutableLiveData("")
// 联系人姓名
val contactName = MutableLiveData("")
// 联系人电话
val contactPhone = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_int_exp_arrive_delete
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 确认按钮点击
*/
fun onConfirmClick() {
// 验证变更原因
if (changeReason.value.verifyNullOrEmpty("请选择变更原因")) {
return
}
// 验证联系人姓名
if (contactName.value.verifyNullOrEmpty("请输入联系人姓名")) {
return
}
// 验证联系人电话
if (contactPhone.value.verifyNullOrEmpty("请输入联系人电话")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpLoadDeleteBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港装载 - 删除申报对话框
*/
class IntExpLoadDeleteDialogModel(
val changeReasonList: List<KeyValue>, // 变更原因列表
private val callback: (IntExpLoadDeleteDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpLoadDeleteBinding>(DIALOG_TYPE_CENTER) {
// 变更原因代码(存储的是 code
val changeReason = MutableLiveData("")
// 联系人姓名
val contactName = MutableLiveData("")
// 联系人电话
val contactPhone = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_int_exp_load_delete
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 确认按钮点击
*/
fun onConfirmClick() {
// 验证变更原因
if (changeReason.value.verifyNullOrEmpty("请选择变更原因")) {
return
}
// 验证联系人姓名
if (contactName.value.verifyNullOrEmpty("请输入联系人姓名")) {
return
}
// 验证联系人电话
if (contactPhone.value.verifyNullOrEmpty("请输入联系人电话")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpTallyDeleteBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港理货 - 删除申报对话框
*/
class IntExpTallyDeleteDialogModel(
val changeReasonList: List<KeyValue>, // 变更原因列表
private val callback: (IntExpTallyDeleteDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpTallyDeleteBinding>(DIALOG_TYPE_CENTER) {
// 变更原因代码(存储的是 code
val changeReason = MutableLiveData("")
// 联系人姓名
val contactName = MutableLiveData("")
// 联系人电话
val contactPhone = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_int_exp_tally_delete
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 确认按钮点击
*/
fun onConfirmClick() {
// 验证变更原因
if (changeReason.value.verifyNullOrEmpty("请选择变更原因")) {
return
}
// 验证联系人姓名
if (contactName.value.verifyNullOrEmpty("请输入联系人姓名")) {
return
}
// 验证联系人电话
if (contactPhone.value.verifyNullOrEmpty("请输入联系人电话")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -7,6 +7,9 @@ import com.lukouguoji.module_base.bean.AssembleInfoBean
/**
* 组装信息ViewHolder
* 支持两种行类型:
* 1. 一级ULD行: 显示ULD编号、总件数、总重量、展开/折叠箭头
* 2. 二级运单行: 显示缩进、运单号、件数、重量
*/
class AssembleInfoViewHolder(view: View) :
BaseViewHolder<AssembleInfoBean, ItemAssembleInfoBinding>(view) {
@@ -15,6 +18,12 @@ class AssembleInfoViewHolder(view: View) :
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
// 设置点击事件type=2表示组装信息列表点击
itemView.setOnClickListener {
clickListener?.onItemClick(position, 2)
}
binding.executePendingBindings()
}
}

View File

@@ -16,9 +16,9 @@ class AssembleWaybillViewHolder(view: View) :
binding.bean = bean
binding.position = position
// 点击运单
// 点击整行触发选择事件(单选模式,通过回调处理)
itemView.setOnClickListener {
clickListener?.onItemClick(position, 0)
clickListener?.onItemClick(position, 1) // type=1表示运单列表点击
}
binding.executePendingBindings()

View File

@@ -1,6 +1,7 @@
package com.lukouguoji.gjc.holder
import android.view.View
import com.lukouguoji.gjc.activity.GjcWeighingRecordDetailsActivity
import com.lukouguoji.gjc.databinding.ItemGjcCheckInRecordBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjcCheckInRecord
@@ -11,14 +12,13 @@ import com.lukouguoji.module_base.bean.GjcCheckInRecord
class GjcCheckInRecordViewHolder(view: View) :
BaseViewHolder<GjcCheckInRecord, ItemGjcCheckInRecordBinding>(view) {
private var isEditMode: Boolean = false
fun updateEditMode(editMode: Boolean) {
this.isEditMode = editMode
}
override fun onBind(item: Any?, position: Int) {
val record = getItemBean(item)!!
// 从Activity获取当前编辑模式
val activity = itemView.context as? GjcWeighingRecordDetailsActivity
val isEditMode = activity?.currentEditMode ?: false
binding.record = record
binding.isEditMode = isEditMode
binding.position = position // 传入位置用于显示序号

View File

@@ -0,0 +1,29 @@
package com.lukouguoji.gjc.holder
import android.view.View
import com.lukouguoji.gjc.databinding.ItemIntExpLoadBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjcExportLoad
/**
* 国际出港-出港装载 列表项ViewHolder
*/
class IntExpLoadViewHolder(view: View) :
BaseViewHolder<GjcExportLoad, ItemIntExpLoadBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
// 添加图标点击事件 - 切换选择状态
binding.ivIcon.setOnClickListener {
// 反转checked状态
bean.checked.set(!bean.checked.get())
// 立即更新UI (图片自动切换)
binding.executePendingBindings()
}
}
}

View File

@@ -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<GjcMaWb, ItemIntExpTallyBinding>(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()
}
}
}

View File

@@ -26,6 +26,9 @@ class IntExpAssembleActivity :
setBackArrow("出港组装")
binding.viewModel = viewModel
// 初始化组装人下拉列表
viewModel.initAssemblerList()
// 绑定分页
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
@@ -36,5 +39,8 @@ class IntExpAssembleActivity :
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
// 首次加载数据
viewModel.refresh()
}
}

View File

@@ -1,5 +1,6 @@
package com.lukouguoji.gjc.page.assemble
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -10,6 +11,10 @@ import com.lukouguoji.gjc.databinding.ActivityIntExpAssembleStartBinding
import com.lukouguoji.gjc.viewModel.IntExpAssembleStartViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -17,7 +22,8 @@ import com.lukouguoji.module_base.router.ARouterConstants
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_ASSEMBLE_START)
class IntExpAssembleStartActivity :
BaseBindingActivity<ActivityIntExpAssembleStartBinding, IntExpAssembleStartViewModel>() {
BaseBindingActivity<ActivityIntExpAssembleStartBinding, IntExpAssembleStartViewModel>(),
IOnItemClickListener {
private var assembleInfoAdapter: CommonAdapter? = null
private var assemblePositionAdapter: CommonAdapter? = null
@@ -39,11 +45,20 @@ class IntExpAssembleStartActivity :
setBackArrow("开始组装")
binding.viewModel = viewModel
// 为ULD编号添加大写字母和数字的输入限制
binding.uldNoInput.et.setUpperCaseAlphanumericFilter()
// 初始化列表
initRecyclerViews()
// 加载模拟数据
viewModel.initMockData()
// 初始化加载待组装运单数据
viewModel.loadInitialWaitingAssemble()
// 加载组装位置数据从API
viewModel.loadAssemblePosition()
// 加载组装人列表
viewModel.loadAssemblerList()
// 观察数据变化
observeData()
@@ -61,6 +76,8 @@ class IntExpAssembleStartActivity :
)
binding.rvAssembleInfo.layoutManager = LinearLayoutManager(this)
binding.rvAssembleInfo.adapter = assembleInfoAdapter
// 添加点击监听器
binding.rvAssembleInfo.addOnItemClickListener(this)
// 左侧组装位置列表
assemblePositionAdapter = CommonAdapter(
@@ -70,6 +87,8 @@ class IntExpAssembleStartActivity :
)
binding.rvAssemblePosition.layoutManager = LinearLayoutManager(this)
binding.rvAssemblePosition.adapter = assemblePositionAdapter
// 添加点击监听器
binding.rvAssemblePosition.addOnItemClickListener(this)
// 右侧运单列表
waybillAdapter = CommonAdapter(
@@ -79,6 +98,8 @@ class IntExpAssembleStartActivity :
)
binding.rvWaybillList.layoutManager = LinearLayoutManager(this)
binding.rvWaybillList.adapter = waybillAdapter
// 添加点击监听器
binding.rvWaybillList.addOnItemClickListener(this)
}
/**
@@ -97,4 +118,34 @@ class IntExpAssembleStartActivity :
waybillAdapter?.refresh(list)
}
}
/**
* 列表项点击事件
*/
override fun onItemClick(position: Int, type: Int) {
when (type) {
0 -> viewModel.onPositionItemClick(position) // 组装位置点击
1 -> viewModel.onWaybillItemClick(position) // 运单列表点击
2 -> viewModel.onAssembleInfoItemClick(position) // 组装信息列表点击
else -> {}
}
}
/**
* 处理扫码结果
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {
// 获取扫码结果
val codedContent = data?.getStringExtra(Constant.Result.CODED_CONTENT)
// 更新搜索框内容
viewModel.searchText.value = codedContent
// 自动触发查询
viewModel.loadWaitingAssembleWaybills()
}
}
}

View File

@@ -2,11 +2,14 @@ package com.lukouguoji.gjc.viewModel
import android.app.AlertDialog
import android.widget.EditText
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.GjcAssembleAllocateDialogModel
import com.lukouguoji.gjc.holder.GjcAssembleAllocateViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.AssembleCompanyBean
import com.lukouguoji.module_base.bean.GjcAssembleAllocate
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.http.net.NetApply
@@ -17,6 +20,7 @@ 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.util.CheckUtil
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/**
@@ -37,12 +41,14 @@ class GjcAssembleAllocateViewModel : BasePageViewModel() {
// 统计数据
val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
// 全选状态
val isAllChecked = MutableLiveData(false)
// 分配人列表(从接口获取,存储 KeyValue 格式)
private val _assembleCompanyList = MutableLiveData<List<KeyValue>>(emptyList())
val assembleCompanyList: LiveData<List<KeyValue>> = _assembleCompanyList
///////////////////////////////////////////////////////////////////////////
// 方法区
///////////////////////////////////////////////////////////////////////////
@@ -95,8 +101,6 @@ class GjcAssembleAllocateViewModel : BasePageViewModel() {
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()
}
}
}
@@ -129,6 +133,19 @@ class GjcAssembleAllocateViewModel : BasePageViewModel() {
updateCheckAllStatus()
}
/**
* 获取分配人列表
* 在 Activity 初始化时调用
*/
fun getAssembleCompanyList() {
launchCollect({ NetApply.api.getAssembleCompanyList() }) {
onSuccess = { result ->
val list = result.data?.map { it.toKeyValue() } ?: emptyList()
_assembleCompanyList.value = list
}
}
}
/**
* 分配按钮点击
*/
@@ -141,45 +158,45 @@ class GjcAssembleAllocateViewModel : BasePageViewModel() {
return
}
// 显示分配人输入对话框
showAllocatorInputDialog(selectedItems)
// 检查分配人列表是否为空
if (_assembleCompanyList.value.isNullOrEmpty()) {
showToast("分配人列表为空,请稍后重试")
return
}
// 显示分配人选择对话框
showAllocatorSelectDialog(selectedItems)
}
/**
* 显示分配人输入对话框
* 显示分配人选择对话框
*/
private fun showAllocatorInputDialog(items: List<GjcAssembleAllocate>) {
val activity = getTopActivity()
val editText = EditText(activity)
editText.hint = "请输入分配人姓名"
private fun showAllocatorSelectDialog(items: List<GjcAssembleAllocate>) {
// 构建航班信息字符串例如CA1234、MU5678
val flightInfo = items.joinToString("") { it.fno ?: "" }
AlertDialog.Builder(activity)
.setTitle("分配人员")
.setView(editText)
.setPositiveButton("确定") { dialog, _ ->
val allocatorName = editText.text.toString().trim()
if (allocatorName.isEmpty()) {
showToast("请输入分配人姓名")
} else {
performAllocate(items, allocatorName)
dialog.dismiss()
}
}
.setNegativeButton("取消") { dialog, _ ->
dialog.dismiss()
}
.show()
GjcAssembleAllocateDialogModel(
flightInfo = flightInfo,
assembleCompanyList = _assembleCompanyList.value ?: emptyList()
) { dialog ->
// 回调:用户点击确定后执行分配操作
// dialog.allocator.value 存储的是选中的 code例如 "ATR"
val allocatorCode = dialog.allocator.value ?: ""
performAllocate(items, allocatorCode)
}.show(getTopActivity())
}
/**
* 执行分配操作
* @param items 选中的航班列表
* @param allocatorCode 分配人代码(例如 "ATR",而非 "ATR:马道"
*/
private fun performAllocate(items: List<GjcAssembleAllocate>, allocatorName: String) {
private fun performAllocate(items: List<GjcAssembleAllocate>, allocatorCode: String) {
val fidList = items.mapNotNull { it.fid }
val requestData = mapOf(
"fidList" to fidList, // 航班ID列表
"acName" to allocatorName // 分配人姓名
"abId" to allocatorCode // 分配人代码(传递 code 而非 name
).toRequestBody()
launchLoadingCollect({ NetApply.api.allocateAssemble(requestData) }) {

View File

@@ -15,14 +15,17 @@ import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.getActivity
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 com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import com.lukouguoji.module_base.model.BluetoothDialogModel
import com.lukouguoji.module_base.model.ScanModel
import com.lukouguoji.module_base.util.Common
import com.lukouguoji.module_base.util.DictUtils
import com.lukouguoji.module_base.util.PrinterUtils
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
import java.util.Calendar
@@ -40,11 +43,20 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
// val diBangModel = DiBangWeightModel()
val channel = MutableLiveData("") // 通道号用于控制地磅key
// 地磅称重输入(独立字段,单向同步到总重)
val diBangWeight = MutableLiveData("0")
// 计算字段显示
val totalWeight = MutableLiveData("0") // 总重(红色)
val netWeight = MutableLiveData("0") // 装机重(蓝色)
val cargoWeight = MutableLiveData("0") // 货重(绿色)
// 需要自动查询的独立字段(用于监听输入变化)
val carId = MutableLiveData("") // 架子车号
val uldNo = MutableLiveData("") // ULD编号
val flightNo = MutableLiveData("") // 航班号
val flightDate = MutableLiveData("") // 航班日期
// 下拉选择数据源
val passagewayList = MutableLiveData<List<KeyValue>>() // 通道号列表
val piCloseList = MutableLiveData<List<KeyValue>>() // 探板收口列表
@@ -52,6 +64,11 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
// 打印挂签
val printTag = MutableLiveData(false)
// 标记位,避免重复查询
private var lastQueriedFlight = ""
private var lastQueriedCarId = ""
private var lastQueriedUld = ""
/**
* 初始化
*/
@@ -70,20 +87,117 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
// diBangModel.key = it ?: ""
// }
// 监听地磅称重输入,单向同步到总重
diBangWeight.observe(activity as LifecycleOwner) { weight ->
val w = weight?.toDoubleOrNull() ?: 0.0
totalWeight.value = w.toString()
dataBean.value = dataBean.value?.apply { totalWeight = w }
// 实时计算装机重和货重
calculateWeights()
}
// 监听总重变化,实时计算装机重和货重
totalWeight.observe(activity as LifecycleOwner) {
val w = it?.toDoubleOrNull() ?: 0.0
dataBean.value = dataBean.value?.apply { totalWeight = w }
calculateWeights()
}
// 加载下拉列表数据
loadPassagewayList()
loadPiCloseList()
// 初始化航班日期为今天
dataBean.value?.fdate = Date().formatDate()
val today = Date().formatDate()
flightDate.value = today
dataBean.value?.fdate = today
}
/**
* 架子车号输入完成时调用
*/
fun onCarIdInputComplete() {
val id = carId.value
if (!id.isNullOrEmpty() && id != lastQueriedCarId) {
lastQueriedCarId = id
queryFlatcarInfo(id)
}
}
/**
* ULD编号输入完成时调用
*/
fun onUldNoInputComplete() {
val uld = uldNo.value
if (!uld.isNullOrEmpty() && uld != lastQueriedUld) {
lastQueriedUld = uld
queryUldInfo(uld)
}
}
/**
* 航班号输入完成时调用
*/
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
/**
* 航班日期输入完成时调用
*/
fun onFlightDateInputComplete() {
// 清除查询标记,以便重新查询
lastQueriedFlight = ""
queryFlightIfReady()
}
/**
* 检查航班日期和航班号,如果都有值则查询航班信息
*/
private fun queryFlightIfReady() {
val fdate = flightDate.value
val fno = flightNo.value
if (!fdate.isNullOrEmpty() && !fno.isNullOrEmpty()) {
val key = "$fdate-$fno"
if (key != lastQueriedFlight) {
lastQueriedFlight = key
queryFlightInfo(fdate, fno)
}
}
}
/**
* 查询航班信息,自动填充目的港
*/
private fun queryFlightInfo(fdate: String, fno: String) {
val params = mapOf(
"fdate" to fdate,
"fno" to fno,
"countryType" to "1" // 国际航班
).toRequestBody()
launchCollect({ NetApply.api.queryFlightByDateAndNo(params) }) {
onSuccess = { result ->
val flight = result.data
if (flight != null) {
dataBean.value = dataBean.value?.apply {
fdest = flight.fdest
}
}
}
}
}
/**
* 加载通道号列表
*/
private fun loadPassagewayList() {
DictUtils.getChannelList {
passagewayList.value = it
launchCollect({
NetApply.api.getDictList("GJPASSAGEWAY")
}) {
onSuccess = {
passagewayList.value = (it.data ?: emptyList()).map { b -> b.toKeyValue() }
}
}
}
@@ -122,11 +236,16 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
* 航班日期点击
*/
fun flightDateClick(view: View) {
Common.onYearMonthDay(view.context.getActivity(), dataBean.value?.fdate) { year, month, day ->
Common.onYearMonthDay(view.context.getActivity(), flightDate.value) { year, month, day ->
val calendar = Calendar.getInstance()
calendar.set(year, month - 1, day)
val date = calendar.time.formatDate()
// 清除查询标记,以便重新查询
lastQueriedFlight = ""
flightDate.value = date
dataBean.value = dataBean.value?.apply { fdate = date }
// 日期选择完成后立即触发查询
onFlightDateInputComplete()
}
}
@@ -148,14 +267,28 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
* 重置按钮点击
*/
fun resetClick() {
val today = Date().formatDate()
dataBean.value = GjcUldUseBean().apply {
fdate = Date().formatDate()
fdate = today
}
diBangWeight.value = "0"
totalWeight.value = "0"
netWeight.value = "0"
cargoWeight.value = "0"
channel.value = ""
printTag.value = false
// 重置独立字段
carId.value = ""
uldNo.value = ""
flightNo.value = ""
flightDate.value = today
// 重置查询标记
lastQueriedFlight = ""
lastQueriedCarId = ""
lastQueriedUld = ""
}
/**
@@ -164,6 +297,12 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
fun confirmClick() {
val bean = dataBean.value ?: return
// 同步独立字段到 dataBean
bean.carId = carId.value ?: ""
bean.uld = uldNo.value ?: ""
bean.fno = flightNo.value ?: ""
bean.fdate = flightDate.value ?: ""
// 验证必填字段
if (bean.carId.verifyNullOrEmpty("请输入架子车号")) return
if (bean.uld.verifyNullOrEmpty("请输入ULD编号")) return
@@ -196,6 +335,12 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
onSuccess = { result ->
if (result.verifySuccess()) {
showToast("添加成功")
// 如果勾选了打印挂签,则执行打印
if (printTag.value == true) {
executePrint()
}
// 发送刷新事件
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
@@ -208,6 +353,19 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
}
}
/**
* 执行打印
*/
private fun executePrint() {
val bean = dataBean.value ?: return
// 使用 BluetoothDialogModel 选择打印机并打印
BluetoothDialogModel()
.showCallBack {
PrinterUtils.printGjcBoxWeighing(bean)
}
}
/**
* 处理扫码结果
*/
@@ -216,10 +374,58 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
val content = data.getStringExtra(Constant.Result.CODED_CONTENT).noNull()
when (requestCode) {
Constant.RequestCode.ULD -> {
// 更新独立字段
uldNo.value = content
dataBean.value = dataBean.value?.apply { uld = content }
// 扫码完成后立即查询
onUldNoInputComplete()
}
Constant.RequestCode.CAR -> {
// 更新独立字段
carId.value = content
dataBean.value = dataBean.value?.apply { carId = content }
// 扫码完成后立即查询
onCarIdInputComplete()
}
}
}
}
/**
* 查询ULD信息
*/
private fun queryUldInfo(uldNo: String) {
launchCollect({ NetApply.api.queryUldByCode(uldNo) }) {
onSuccess = { result ->
val uldBean = result.data
if (uldBean != null) {
val weight = uldBean.uldWeight.toDoubleOrNull() ?: 0.0
dataBean.value = dataBean.value?.apply {
uldWeight = weight
maxWeight = uldBean.maxWeight.toDoubleOrNull() ?: 0.0
maxVolume = uldBean.maxVolume.toDoubleOrNull() ?: 0.0
}
// 触发重量计算
calculateWeights()
}
}
}
}
/**
* 查询架子车信息
*/
private fun queryFlatcarInfo(carId: String) {
launchCollect({ NetApply.api.getFlatcarInfo(carId) }) {
onSuccess = { result ->
val flatcarBean = result.data
if (flatcarBean != null) {
val weight = flatcarBean.carWeight.toDoubleOrNull() ?: 0.0
dataBean.value = dataBean.value?.apply {
carWeight = weight
}
// 触发重量计算
calculateWeights()
}
}
}

View File

@@ -33,7 +33,6 @@ class GjcBoxWeighingViewModel : BasePageViewModel() {
val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
val cargoWeight = MutableLiveData("0") // 总货重
///////////////////////////////////////////////////////////////////////////
// 方法区
@@ -123,7 +122,6 @@ class GjcBoxWeighingViewModel : BasePageViewModel() {
totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
cargoWeight.value = (data?.cargoWeight ?: 0.0).toString()
}
}
}

View File

@@ -1,19 +1,439 @@
package com.lukouguoji.gjc.viewModel
import android.app.AlertDialog
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjcHandoverSheetBean
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.*
import java.util.Date
/**
* 国际出港货物交接单 ViewModel
*/
class GjcHandoverViewModel : BaseViewModel() {
// 暂时为静态页面,无业务逻辑
// 运单主键ID
var maWbId: Long = 0L
fun cancelClick() {
// 数据Bean
val dataBean = MutableLiveData(GjcHandoverSheetBean())
// ========== 主单数据持有者 ==========
val maWbData = MutableLiveData<GjcMaWb>(GjcMaWb())
// ========== 计算/格式化字段 ==========
val displayAgentName = MutableLiveData<String>() // 托运人/交货单位/盖章单位
val displayDeliveryDate = MutableLiveData<String>() // 交货日期2025年12月03日
val displayFlightPlan = MutableLiveData<String>() // 计划班期MU5555/2025-12-03/LAX
val displayWaybillNo = MutableLiveData<String>() // 货单号834-91508524
val displayGoods = MutableLiveData<String>() // 品名(优先中文)
val displayPc = MutableLiveData<String>() // 件数
val displayWeight = MutableLiveData<String>() // 重量
val displayVolume = MutableLiveData<String>() // 体积
val displayChargeWeight = MutableLiveData<String>() // 计费重量
val displayRemark = MutableLiveData<String>() // 备注
// ========== 跨境电商单选框 ==========
val cbEcFlag = MutableLiveData("1") // 默认选中"是"
/**
* 跨境电商RadioButton点击已禁用仅根据expressName自动判断
*/
fun onCbEcFlagClick(value: String) {
// 不允许手动点击修改仅根据expressName自动判断
}
fun saveClick() {
// ========== 防止隐含危险品检查单 ==========
val goodsNameYes = MutableLiveData(false) // 品名为确指品名-是
val goodsNameNo = MutableLiveData(false) // 品名为确指品名-否
val dangerYes = MutableLiveData(false) // 不含危险品-是
val dangerNo = MutableLiveData(false) // 不含危险品-否
val fishYes = MutableLiveData(false) // 非观赏鱼类-是
val fishNo = MutableLiveData(false) // 非观赏鱼类-否
val packagingYes = MutableLiveData(false) // 无油渍渗漏-是
val packagingNo = MutableLiveData(false) // 无油渍渗漏-否
val labelsYes = MutableLiveData(false) // 清除标记-是
val labelsNo = MutableLiveData(false) // 清除标记-否
// ========== 高风险货物检查单 ==========
val appearanceYes = MutableLiveData(false) // 外观异常-是
val appearanceNo = MutableLiveData(false) // 外观异常-否
val threatYes = MutableLiveData(false) // 情报威胁-是
val threatNo = MutableLiveData(false) // 情报威胁-否
val highRiskYes = MutableLiveData(false) // 高风险-是
val highRiskNo = MutableLiveData(false) // 高风险-否
// ========== 跨境电商检查单 ==========
val submitStatementYes = MutableLiveData(false) // 提交声明-是
val submitStatementNA = MutableLiveData(false) // 提交声明-不适用
val submitStatementNo = MutableLiveData(false) // 提交声明-否
// ========== 安检信息 ==========
val securityChannel = MutableLiveData("") // 安检机通道号
val securityStartTime = MutableLiveData("") // 开始过机时间
val securityEndTime = MutableLiveData("") // 结束过机时间
/**
* 初始化(从Intent获取参数并加载数据)
*/
fun initOnCreated(intent: Intent) {
maWbId = intent.getLongExtra(Constant.Key.MAWB_ID, 0L)
if (maWbId > 0) {
loadData()
}
}
/**
* 加载交接单数据
*/
private fun loadData() {
launchLoadingCollect({ NetApply.api.queryHandoverSheet(maWbId) }) {
onSuccess = { result ->
val response = result.data
val maWb = response?.maWb
val handoverSheet = response?.handoverSheet
// 创建或更新dataBean
val bean = (handoverSheet ?: GjcHandoverSheetBean()).apply {
// 如果handoverSheet为null从maWb填充基础信息
if (handoverSheet == null && maWb != null) {
this.maWbId = maWb.maWbId
this.prefix = maWb.prefix
this.no = maWb.no
this.chargeWeight = maWb.weight // 使用主单重量作为计费重量
this.saleAgentCode = maWb.agentCode
}
}
dataBean.value = bean
// 填充主单数据
maWbData.value = maWb ?: GjcMaWb()
// 计算格式化字段
updateDisplayFields(maWb)
// 填充CheckBox状态
updateCheckBoxState(bean)
// 填充安检信息
securityChannel.value = bean.securityChannel ?: ""
securityStartTime.value = bean.securityStartTime ?: ""
securityEndTime.value = bean.securityEndTime ?: ""
}
}
}
/**
* 根据Bean数据更新CheckBox状态
*/
private fun updateCheckBoxState(bean: GjcHandoverSheetBean) {
// 跨境电商 - 根据expressName自动判断
// 当expressName不为null且不为空时为"是"(1),否则为"否"(0)
cbEcFlag.value = if (!bean.expressName.isNullOrEmpty()) "1" else "0"
// 防止隐含危险品检查单
goodsNameYes.value = (bean.goodsName == "1")
goodsNameNo.value = (bean.goodsName == "0")
dangerYes.value = (bean.danger == "1")
dangerNo.value = (bean.danger == "0")
fishYes.value = (bean.fish == "1")
fishNo.value = (bean.fish == "0")
packagingYes.value = (bean.packaging == "1")
packagingNo.value = (bean.packaging == "0")
labelsYes.value = (bean.labels == "1")
labelsNo.value = (bean.labels == "0")
// 高风险货物检查单
appearanceYes.value = (bean.appearance == "1")
appearanceNo.value = (bean.appearance == "0")
threatYes.value = (bean.threat == "1")
threatNo.value = (bean.threat == "0")
highRiskYes.value = (bean.highRisk == "1")
highRiskNo.value = (bean.highRisk == "0")
// 跨境电商检查单
submitStatementYes.value = (bean.submitStatement == "1")
submitStatementNA.value = (bean.submitStatement == "2")
submitStatementNo.value = (bean.submitStatement == "0")
}
/**
* CheckBox点击事件处理(防止隐含危险品)
*/
fun onGoodsNameClick(isYes: Boolean) {
if (isYes) {
goodsNameYes.value = true
goodsNameNo.value = false
} else {
goodsNameYes.value = false
goodsNameNo.value = true
}
}
fun onDangerClick(isYes: Boolean) {
if (isYes) {
dangerYes.value = true
dangerNo.value = false
} else {
dangerYes.value = false
dangerNo.value = true
}
}
fun onFishClick(isYes: Boolean) {
if (isYes) {
fishYes.value = true
fishNo.value = false
} else {
fishYes.value = false
fishNo.value = true
}
}
fun onPackagingClick(isYes: Boolean) {
if (isYes) {
packagingYes.value = true
packagingNo.value = false
} else {
packagingYes.value = false
packagingNo.value = true
}
}
fun onLabelsClick(isYes: Boolean) {
if (isYes) {
labelsYes.value = true
labelsNo.value = false
} else {
labelsYes.value = false
labelsNo.value = true
}
}
/**
* CheckBox点击事件处理(高风险货物)
*/
fun onAppearanceClick(isYes: Boolean) {
if (isYes) {
appearanceYes.value = true
appearanceNo.value = false
} else {
appearanceYes.value = false
appearanceNo.value = true
}
}
fun onThreatClick(isYes: Boolean) {
if (isYes) {
threatYes.value = true
threatNo.value = false
} else {
threatYes.value = false
threatNo.value = true
}
}
fun onHighRiskClick(isYes: Boolean) {
if (isYes) {
highRiskYes.value = true
highRiskNo.value = false
} else {
highRiskYes.value = false
highRiskNo.value = true
}
}
/**
* CheckBox点击事件处理(跨境电商)
*/
fun onSubmitStatementClick(type: Int) {
when (type) {
1 -> { // 是
submitStatementYes.value = true
submitStatementNA.value = false
submitStatementNo.value = false
}
2 -> { // 不适用
submitStatementYes.value = false
submitStatementNA.value = true
submitStatementNo.value = false
}
0 -> { // 否
submitStatementYes.value = false
submitStatementNA.value = false
submitStatementNo.value = true
}
}
}
/**
* 取消按钮点击
*/
fun cancelClick() {
AlertDialog.Builder(getTopActivity())
.setTitle("提示")
.setMessage("确定要取消吗?未保存的数据将丢失")
.setPositiveButton("确定") { _, _ -> getTopActivity().finish() }
.setNegativeButton("取消", null)
.show()
}
/**
* 保存按钮点击
*/
fun saveClick() {
val bean = dataBean.value ?: GjcHandoverSheetBean()
// 更新Bean中的CheckBox字段
bean.maWbId = maWbId
bean.cbEcFlag = cbEcFlag.value
// 防止隐含危险品检查单
bean.goodsName = if (goodsNameYes.value == true) "1" else if (goodsNameNo.value == true) "0" else null
bean.danger = if (dangerYes.value == true) "1" else if (dangerNo.value == true) "0" else null
bean.fish = if (fishYes.value == true) "1" else if (fishNo.value == true) "0" else null
bean.packaging = if (packagingYes.value == true) "1" else if (packagingNo.value == true) "0" else null
bean.labels = if (labelsYes.value == true) "1" else if (labelsNo.value == true) "0" else null
// 高风险货物检查单
bean.appearance = if (appearanceYes.value == true) "1" else if (appearanceNo.value == true) "0" else null
bean.threat = if (threatYes.value == true) "1" else if (threatNo.value == true) "0" else null
bean.highRisk = if (highRiskYes.value == true) "1" else if (highRiskNo.value == true) "0" else null
// 跨境电商检查单
bean.submitStatement = when {
submitStatementYes.value == true -> "1"
submitStatementNA.value == true -> "2"
submitStatementNo.value == true -> "0"
else -> null
}
// 发送保存请求(已删除不需要的安检信息字段赋值)
launchLoadingCollect({ NetApply.api.saveHandoverSheet(bean.toRequestBody()) }) {
onSuccess = {
showToast("保存成功")
getTopActivity().finish()
}
}
}
/**
* 更新格式化/计算字段
*/
private fun updateDisplayFields(maWb: GjcMaWb?) {
if (maWb == null) {
displayAgentName.value = ""
displayDeliveryDate.value = ""
displayFlightPlan.value = ""
displayWaybillNo.value = ""
displayGoods.value = ""
displayPc.value = "0"
displayWeight.value = "0.0"
displayVolume.value = "0.0"
displayChargeWeight.value = "0.0"
displayRemark.value = ""
return
}
// 1. 托运人/交货单位/盖章单位
displayAgentName.value = maWb.agentName ?: ""
// 2. 交货日期格式化Date → "2025年12月03日"
displayDeliveryDate.value = formatDeliveryDate(maWb.opDate)
// 3. 计划班期拼接:航班号/日期/目的地
displayFlightPlan.value = buildFlightPlan(maWb.fno, maWb.fdate, maWb.dest)
// 4. 货单号拼接prefix-no
displayWaybillNo.value = buildWaybillNo(maWb.prefix, maWb.no)
// 5. 品名(优先中文)
displayGoods.value = maWb.goodsCn?.ifEmpty { maWb.goods } ?: maWb.goods ?: ""
// 6. 件数
displayPc.value = (maWb.pc ?: 0L).toString()
// 7. 重量
displayWeight.value = (maWb.weight ?: 0.0).toString()
// 8. 体积
displayVolume.value = (maWb.volume ?: 0.0).toString()
// 9. 计费重量
displayChargeWeight.value = (dataBean.value?.chargeWeight ?: 0.0).toString()
// 10. 备注
displayRemark.value = maWb.remark ?: ""
}
/**
* 格式化交货日期String → "2025年12月03日"
*/
private fun formatDeliveryDate(opDate: String?): String {
if (opDate.isNullOrEmpty()) return ""
try {
// opDate格式: "2025-12-03 19:40:51" 或 "2025-12-03"
val datePart = opDate.split(" ")[0] // 取日期部分
val parts = datePart.split("-")
if (parts.size == 3) {
val year = parts[0]
val month = parts[1]
val day = parts[2]
return "${year}${month}${day}"
}
return ""
} catch (e: Exception) {
e.printStackTrace()
return ""
}
}
/**
* 构建航班计划:航班号/日期/目的地
*/
private fun buildFlightPlan(fno: String?, fdate: Date?, dest: String?): String {
val parts = mutableListOf<String>()
// 航班号
if (!fno.isNullOrEmpty()) {
parts.add(fno)
}
// 日期格式化为yyyy-MM-dd
if (fdate != null) {
try {
val calendar = java.util.Calendar.getInstance()
calendar.time = fdate
val year = calendar.get(java.util.Calendar.YEAR)
val month = calendar.get(java.util.Calendar.MONTH) + 1
val day = calendar.get(java.util.Calendar.DAY_OF_MONTH)
parts.add(String.format("%d-%02d-%02d", year, month, day))
} catch (e: Exception) {
e.printStackTrace()
}
}
// 目的地
if (!dest.isNullOrEmpty()) {
parts.add(dest)
}
return parts.joinToString("/")
}
/**
* 构建货单号prefix-no
*/
private fun buildWaybillNo(prefix: String?, no: String?): String {
return if (!prefix.isNullOrEmpty() && !no.isNullOrEmpty()) {
"$prefix-$no"
} else {
(prefix ?: "") + (no ?: "")
}
}
}

View File

@@ -31,6 +31,9 @@ class GjcInspectionDetailsViewModel : BaseViewModel() {
// 详情数据
val dataBean = MutableLiveData<GjcInspectionBean>()
// 退回原因(独立字段,初始为空)
val returnReason = MutableLiveData("")
/**
* 初始化数据
*/
@@ -63,7 +66,7 @@ class GjcInspectionDetailsViewModel : BaseViewModel() {
fun auditPass() {
val bean = dataBean.value ?: return
getTopActivity().showConfirmDialog("确定要通过该单证吗?") {
performAudit(bean, true, "通过")
performAudit(bean, true, "通过", "")
}
}
@@ -72,12 +75,13 @@ class GjcInspectionDetailsViewModel : BaseViewModel() {
*/
fun auditReject() {
val bean = dataBean.value ?: return
if (TextUtils.isEmpty(bean.remark)) {
showToast("请在备注中输入退回原因")
val reason = returnReason.value ?: ""
if (reason.isEmpty()) {
showToast("请输入退回原因")
return
}
getTopActivity().showConfirmDialog("确定要退回该单证吗?") {
performAudit(bean, false, "退回")
performAudit(bean, false, "退回", reason)
}
}
@@ -86,8 +90,9 @@ class GjcInspectionDetailsViewModel : BaseViewModel() {
* @param bean 数据
* @param isPass true:通过, false:退回
* @param action 操作名称(用于提示)
* @param reason 退回原因(仅退回时使用)
*/
private fun performAudit(bean: GjcInspectionBean, isPass: Boolean, action: String) {
private fun performAudit(bean: GjcInspectionBean, isPass: Boolean, action: String, reason: String) {
// 构建请求参数:数组对象,包含 maWbId、wbNo、prefix、no、reviewStatus必传
// 使用数据自身的 reviewStatus 值
val requestData = listOf(
@@ -105,7 +110,7 @@ class GjcInspectionDetailsViewModel : BaseViewModel() {
if (isPass) {
NetApply.api.passGjcInspection(requestData)
} else {
NetApply.api.backGjcInspection(bean.remark, requestData)
NetApply.api.backGjcInspection(reason, requestData)
}
}) {
onSuccess = {

View File

@@ -5,6 +5,7 @@ import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.GjcInspectionRejectDialogModel
import com.lukouguoji.gjc.holder.GjcInspectionViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.GjcInspectionBean
@@ -157,7 +158,7 @@ class GjcInspectionViewModel : BasePageViewModel() {
return
}
getTopActivity().showConfirmDialog("确定要通过选中的 ${filter.size} 条数据吗?") {
performAudit(filter, true, "通过")
performAudit(filter, true, "通过", "")
}
}
@@ -167,13 +168,25 @@ class GjcInspectionViewModel : BasePageViewModel() {
fun auditRejectClick() {
val list = pageModel.rv!!.commonAdapter()!!.items as List<GjcInspectionBean>
val filter = list.filter { it.checked.get() }
// 验证是否选择了数据
if (filter.isEmpty()) {
showToast("请选择数据")
return
}
getTopActivity().showConfirmDialog("确定要退回选中的 ${filter.size} 条数据吗?") {
performAudit(filter, false, "退回")
// 验证只能选择一个单据
if (filter.size > 1) {
showToast("退回时只能选择一个单据")
return
}
// 弹出退回原因对话框
val dialog = GjcInspectionRejectDialogModel { reason ->
// 用户填写完退回原因后,执行退回操作
performAudit(filter, false, "退回", reason)
}
dialog.show()
}
/**
@@ -181,8 +194,9 @@ class GjcInspectionViewModel : BasePageViewModel() {
* @param items 选中的数据列表
* @param isPass true:通过, false:退回
* @param action 操作名称(用于提示)
* @param reason 退回原因(仅退回时使用)
*/
private fun performAudit(items: List<GjcInspectionBean>, isPass: Boolean, action: String) {
private fun performAudit(items: List<GjcInspectionBean>, isPass: Boolean, action: String, reason: String) {
// 构建请求参数:数组对象,包含 maWbId、wbNo、prefix、no、reviewStatus必传
// 使用数据自身的 reviewStatus 值
val requestData = items.map {
@@ -200,8 +214,7 @@ class GjcInspectionViewModel : BasePageViewModel() {
if (isPass) {
NetApply.api.passGjcInspection(requestData)
} else {
// TODO: impl reason dialog
NetApply.api.backGjcInspection("test reason", requestData)
NetApply.api.backGjcInspection(reason, requestData)
}
}) {
onSuccess = {

View File

@@ -96,7 +96,7 @@ class GjcQueryDetailsViewModel : BaseViewModel() {
val prefix = maWb["prefix"] as? String ?: ""
val no = maWb["no"] as? String ?: ""
if (prefix.isNotEmpty() || no.isNotEmpty()) {
mergedData["wbNo"] = "$prefix-$no"
mergedData["wbNo"] = "$prefix$no"
}
// 字段映射: cmdStatus -> customsCommand

View File

@@ -77,7 +77,7 @@ class GjcWeighingRecordDetailsViewModel : BaseViewModel() {
waybillBean.value = it
// 提取运单信息字段
waybillNo.value = "${it.prefix}-${it.no}"
waybillNo.value = it.wbNo
prePc.value = it.pc.toString()
preWeight.value = it.weight.toString()
goodsName.value = it.goodsCn
@@ -108,6 +108,15 @@ class GjcWeighingRecordDetailsViewModel : BaseViewModel() {
launchLoadingCollect({ NetApply.api.getGjcCheckInRecordList(params) }) {
onSuccess = { result ->
val list = result.data ?: emptyList()
// 为每个记录设置数据变化回调
list.forEach { record ->
record.onDataChanged = {
// 数据变化时重新计算统计
calculateStatistics()
}
}
recordList.value = list
if (list.isEmpty()) {
@@ -136,7 +145,7 @@ class GjcWeighingRecordDetailsViewModel : BaseViewModel() {
// 计算重量误差百分比
val preWeightValue = preWeight.value?.toDoubleOrNull() ?: 0.0
val error = if (preWeightValue > 0) {
val error = if (sumWeight > 0 && preWeightValue > 0) {
((sumWeight - preWeightValue) / preWeightValue * 100)
} else {
0.0

View File

@@ -12,6 +12,8 @@ import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import com.lukouguoji.module_base.util.DictUtils
import dev.utils.app.info.KeyValue
/**
* 国际出港计重记录 ViewModel
@@ -25,6 +27,10 @@ class GjcWeighingRecordViewModel : BasePageViewModel() {
val spCode = MutableLiveData("") // 特码
val waybillNo = MutableLiveData("") // 运单号
// 下拉列表数据源
val agentList = MutableLiveData(listOf(KeyValue("全部", "")))
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
// 适配器配置
val itemViewHolder = GjcWeighingRecordViewHolder::class.java
val itemLayoutId = R.layout.item_gjc_weighing_record
@@ -39,6 +45,36 @@ class GjcWeighingRecordViewModel : BasePageViewModel() {
// 方法区
///////////////////////////////////////////////////////////////////////////
/**
* 初始化代理人列表
*/
fun initAgentList() {
launchCollect({
NetApply.api.getIntExpAgentList()
}) {
onSuccess = { result ->
val list = mutableListOf(KeyValue("全部", ""))
result.data?.forEach {
list.add(KeyValue(it.name ?: "", it.code ?: ""))
}
agentList.value = list
}
}
}
/**
* 初始化特码列表
*/
fun initSpecialCodeList() {
DictUtils.getSpecialCodeList(
flag = 1, // 国际
ieFlag = "", // 空字符串
parentcode = "" // 无父级
) {
spCodeList.value = it
}
}
/**
* 扫码输入航班号
*/

View File

@@ -7,6 +7,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.bean.GjcWeighingBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
@@ -37,8 +38,11 @@ class GjcWeighingStartViewModel : BaseViewModel() {
// 运单ID从列表页传入
var maWbId: Long = 0
// 数据Bean
val dataBean = MutableLiveData(GjcWeighingBean())
// 运单数据Bean
val maWbBean = MutableLiveData(GjcMaWb())
// 航班日期格式化为字符串用于DataBinding
val flightDate = MutableLiveData("")
// 地磅集成
val diBangModel = DiBangWeightModel()
@@ -82,6 +86,18 @@ class GjcWeighingStartViewModel : BaseViewModel() {
diBangModel.key = it ?: ""
}
// 监听运抵重量变化,自动计算运抵体积
arriveWeight.observe(activity as LifecycleOwner) { weightStr ->
// 将字符串转换为 Double如果转换失败或为空则使用 0.0
val weight = weightStr?.toDoubleOrNull() ?: 0.0
// 计算体积:运抵体积 = 运抵重量 / 220
val volume = if (weight > 0) weight / 220.0 else 0.0
// 格式化为两位小数并更新 LiveData
arriveVolume.value = String.format("%.2f", volume)
}
// 加载下拉列表数据
loadChannelList()
loadAgentList()
@@ -91,24 +107,30 @@ class GjcWeighingStartViewModel : BaseViewModel() {
// 加载运单数据
if (maWbId > 0) {
loadWeighingData()
loadRealTimeRecord() // 新增: 加载实时计重数据
}
}
/**
* 加载通道号列表
* 加载通道号列表 (国际出港专用)
*/
private fun loadChannelList() {
DictUtils.getChannelList {
DictUtils.getGjcChannelList {
channelList.value = it
}
}
/**
* 加载代理人列表
* 加载代理人列表 (国际出港专用)
*/
private fun loadAgentList() {
DictUtils.getAgentList {
agentList.value = it
launchCollect({
NetApply.api.getIntExpAgentList()
}) {
onSuccess = { result ->
val list = (result.data ?: emptyList()).map { it.toKeyValue() }
agentList.value = list
}
}
}
@@ -116,43 +138,50 @@ class GjcWeighingStartViewModel : BaseViewModel() {
* 加载特码列表
*/
private fun loadSpCodeList() {
// TODO: 从字典获取特码列表
spCodeList.value = listOf()
DictUtils.getSpecialCodeList(
flag = 1, // 国际
ieFlag = "", // 空字符串
parentcode = "" // 无父级
) {
spCodeList.value = it
}
}
/**
* 加载业务类型列表
*/
private fun loadBusinessTypeList() {
// TODO: 从字典获取业务类型列表
businessTypeList.value = listOf()
DictUtils.getBusinessTypeList(
type = "IO", // IO = 国际出港
addAll = false // 不添加"全部"选项
) {
businessTypeList.value = it
}
}
/**
* 加载运单数据
* 加载运单详情数据
*/
private fun loadWeighingData() {
val params = mapOf(
"maWbId" to maWbId
).toRequestBody()
launchLoadingCollect({ NetApply.api.getIntExpCheckInWbById(maWbId) }) {
onSuccess = { result ->
maWbBean.value = result.data ?: GjcMaWb()
// 更新航班日期字符串
flightDate.value = result.data?.fdate?.formatDate() ?: ""
}
}
}
launchCollect({
// 使用查询接口获取运单详情暂时使用列表接口传入maWbId过滤
NetApply.api.getGjcWeighingList(params)
}) {
onSuccess = {
if (it.list?.isNotEmpty() == true) {
val bean = it.list!![0]
dataBean.value = bean
// 填充可编辑字段
realTimePc.value = if (bean.pc > 0) bean.pc.toString() else ""
realTimeWeight.value = if (bean.weight > 0) bean.weight.toString() else ""
realTimeVolume.value = if (bean.volume > 0) bean.volume.toString() else ""
arrivePc.value = if (bean.arrivePc > 0) bean.arrivePc.toString() else ""
arriveWeight.value = if (bean.arriveWeight > 0) bean.arriveWeight.toString() else ""
arriveVolume.value = if (bean.arriveVolume > 0) bean.arriveVolume.toString() else ""
}
/**
* 加载实时计重数据 (仅调用一次)
*/
private fun loadRealTimeRecord() {
launchCollect({ NetApply.api.getIntExpRealTimeRecord(maWbId) }) {
onSuccess = { result ->
val record = result.data
realTimePc.value = (record?.pc ?: 0).toString()
realTimeWeight.value = String.format("%.2f", record?.weight ?: 0.0)
realTimeVolume.value = String.format("%.3f", record?.volume ?: 0.0)
}
}
}
@@ -161,11 +190,15 @@ class GjcWeighingStartViewModel : BaseViewModel() {
* 航班日期点击
*/
fun flightDateClick(view: View) {
Common.onYearMonthDay(view.context.getActivity(), dataBean.value?.fdate) { year, month, day ->
Common.onYearMonthDay(
view.context.getActivity(),
maWbBean.value?.fdate?.formatDate()
) { year, month, day ->
val calendar = Calendar.getInstance()
calendar.set(year, month - 1, day)
val date = calendar.time.formatDate()
dataBean.value = dataBean.value?.apply { fdate = date }
val date = calendar.time
maWbBean.value = maWbBean.value?.apply { fdate = date }
flightDate.value = date.formatDate()
}
}
@@ -216,32 +249,80 @@ class GjcWeighingStartViewModel : BaseViewModel() {
}
/**
* 分计重按钮点击
* 分计重按钮点击
*/
fun sortingWeighingClick() {
showToast("分拣计重功能开发中")
// TODO: 实现分拣计重功能
val bean = maWbBean.value ?: return
// 1. 验证必填字段
if (bean.no.verifyNullOrEmpty("请输入运单号")) return
if (bean.fno.verifyNullOrEmpty("请输入航班号")) return
if (channel.value.verifyNullOrEmpty("请选择通道号")) return
// 2. 收集当前表单数据,更新到 bean
bean.apply {
// 更新运抵数据(如果用户已编辑)
arrivePc = this@GjcWeighingStartViewModel.arrivePc.value?.toLongOrNull() ?: arrivePc
arriveWeight =
this@GjcWeighingStartViewModel.arriveWeight.value?.toDoubleOrNull() ?: arriveWeight
arriveVolume =
this@GjcWeighingStartViewModel.arriveVolume.value?.toDoubleOrNull() ?: arriveVolume
// 添加通道号
passageWay = this@GjcWeighingStartViewModel.channel.value
}
// 3. 构建请求数据GjcMaWb转RequestBody包含通道号
val params = bean.toRequestBody(removeEmptyOrNull = true)
// 4. 调用接口
launchLoadingCollect({
NetApply.api.splitCheckIn(params)
}) {
onSuccess = { result ->
if (result.verifySuccess()) {
showToast("分托计重成功")
// 发送刷新事件
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
// 刷新实时计重数据第5行的只读字段
loadRealTimeRecord()
// 清空表单字段,等待下一次计重
arrivePc.value = ""
arriveWeight.value = ""
arriveVolume.value = ""
maWbBean.value = maWbBean.value?.apply {
carId = null
remark = null
}
carWeight.value = "0"
} else {
showToast(result.msg.noNull("分托计重失败"))
}
}
}
}
/**
* 完成计重按钮点击
*/
fun completeCheckInClick() {
val bean = dataBean.value ?: return
val bean = maWbBean.value ?: return
// 验证必填字段
if (bean.no.verifyNullOrEmpty("请输入运单号")) return
if (bean.fno.verifyNullOrEmpty("请输入航班号")) return
if (channel.value.verifyNullOrEmpty("请选择通道号")) return
// 从编辑字段获取数值
val pc = realTimePc.value?.toLongOrNull() ?: bean.pc
val weight = realTimeWeight.value?.toDoubleOrNull() ?: bean.weight
val volume = realTimeVolume.value?.toDoubleOrNull() ?: bean.volume
val arrivePcVal = arrivePc.value?.toLongOrNull() ?: bean.arrivePc
val arriveWeightVal = arriveWeight.value?.toDoubleOrNull() ?: bean.arriveWeight
val arriveVolumeVal = arriveVolume.value?.toDoubleOrNull() ?: bean.arriveVolume
// 提交数据到接口
// 提交数据到接口(添加通道号参数)
val params = mapOf(
"maWbId" to bean.maWbId,
"no" to bean.no,
@@ -258,9 +339,9 @@ class GjcWeighingStartViewModel : BaseViewModel() {
"dest" to bean.dest,
"dest1" to bean.dest1,
"dest2" to bean.dest2,
"pc" to pc,
"weight" to weight,
"volume" to volume,
"pc" to bean.pc,
"weight" to bean.weight,
"volume" to bean.volume,
"arrivePc" to arrivePcVal,
"arriveWeight" to arriveWeightVal,
"arriveVolume" to arriveVolumeVal,
@@ -270,7 +351,8 @@ class GjcWeighingStartViewModel : BaseViewModel() {
"businessType" to bean.businessType,
"carId" to bean.carId,
"remark" to bean.remark,
"checkIn" to "1" // 收运状态设置为已收运
"checkIn" to "1", // 收运状态设置为已收运
"passageWay" to channel.value // 通道号参数
).toRequestBody(removeEmptyOrNull = true)
launchLoadingCollect({
@@ -288,6 +370,10 @@ class GjcWeighingStartViewModel : BaseViewModel() {
showToast(result.msg.noNull("计重失败"))
}
}
onFailed = { code, msg ->
showToast(msg)
}
}
}
@@ -299,13 +385,15 @@ class GjcWeighingStartViewModel : BaseViewModel() {
val content = data.getStringExtra(Constant.Result.CODED_CONTENT).noNull()
when (requestCode) {
Constant.RequestCode.WAYBILL -> {
dataBean.value = dataBean.value?.apply { no = content }
maWbBean.value = maWbBean.value?.apply { no = content }
}
Constant.RequestCode.FLIGHT_NO -> {
dataBean.value = dataBean.value?.apply { fno = content }
maWbBean.value = maWbBean.value?.apply { fno = content }
}
Constant.RequestCode.CAR -> {
dataBean.value = dataBean.value?.apply { carId = content }
maWbBean.value = maWbBean.value?.apply { carId = content }
// 查询托盘车自重
queryCarWeight(content)
}

View File

@@ -15,6 +15,8 @@ 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 com.lukouguoji.module_base.util.DictUtils
import dev.utils.app.info.KeyValue
/**
* 国际出港计重 ViewModel
@@ -28,6 +30,10 @@ class GjcWeighingViewModel : BasePageViewModel() {
val spCode = MutableLiveData("") // 特码
val waybillNo = MutableLiveData("") // 运单号
// 下拉列表数据源
val agentList = MutableLiveData(listOf(KeyValue("全部", "")))
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
// 适配器配置
val itemViewHolder = GjcWeighingViewHolder::class.java
val itemLayoutId = R.layout.item_gjc_weighing
@@ -36,12 +42,43 @@ class GjcWeighingViewModel : BasePageViewModel() {
val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
val cargoWeight = MutableLiveData("0") // 总货重
///////////////////////////////////////////////////////////////////////////
// 方法区
///////////////////////////////////////////////////////////////////////////
/**
* 初始化代理下拉列表从API获取
*/
fun initAgentList() {
launchCollect({
// 调用API获取代理人列表
NetApply.api.getIntExpAgentList()
}) {
onSuccess = { result ->
val list = mutableListOf(KeyValue("全部", ""))
// 将DictBean转换为KeyValue
result.data?.forEach {
list.add(KeyValue(it.name ?: "", it.code ?: ""))
}
agentList.value = list
}
}
}
/**
* 初始化特码下拉列表从API获取
*/
fun initSpecialCodeList() {
DictUtils.getSpecialCodeList(
flag = 1, // 国际
ieFlag = "", // 空字符串
parentcode = "" // 无父级
) {
spCodeList.value = it
}
}
/**
* 扫码输入航班号
*/
@@ -67,9 +104,7 @@ class GjcWeighingViewModel : BasePageViewModel() {
* 添加按钮点击(跳转到开始计重页面)
*/
fun addClick() {
// showToast("请从列表中选择一条待计重运单")
GjcWeighingStartActivity.startForAdd(getTopActivity(), 123)
GjcWeighingStartActivity.startForAdd(getTopActivity())
}
/**
@@ -79,6 +114,13 @@ class GjcWeighingViewModel : BasePageViewModel() {
GjcWeighingRecordListActivity.start(getTopActivity())
}
/**
* 提前运抵
*/
fun arrivedAhead() {
}
/**
* 获取列表数据
*/
@@ -121,7 +163,6 @@ class GjcWeighingViewModel : BasePageViewModel() {
totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
cargoWeight.value = (data?.cargoWeight ?: 0.0).toString()
}
}
}

View File

@@ -3,8 +3,10 @@ package com.lukouguoji.gjc.viewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.IntExpArriveDeleteDialogModel
import com.lukouguoji.gjc.holder.IntExpArriveViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.GjcDeclareParam
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
@@ -114,7 +116,46 @@ class IntExpArriveViewModel : BasePageViewModel() {
* 删除申报
*/
fun deleteDeclareClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要删除申报的记录")
return
}
// 从接口获取删除原因列表
launchLoadingCollect({ NetApply.api.getDelReasonList() }) {
onSuccess = { result ->
val changeReasonList = result.data?.map { it.toKeyValue() } ?: emptyList()
// 创建并显示弹框
val dialog = IntExpArriveDeleteDialogModel(changeReasonList) { dialogModel ->
// 弹框确认后的回调
val param = GjcDeclareParam(
dcode = dialogModel.changeReason.value,
dcontactsName = dialogModel.contactName.value,
dcontactsTel = dialogModel.contactPhone.value,
maWbList = selectedItems
)
val requestData = param.toRequestBody()
// 调用删除接口
launchLoadingCollect({ NetApply.api.deleteArriveDeclare(requestData) }) {
onSuccess = {
showToast("删除申报成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
dialog.show()
}
}
}
/**

View File

@@ -7,7 +7,15 @@ import com.lukouguoji.gjc.holder.AssemblePositionViewHolder
import com.lukouguoji.gjc.holder.AssembleWaybillViewHolder
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.*
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
import com.lukouguoji.module_base.http.net.NetApply
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 dev.utils.app.info.KeyValue
/**
* 国际出港-开始组装ViewModel静态数据
@@ -16,6 +24,14 @@ class IntExpAssembleStartViewModel : BaseViewModel() {
// ========== 搜索条件 ==========
val searchText = MutableLiveData("")
val uldSearchText = MutableLiveData("") // ULD搜索框
// ========== 组装参数(从选中运单自动提取)==========
val assembleFlightNo = MutableLiveData("") // 航班号
val assembleFlightDate = MutableLiveData("") // 航班日期
// ========== 防抖标记 ==========
private var lastQueriedAssembledParams = "" // 避免重复查询
// ========== 左侧组装信息列表 ==========
val assembleInfoList = MutableLiveData<MutableList<AssembleInfoBean>>()
@@ -27,139 +43,765 @@ class IntExpAssembleStartViewModel : BaseViewModel() {
val assemblePositionLayoutId = R.layout.item_assemble_position
val assemblePositionViewHolder = AssemblePositionViewHolder::class.java
// ========== 选中的组装位置 ==========
val selectedPosition = MutableLiveData<AssemblePositionBean?>()
// ========== 右侧运单列表 ==========
val waybillList = MutableLiveData<MutableList<AssembleWaybillBean>>()
val waybillLayoutId = R.layout.item_assemble_waybill
val waybillViewHolder = AssembleWaybillViewHolder::class.java
// ========== ULD信息 ==========
val uldInfo = MutableLiveData(UldInfoBean().apply {
uldNo = "PMC12345MU"
materialWeight = ""
uldStatus = "正常"
})
val uldInfo = MutableLiveData(UldInfoBean())
// ========== 运单信息 ==========
val waybillInfo = MutableLiveData(WaybillInfoBean().apply {
waybillNo = "78112345678"
waybillPieces = "100"
waybillWeight = "200"
assembleCount = ""
assembleWeight = ""
operator = "张三"
})
val waybillInfo = MutableLiveData(WaybillInfoBean())
// ========== 组装人列表 ==========
val assemblerList = MutableLiveData<List<KeyValue>>(emptyList())
// ========== 标记位,避免重复查询 ==========
private var lastQueriedUldNo = ""
/**
* 初始化模拟数据
* ULD编号锁定状态
*/
fun initMockData() {
// 组装信息列表(左侧)
assembleInfoList.value = mutableListOf(
AssembleInfoBean().apply {
uldNo = "PMC12345MU"
weightInfo = "100/290kg"
hasArrow = true
isOrange = false
showIndex = true
},
AssembleInfoBean().apply {
uldNo = "AKE453654CZ"
weightInfo = "100/290kg"
hasArrow = true
isOrange = false
showIndex = true
},
AssembleInfoBean().apply {
uldNo = "AKE598190CZ"
weightInfo = "100/290kg"
hasArrow = true
isOrange = false
showIndex = true
},
AssembleInfoBean().apply {
uldNo = "78112345678"
weightInfo = "100/100kg"
hasArrow = false
isOrange = true
showIndex = false
},
AssembleInfoBean().apply {
uldNo = "78112345999"
weightInfo = "150/200kg"
hasArrow = false
isOrange = true
showIndex = false
},
AssembleInfoBean().apply {
uldNo = "78112345454"
weightInfo = "120/300kg"
hasArrow = false
isOrange = true
showIndex = false
}
)
val isUldNoLocked = MutableLiveData(false)
// 组装位置列表(左侧)
assemblePositionList.value = mutableListOf(
AssemblePositionBean().apply {
positionName = "组装区001"
isSelected = true
},
AssemblePositionBean().apply {
positionName = "组装区002"
isSelected = false
},
AssemblePositionBean().apply {
positionName = "组装区003"
isSelected = false
},
AssemblePositionBean().apply {
positionName = "组装区004"
isSelected = false
}
)
// 运单列表(右侧)
waybillList.value = mutableListOf(
AssembleWaybillBean().apply {
waybillNo = "99912345678"
pieces = "25"
weight = "350.5"
isMarked = false
},
AssembleWaybillBean().apply {
waybillNo = "99912345679"
pieces = "18"
weight = "280.0"
isMarked = true // 标记为红色
},
AssembleWaybillBean().apply {
waybillNo = "99912345680"
pieces = "32"
weight = "520.8"
isMarked = false
/**
* 加载组装位置列表
*/
fun loadAssemblePosition() {
launchLoadingCollect({ NetApply.api.getDictListByLocation("GJCLOAD") }) {
onSuccess = { result ->
val list = result.data?.mapIndexed { index, dictBean ->
AssemblePositionBean().apply {
positionName = dictBean.name
isSelected = (index == 0) // 默认选中第一项
}
}?.toMutableList() ?: mutableListOf()
assemblePositionList.value = list
// 保存默认选中的第一项
if (list.isNotEmpty()) {
selectedPosition.value = list[0]
}
}
)
}
}
/**
* 组装位置点击(单选切换)
*/
fun onPositionItemClick(position: Int) {
val list = assemblePositionList.value ?: return
// 取消所有选中状态
list.forEach { it.isSelected = false }
// 选中当前项
if (position in list.indices) {
list[position].isSelected = true
selectedPosition.value = list[position]
}
// 刷新列表
assemblePositionList.value = list
// 触发组装信息列表查询
loadAssembledList()
}
/**
* 运单点击(单选切换)
*/
fun onWaybillItemClick(position: Int) {
val list = waybillList.value ?: return
// 选中新运单前,先检查是否切换了运单
val previousWaybillNo = waybillInfo.value?.waybillNo ?: ""
val selectedWaybill = if (position in list.indices) list[position] else null
val isWaybillChanged = selectedWaybill != null && previousWaybillNo.isNotEmpty()
&& selectedWaybill.waybillNo != previousWaybillNo
// 取消所有运单的选中状态
list.forEach { it.isSelected.set(false) }
// 选中当前运单
if (selectedWaybill != null) {
selectedWaybill.isSelected.set(true)
// 自动提取航班号和航班日期
assembleFlightNo.value = selectedWaybill.fno
assembleFlightDate.value = selectedWaybill.fdate
// 保存当前的组装人(始终保留)
val previousOperator = waybillInfo.value?.operator ?: ""
// 判断是否需要保留组装件数和重量
val previousAssembleCount: String
val previousAssembleWeight: String
if (isWaybillChanged) {
// 运单切换了:清空组装件数和组装重量
previousAssembleCount = ""
previousAssembleWeight = ""
// 解锁ULD编号
isUldNoLocked.value = false
} else {
// 同一个运单:保留组装件数和组装重量
previousAssembleCount = waybillInfo.value?.assembleCount ?: ""
previousAssembleWeight = waybillInfo.value?.assembleWeight ?: ""
}
// 同步运单信息到表单
waybillInfo.value = WaybillInfoBean().apply {
waybillNo = selectedWaybill.waybillNo
waybillPieces = selectedWaybill.pieces
waybillWeight = selectedWaybill.weight
assembleCount = previousAssembleCount
assembleWeight = previousAssembleWeight
operator = previousOperator
}
}
// 刷新列表
waybillList.value = list
// 清除防抖标记,强制重新查询组装信息列表
lastQueriedAssembledParams = ""
// 触发组装信息列表查询
loadAssembledList()
}
/**
* 扫码运单
*/
fun scanWaybill() {
showToast("扫码功能(静态页面暂不实现)")
ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL)
}
/**
* 加载待组装运单列表
*/
fun loadWaitingAssembleWaybills() {
val wbNo = searchText.value?.trim() ?: ""
// 验证运单号不能为空
if (wbNo.isEmpty()) {
showToast("请输入运单号")
return
}
// 发起网络请求
launchLoadingCollect({ NetApply.api.queryWaitingAssemble(wbNo) }) {
onSuccess = { result ->
// 数据转换: GjcWarehouse -> AssembleWaybillBean
val warehouseList = result.data ?: mutableListOf()
val waybillBeanList = warehouseList.map { warehouse ->
AssembleWaybillBean().apply {
waybillNo = warehouse.wbNo
pieces = warehouse.pc.toString()
weight = String.format("%.1f", warehouse.weight)
flight = warehouse.flight
fno = warehouse.fno
fdate = warehouse.fdate
whId = warehouse.whId // 添加运单ID
isMarked = false
}
}.toMutableList()
// 更新列表
waybillList.value = waybillBeanList
// 检查当前填充的运单是否在新列表中
val currentWaybillNo = waybillInfo.value?.waybillNo ?: ""
if (currentWaybillNo.isNotEmpty()) {
val existsInNewList = waybillBeanList.any { it.waybillNo == currentWaybillNo }
if (!existsInNewList) {
// 当前运单不在新列表中,清空表单
val previousOperator = waybillInfo.value?.operator ?: ""
waybillInfo.value = WaybillInfoBean().apply {
operator = previousOperator
}
}
}
// 结果反馈
if (waybillBeanList.isEmpty()) {
showToast("未找到待组装运单")
} else {
showToast("查询成功,共${waybillBeanList.size}条记录")
}
}
onFailed = { code, message ->
showToast("查询失败: $message")
waybillList.value = mutableListOf()
}
}
}
/**
* 初始化加载待组装运单列表(页面打开时调用)
*/
fun loadInitialWaitingAssemble() {
launchLoadingCollect({ NetApply.api.queryWaitingAssemble("") }) {
onSuccess = { result ->
val warehouseList = result.data ?: mutableListOf()
val waybillBeanList = warehouseList.map { warehouse ->
AssembleWaybillBean().apply {
waybillNo = warehouse.wbNo
pieces = warehouse.pc.toString()
weight = String.format("%.1f", warehouse.weight)
flight = warehouse.flight
fno = warehouse.fno
fdate = warehouse.fdate
whId = warehouse.whId // 添加运单ID
isMarked = false
}
}.toMutableList()
waybillList.value = waybillBeanList
// 检查当前填充的运单是否在新列表中
val currentWaybillNo = waybillInfo.value?.waybillNo ?: ""
if (currentWaybillNo.isNotEmpty()) {
val existsInNewList = waybillBeanList.any { it.waybillNo == currentWaybillNo }
if (!existsInNewList) {
// 当前运单不在新列表中,清空表单
val previousOperator = waybillInfo.value?.operator ?: ""
waybillInfo.value = WaybillInfoBean().apply {
operator = previousOperator
}
}
}
if (waybillBeanList.isEmpty()) {
showToast("暂无待组装运单")
}
}
onFailed = { code, message ->
showToast("加载失败: $message")
waybillList.value = mutableListOf()
}
}
}
/**
* 加载组装人列表
*/
fun loadAssemblerList() {
launchCollect({ NetApply.api.getIntExpAssemblerList() }) {
onSuccess = { result ->
val list = result.data ?: emptyList()
// 转换为 KeyValue 列表
val keyValueList = list.map { KeyValue(it, it) }
assemblerList.value = keyValueList
// 获取当前登录用户名
val currentUserName = SharedPreferenceUtil.getString(Constant.Share.userName)
// 如果当前用户名在列表中,设置为默认值;否则保持为空(显示 hint
if (currentUserName.isNotEmpty() && list.contains(currentUserName)) {
waybillInfo.value?.operator = currentUserName
waybillInfo.value = waybillInfo.value // 触发LiveData更新
}
// 注意:不匹配时不需要显式设置为空,因为初始值已经是空字符串
}
onFailed = { code, message ->
showToast("加载组装人列表失败: $message")
assemblerList.value = emptyList()
}
}
}
/**
* ULD编号输入完成时调用
*/
fun onUldNoInputComplete() {
val uld = uldInfo.value?.uldNo?.trim() ?: ""
if (uld.isNotEmpty() && uld != lastQueriedUldNo) {
lastQueriedUldNo = uld
queryUldInfo(uld)
}
}
/**
* 查询ULD信息状态和耗材重量
*/
private fun queryUldInfo(uldNo: String) {
launchCollect({ NetApply.api.getUldWithConsumeWeight(uldNo) }) {
onSuccess = { result ->
val uldBean = result.data
if (uldBean != null) {
// 更新ULD状态和耗材重量
uldInfo.value = uldInfo.value?.apply {
// status: 0-正常, 1-故障
uldStatus = when (uldBean.status) {
"0" -> "正常"
"1" -> "故障"
else -> uldBean.status ?: ""
}
// 耗材重量保持可编辑,仅在为空时填充
if (materialWeight.isEmpty()) {
materialWeight = uldBean.consumeWeight?.toString() ?: ""
}
}
}
}
onFailed = { code, message ->
showToast("查询ULD信息失败: $message")
}
}
}
/**
* 卸货按钮点击
*/
fun onUnloadClick() {
showToast("卸货操作(静态页面暂不实现)")
performAssembleOperation(isLoad = false)
}
/**
* 装货按钮点击
*/
fun onLoadClick() {
showToast("装货操作(静态页面暂不实现)")
performAssembleOperation(isLoad = true)
}
/**
* 执行组装操作(卸货或装货)
* @param isLoad true-装货false-卸货
*/
private fun performAssembleOperation(isLoad: Boolean) {
// 1. 验证必填字段
val uldNo = uldInfo.value?.uldNo?.trim() ?: ""
if (uldNo.isEmpty()) {
showToast("请输入ULD编号")
return
}
val materialWeight = uldInfo.value?.materialWeight?.trim() ?: ""
if (materialWeight.isEmpty()) {
showToast("请输入耗材重量")
return
}
val waybillNo = waybillInfo.value?.waybillNo?.trim() ?: ""
if (waybillNo.isEmpty()) {
showToast("请选择运单")
return
}
val assembleCount = waybillInfo.value?.assembleCount?.trim() ?: ""
if (assembleCount.isEmpty()) {
showToast("请输入组装件数")
return
}
val assembleWeight = waybillInfo.value?.assembleWeight?.trim() ?: ""
// 组装重量为非必填,不进行验证
val operator = waybillInfo.value?.operator?.trim() ?: ""
if (operator.isEmpty()) {
showToast("请选择组装人")
return
}
val loadArea = selectedPosition.value?.positionName?.trim() ?: ""
if (loadArea.isEmpty()) {
showToast("请选择组装位置")
return
}
// 2. 获取或构建运单Bean
// 从运单列表中获取选中的运单
val currentWaybillList = waybillList.value
if (currentWaybillList == null) {
showToast("运单列表为空")
return
}
val selectedWaybill = currentWaybillList.firstOrNull { it.isSelected.get() }
if (selectedWaybill == null) {
showToast("请选择运单")
return
}
// 3. 构建useInfoULD信息
val useInfo = mapOf(
"uld" to uldNo,
"consumeWeight" to materialWeight.toDoubleOrNull(),
"status" to when (uldInfo.value?.uldStatus) {
"正常" -> "0"
"故障" -> "1"
else -> ""
},
"loadArea" to loadArea
)
// 4. 构建wbInfo运单信息
// 使用原始运单件数/重量(如果有),否则使用当前件数/重量
val waybillPc = if (selectedWaybill.originalPieces.isNotEmpty()) {
selectedWaybill.originalPieces.toLongOrNull()
} else {
selectedWaybill.pieces.toLongOrNull()
}
val waybillWeight = if (selectedWaybill.originalWeight.isNotEmpty()) {
selectedWaybill.originalWeight.toDoubleOrNull()
} else {
selectedWaybill.weight.toDoubleOrNull()
}
val wbInfo = mapOf(
"wbNo" to selectedWaybill.waybillNo,
"pc" to waybillPc,
"weight" to waybillWeight,
"fdate" to selectedWaybill.fdate,
"fno" to selectedWaybill.fno,
"whId" to selectedWaybill.whId
)
// 5. 构建完整请求参数
val params = mapOf(
"abPc" to assembleCount.toLongOrNull(),
"abWeight" to assembleWeight.toDoubleOrNull(),
"consumeWeight" to materialWeight.toDoubleOrNull(),
"ldId" to operator,
"loadArea" to loadArea,
"useInfo" to useInfo,
"wbInfo" to wbInfo,
"userId" to SharedPreferenceUtil.getString(Constant.Share.account)
).toRequestBody()
// 6. 调用接口带Loading等待接口返回
val operationName = if (isLoad) "装货" else "卸货"
launchLoadingCollect({
if (isLoad) {
NetApply.api.assembleLoadCargo(params)
} else {
NetApply.api.assembleDropCargo(params)
}
}) {
onSuccess = { result ->
// 接口成功后才显示成功提示并刷新列表
handleOperationSuccess(operationName, isLoad, uldNo, selectedWaybill, assembleCount, assembleWeight)
}
onFailed = { code, message ->
showToast("${operationName}失败: $message")
}
}
}
/**
* 处理装货/卸货操作成功
*/
private fun handleOperationSuccess(
operationName: String,
isLoad: Boolean,
uldNo: String,
selectedWaybill: AssembleWaybillBean,
assembleCount: String,
assembleWeight: String
) {
showToast("${operationName}成功")
// 重新查询组装信息列表(刷新数据)
loadAssembledList()
// 刷新运单列表
loadInitialWaitingAssemble()
// 清空表单
clearForm()
}
/**
* 组装信息列表点击事件
* 1. 点击一级ULD行展开/折叠(按需加载运单列表)
* 2. 点击二级运单行:填充表单(编辑模式)
*/
fun onAssembleInfoItemClick(position: Int) {
val list = assembleInfoList.value ?: return
if (position !in list.indices) return
val clickedItem = list[position]
when (clickedItem.itemType) {
AssembleInfoBean.ItemType.ULD_HEADER -> {
// 一级ULD行切换展开/折叠
val newExpandState = !clickedItem.isExpanded.get()
clickedItem.isExpanded.set(newExpandState)
if (newExpandState) {
// 展开查询该ULD的运单列表
loadWaybillsByUld(position, clickedItem)
} else {
// 折叠:移除二级运单行
removeWaybillRows(position)
}
}
AssembleInfoBean.ItemType.WAYBILL_DETAIL -> {
// 二级运单行:填充表单(编辑模式)
fillFormFromWaybillDetail(clickedItem)
}
}
}
/**
* 加载指定ULD的运单列表
*/
private fun loadWaybillsByUld(uldPosition: Int, uldItem: AssembleInfoBean) {
val uldBean = uldItem.tag as? GjcUldUseBean ?: return
// 检查是否已缓存
if (uldBean.waybillDetails != null) {
// 已缓存,直接展开
insertWaybillRows(uldPosition, uldBean.waybillDetails!!)
return
}
// 未缓存,调用接口查询
val params = uldBean.toRequestBody()
launchLoadingCollect({ NetApply.api.getAssembledWaybillsByUld(params) }) {
onSuccess = { result ->
val waybillList = result.data ?: emptyList()
if (waybillList.isEmpty()) {
showToast("该ULD暂无运单记录")
// 折叠回去
uldItem.isExpanded.set(false)
} else {
// 缓存到GjcUldUseBean
uldBean.waybillDetails = waybillList.toMutableList()
// 插入二级运单行
insertWaybillRows(uldPosition, waybillList)
}
}
onFailed = { code, message ->
showToast("查询失败: $message")
// 折叠回去
uldItem.isExpanded.set(false)
}
}
}
/**
* 在指定位置后插入二级运单行
*/
private fun insertWaybillRows(uldPosition: Int, waybillList: List<GjcWarehouse>) {
val list = assembleInfoList.value?.toMutableList() ?: return
val uldItem = list[uldPosition]
// 生成二级运单行
val waybillRows = waybillList.map { warehouse ->
AssembleInfoBean().apply {
itemType = AssembleInfoBean.ItemType.WAYBILL_DETAIL
parentUldNo = uldItem.uldNo
wbNo = warehouse.wbNo
waybillPieces = warehouse.pc.toInt()
waybillWeight = warehouse.weight
showIndent = true
showIndex = false
// 转换为AssembleWaybillBean用于填充表单
waybillData = AssembleWaybillBean().apply {
waybillNo = warehouse.wbNo
pieces = warehouse.pc.toString()
weight = String.format("%.1f", warehouse.weight)
flight = warehouse.flight
fno = warehouse.fno
fdate = warehouse.fdate
whId = warehouse.whId
}
}
}
// 插入到ULD行后面
list.addAll(uldPosition + 1, waybillRows)
assembleInfoList.value = list
}
/**
* 移除指定ULD后的二级运单行
*/
private fun removeWaybillRows(uldPosition: Int) {
val list = assembleInfoList.value?.toMutableList() ?: return
val uldItem = list[uldPosition]
// 移除该ULD的所有二级行
list.removeAll {
it.itemType == AssembleInfoBean.ItemType.WAYBILL_DETAIL &&
it.parentUldNo == uldItem.uldNo
}
assembleInfoList.value = list
}
/**
* 从二级运单行填充表单(编辑模式)
* 1. 填充ULD信息并锁定ULD编号
* 2. 填充运单信息(使用原始运单件数/重量,只读)
* 3. 保留组装件数、组装重量、组装人为可编辑
*/
private fun fillFormFromWaybillDetail(item: AssembleInfoBean) {
val waybill = item.waybillData ?: return
// 1. 填充ULD信息
uldInfo.value = uldInfo.value?.apply {
uldNo = item.parentUldNo
// 耗材重量、ULD状态保持不变
}
// 保存当前的组装人(在创建新对象前)
val previousOperator = waybillInfo.value?.operator ?: ""
// 2. 填充运单信息
waybillInfo.value = WaybillInfoBean().apply {
waybillNo = waybill.waybillNo
waybillPieces = waybill.originalPieces // 使用原始运单件数
waybillWeight = waybill.originalWeight // 使用原始运单重量
// 填充已累积的组装件数和组装重量(可编辑)
assembleCount = waybill.pieces
assembleWeight = waybill.weight
operator = previousOperator // 保留之前选择的组装人
}
// 3. 锁定ULD编号
isUldNoLocked.value = true
// 4. 查询ULD信息如果需要
if (item.parentUldNo != lastQueriedUldNo) {
lastQueriedUldNo = item.parentUldNo
queryUldInfo(item.parentUldNo)
}
}
/**
* 查询已组装的ULD列表
* 参数来源:
* - fno/fdate从当前选中的运单自动提取
* - loadArea从当前选中的组装位置获取
* - uld从ULD搜索框获取可选
*/
fun loadAssembledList() {
// 1. 参数验证
val fno = assembleFlightNo.value ?: ""
val fdate = assembleFlightDate.value ?: ""
val loadArea = selectedPosition.value?.positionName ?: ""
val uldSearch = uldSearchText.value ?: ""
// 必填参数检查
if (fno.isEmpty() || fdate.isEmpty() || loadArea.isEmpty()) {
// 参数缺失,清空列表(静默处理)
assembleInfoList.value = mutableListOf()
return
}
// 2. 防抖检查(避免重复查询)
val currentParams = "$fno|$fdate|$loadArea|$uldSearch"
if (currentParams == lastQueriedAssembledParams) {
return
}
lastQueriedAssembledParams = currentParams
// 3. 构建请求参数
val params = mapOf(
"fno" to fno,
"fdate" to fdate,
"loadArea" to loadArea,
"uld" to uldSearch.ifEmpty { null } // 空值时传null
).toRequestBody()
// 4. 调用接口
launchLoadingCollect({ NetApply.api.getAssembledList(params) }) {
onSuccess = { result ->
val uldList = result.data ?: emptyList()
if (uldList.isEmpty()) {
showToast("暂无已组装记录")
assembleInfoList.value = mutableListOf()
} else {
// 转换为AssembleInfoBean列表
convertToAssembleInfoBeans(uldList)
}
}
onFailed = { code, message ->
showToast("查询失败: $message")
assembleInfoList.value = mutableListOf()
}
}
}
/**
* 数据转换: List<GjcAssembled> → List<AssembleInfoBean>
* 只生成一级ULD行不包含二级运单行
* 同时将运单列表缓存到uldBean.waybillDetails
*/
private fun convertToAssembleInfoBeans(assembledList: List<GjcAssembled>) {
val infoList = assembledList.mapIndexed { index, assembled ->
val uldBean = assembled.uldUse
val warehouseList = assembled.warehouseList
if (uldBean == null) {
return@mapIndexed null
}
// 缓存运单列表到uldBean展开时不需要再次查询
if (warehouseList != null && warehouseList.isNotEmpty()) {
uldBean.waybillDetails = warehouseList
}
// 计算总件数和总重量(从运单列表求和)
val calculatedPieces = warehouseList?.sumOf { it.pc.toInt() } ?: 0
val calculatedWeight = warehouseList?.sumOf { it.weight } ?: 0.0
AssembleInfoBean().apply {
itemType = AssembleInfoBean.ItemType.ULD_HEADER
uldNo = uldBean.uld
uldIndex = index + 1
// 使用计算的总件数和总重量
totalPieces = calculatedPieces
totalWeight = calculatedWeight
hasArrow = true
showIndex = true
isExpanded.set(false) // 默认折叠
// 关联原始ULD数据用于点击展开时查询
tag = uldBean // 使用tag存储GjcUldUseBean对象
}
}.filterNotNull().toMutableList()
assembleInfoList.value = infoList
}
/**
* ULD搜索框输入完成回调
*/
fun onUldSearchInputComplete() {
loadAssembledList()
}
/**
* 清空表单并退出编辑模式
*/
private fun clearForm() {
// 保留组装人的值(用户期望保留上一次的选择)
val previousOperator = waybillInfo.value?.operator ?: ""
waybillInfo.value = WaybillInfoBean().apply {
operator = previousOperator // 恢复组装人
}
isUldNoLocked.value = false
}
}

View File

@@ -39,6 +39,7 @@ class IntExpAssembleViewModel : BasePageViewModel() {
)
)
val assembler = MutableLiveData("") // 组装人
val assemblerList = MutableLiveData<List<KeyValue>>(emptyList()) // 组装人列表
// ========== 适配器配置 ==========
val itemViewHolder = IntExpAssembleViewHolder::class.java
@@ -49,6 +50,21 @@ class IntExpAssembleViewModel : BasePageViewModel() {
val totalPieces = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
/**
* 初始化组装人下拉列表
*/
fun initAssemblerList() {
launchCollect({ NetApply.api.getIntExpAssemblerList() }) {
onSuccess = { result ->
val list = mutableListOf<KeyValue>()
result.data?.forEach { name ->
list.add(KeyValue(name, name))
}
assemblerList.value = list
}
}
}
/**
* 搜索按钮点击
*/

View File

@@ -0,0 +1,230 @@
package com.lukouguoji.gjc.viewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.IntExpLoadDeleteDialogModel
import com.lukouguoji.gjc.holder.IntExpLoadViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.GjcCheckInPage
import com.lukouguoji.module_base.bean.GjcDeclareParam
import com.lukouguoji.module_base.bean.GjcExportLoad
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 dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/**
* 国际出港-出港装载 ViewModel
*/
class IntExpLoadViewModel : 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<GjcExportLoad> ?: return@observeForever
list.forEach { it.checked.set(checked) }
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
}
// ========== 适配器配置 ==========
val itemViewHolder = IntExpLoadViewHolder::class.java
val itemLayoutId = R.layout.item_int_exp_load
/**
* 搜索按钮点击
*/
fun searchClick() {
refresh()
}
/**
* 全选按钮点击 (切换全选状态)
*/
fun checkAllClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcExportLoad> ?: 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<GjcExportLoad> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要重置的记录")
return
}
val param = GjcDeclareParam(loadList = selectedItems)
val requestData = param.toRequestBody()
launchLoadingCollect({ NetApply.api.resetDeclare(requestData) }) {
onSuccess = {
showToast("状态重置成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
/**
* 装载申报 (批量操作)
*/
fun declareLoad() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcExportLoad> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要申报的记录")
return
}
val param = GjcDeclareParam(loadList = selectedItems)
val requestData = param.toRequestBody()
launchLoadingCollect({ NetApply.api.declareLoad(requestData) }) {
onSuccess = {
showToast("装载申报成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
/**
* 删除申报 (批量操作)
*/
fun deleteLoad() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcExportLoad> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要删除申报的记录")
return
}
// 从接口获取删除原因列表
launchLoadingCollect({ NetApply.api.getDelReasonList() }) {
onSuccess = { result ->
val changeReasonList = result.data?.map { it.toKeyValue() } ?: emptyList()
// 创建并显示弹框
val dialog = IntExpLoadDeleteDialogModel(changeReasonList) { dialogModel ->
// 弹框确认后的回调
val param = GjcDeclareParam(
dcode = dialogModel.changeReason.value,
dcontactsName = dialogModel.contactName.value,
dcontactsTel = dialogModel.contactPhone.value,
loadList = selectedItems
)
val requestData = param.toRequestBody()
// 调用删除接口
launchLoadingCollect({ NetApply.api.deleteLoadDeclare(requestData) }) {
onSuccess = {
showToast("删除申报成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
dialog.show()
}
}
}
/**
* 获取数据 (重写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.getIntExpLoadList(listParams) }) {
onSuccess = { pageModel.handleListBean(it) }
}
// 获取统计信息 (后台请求,不阻塞列表)
launchCollect({ NetApply.api.getIntExpLoadTotal(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()
}
}
}
}

View File

@@ -32,7 +32,6 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
// ========== 统计信息 ==========
val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量
// ========== 全选状态 ==========
@@ -135,7 +134,6 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
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()
}
}

View File

@@ -0,0 +1,227 @@
package com.lukouguoji.gjc.viewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.IntExpTallyDeleteDialogModel
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.GjcDeclareParam
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<GjcMaWb> ?: 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<GjcMaWb> ?: 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<GjcMaWb> ?: 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<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
/**
* 理货申报 (批量操作)
*/
fun declareTally() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: 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<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
/**
* 删除申报 (批量操作)
*/
fun deleteTally() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要删除申报的记录")
return
}
// 从接口获取删除原因列表
launchLoadingCollect({ NetApply.api.getDelReasonList() }) {
onSuccess = { result ->
val changeReasonList = result.data?.map { it.toKeyValue() } ?: emptyList()
// 创建并显示弹框
val dialog = IntExpTallyDeleteDialogModel(changeReasonList) { dialogModel ->
// 弹框确认后的回调
val param = GjcDeclareParam(
dcode = dialogModel.changeReason.value,
dcontactsName = dialogModel.contactName.value,
dcontactsTel = dialogModel.contactPhone.value,
maWbList = selectedItems
)
val requestData = param.toRequestBody()
// 调用删除接口
launchLoadingCollect({ NetApply.api.deleteTallyDeclare(requestData) }) {
onSuccess = {
showToast("删除申报成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
dialog.show()
}
}
}
/**
* 获取数据 (重写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()
}
}
}
}

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#7FD16E" />
<solid android:color="#ebfcd0" />
<size
android:width="40dp"
android:height="40dp" />
android:width="32dp"
android:height="32dp" />
</shape>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#699cf8" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -79,13 +79,16 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1">
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
@@ -159,26 +162,6 @@
android:textStyle="bold"
tools:text="合计1票" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="16sp"
android:textStyle="bold"
tools:text="总件数100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总重量:"+viewModel.totalWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="16sp"
android:textStyle="bold"
tools:text="总重量100" />
</LinearLayout>
<!-- 分配按钮 -->

View File

@@ -81,25 +81,29 @@
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.uld}" />
<!-- 搜索按钮 -->
<!-- 搜索和添加按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 添加按钮 -->
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginLeft="15dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.addClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
</LinearLayout>
@@ -169,16 +173,6 @@
android:textStyle="bold"
tools:text="总重量100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总货重:"+viewModel.cargoWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold"
tools:text="总货重150" />
</LinearLayout>
<!-- 挂签打印按钮 -->

View File

@@ -57,11 +57,13 @@
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/carIdInput"
hint='@{"请输入架子车号"}'
setRefreshCallBack="@{viewModel::onCarIdInputComplete}"
title='@{"架子车号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.carId}'
value='@={viewModel.carId}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -88,16 +90,19 @@
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/uldNoInput"
hint='@{"请输入ULD编号"}'
setRefreshCallBack="@{viewModel::onUldNoInputComplete}"
title='@{"ULD编号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.uld}'
value='@={viewModel.uldNo}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/impCodeInput"
hint='@{"请输入IMP代码"}'
title='@{"IMP代码"}'
titleLength="@{5}"
@@ -123,12 +128,12 @@
<!-- 黄色标题栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_height="36dp"
android:background="@drawable/bg_shouyun_dbcz"
android:gravity="center"
android:text="地磅称重"
android:textColor="@color/black"
android:textSize="20sp"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 青色重量显示区域 -->
@@ -136,16 +141,20 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_shouyun_dbzl"
android:minHeight="150dp"
android:padding="8dp">
android:minHeight="60dp">
<TextView
android:id="@+id/tvWeight"
<EditText
android:id="@+id/etWeight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:text="@{viewModel.totalWeight}"
android:background="@null"
android:gravity="center"
android:hint="0"
android:inputType="numberDecimal"
android:text="@={viewModel.diBangWeight}"
android:textColor="@color/text_red"
android:textColorHint="@color/text_red"
android:textSize="45sp"
android:textStyle="bold"
tools:text="1655" />
@@ -153,9 +162,9 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/tvWeight"
android:layout_alignBaseline="@id/etWeight"
android:layout_marginStart="8dp"
android:layout_toEndOf="@id/tvWeight"
android:layout_toEndOf="@id/etWeight"
android:text="kg"
android:textColor="@color/text_red"
android:textSize="24sp"
@@ -196,11 +205,10 @@
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
title='@{"总重"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.totalWeight}'
value='@={viewModel.totalWeight}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -299,20 +307,23 @@
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
setRefreshCallBack="@{viewModel::onFlightDateInputComplete}"
title='@{"航班日期"}'
titleLength="@{5}"
type="@{DataLayoutType.DATE}"
value='@={viewModel.dataBean.fdate}'
value='@={viewModel.flightDate}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/flightNoInput"
hint='@{"请输入航班号"}'
setRefreshCallBack="@{viewModel::onFlightNoInputComplete}"
title='@{"航班号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.fno}'
value='@={viewModel.flightNo}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -379,7 +390,7 @@
<CheckBox
android:id="@+id/cbPrint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:layout_marginEnd="32dp"
android:layout_toStartOf="@+id/btnReset"

View File

@@ -199,10 +199,10 @@
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
title='@{"航班日期"}'
title='@{"航班信息"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fdate}'
value='@{(viewModel.dataBean.fdate != null &amp;&amp; viewModel.dataBean.fdate.length() >= 10 ? viewModel.dataBean.fdate.substring(0, 10).replace(`-`, ``) : ``) + (viewModel.dataBean.fno != null &amp;&amp; !viewModel.dataBean.fno.isEmpty() ? `/` + viewModel.dataBean.fno : ``)}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />

View File

@@ -5,6 +5,8 @@
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.GjcHandoverViewModel" />
@@ -27,8 +29,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
@@ -77,6 +79,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayAgentName}"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -96,7 +99,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="2025 年 12月 20 日"
android:text="@{viewModel.displayDeliveryDate}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -123,6 +126,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.dataBean.saleAgentCode ?? ``}"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -134,7 +138,7 @@
android:gravity="center"
android:text="计划班期(航班号/日期/目的地)"
android:textColor="@color/color_33"
android:textSize="14sp" />
android:textSize="13sp" />
<TextView
android:layout_width="0dp"
@@ -142,6 +146,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayFlightPlan}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -168,6 +173,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayAgentName}"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -187,6 +193,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayWaybillNo}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -213,6 +220,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayPc}"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -232,6 +240,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayWeight}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -248,7 +257,7 @@
android:layout_weight="1"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="计重量"
android:text="计重量"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -258,6 +267,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayChargeWeight}"
android:textColor="@color/color_33"
android:textSize="14sp" />
@@ -277,6 +287,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayVolume}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -303,6 +314,7 @@
android:layout_weight="5"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayGoods}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -329,6 +341,7 @@
android:layout_weight="5"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.displayRemark}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -365,6 +378,10 @@
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
android:checked="@{viewModel.cbEcFlag.equals(`0`)}"
android:clickable="false"
android:focusable="false"
android:text="否"
android:textSize="14sp" />
@@ -372,7 +389,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:checked="true"
android:alpha="1.0"
android:checked="@{viewModel.cbEcFlag.equals(`1`)}"
android:clickable="false"
android:focusable="false"
android:text="是"
android:textSize="14sp" />
</RadioGroup>
@@ -394,6 +414,7 @@
android:layout_weight="3"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@{viewModel.dataBean.expressName ?? ``}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -433,6 +454,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="100dp"
android:textColor="@color/color_33"
tools:text="李某某" />
</LinearLayout>
@@ -488,6 +510,7 @@
android:layout_weight="2"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@={viewModel.dataBean.opName}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -513,6 +536,7 @@
android:layout_weight="5"
android:background="@drawable/bg_table_cell"
android:gravity="center"
android:text="@={viewModel.dataBean.opCardId}"
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -586,7 +610,7 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_weight="0.8"
android:background="@drawable/bg_table_cell"
android:orientation="vertical">
@@ -616,7 +640,7 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:layout_weight="5.2"
android:orientation="vertical">
<LinearLayout
@@ -627,7 +651,7 @@
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:layout_weight="3.2"
android:background="@drawable/bg_table_cell"
android:gravity="start|center_vertical"
android:padding="5dp"
@@ -645,6 +669,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.goodsNameYes}"
android:onClick="@{() -> viewModel.onGoodsNameClick(true)}"
android:text="" />
</LinearLayout>
@@ -658,6 +684,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.goodsNameNo}"
android:onClick="@{() -> viewModel.onGoodsNameClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -670,7 +698,7 @@
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:layout_weight="3.2"
android:background="@drawable/bg_table_cell"
android:gravity="start|center_vertical"
android:padding="5dp"
@@ -688,6 +716,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.dangerYes}"
android:onClick="@{() -> viewModel.onDangerClick(true)}"
android:text="" />
</LinearLayout>
@@ -701,6 +731,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.dangerNo}"
android:onClick="@{() -> viewModel.onDangerClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -714,11 +746,11 @@
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:layout_weight="3.2"
android:background="@drawable/bg_table_cell"
android:gravity="start|center_vertical"
android:padding="5dp"
android:text="3.是否非观赏鱼类货物,或属于无“暖宝宝”且无“高锰酸钾等氧化剂类或其他类消毒剂的观赏鱼类货物"
android:text="3.是否非观赏鱼类货物,或属于无&quot;暖宝宝&quot;且无&quot;高锰酸钾等氧化剂类或其他类消毒剂&quot;的观赏鱼类货物"
android:textColor="@color/color_33"
android:textSize="13sp" />
@@ -732,6 +764,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.fishYes}"
android:onClick="@{() -> viewModel.onFishClick(true)}"
android:text="" />
</LinearLayout>
@@ -745,6 +779,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.fishNo}"
android:onClick="@{() -> viewModel.onFishClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -757,7 +793,7 @@
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:layout_weight="3.2"
android:background="@drawable/bg_table_cell"
android:gravity="start|center_vertical"
android:padding="5dp"
@@ -775,6 +811,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.packagingYes}"
android:onClick="@{() -> viewModel.onPackagingClick(true)}"
android:text="" />
</LinearLayout>
@@ -788,6 +826,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.packagingNo}"
android:onClick="@{() -> viewModel.onPackagingClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -800,7 +840,7 @@
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:layout_weight="3.2"
android:background="@drawable/bg_table_cell"
android:gravity="start|center_vertical"
android:padding="5dp"
@@ -818,6 +858,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.labelsYes}"
android:onClick="@{() -> viewModel.onLabelsClick(true)}"
android:text="" />
</LinearLayout>
@@ -831,6 +873,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.labelsNo}"
android:onClick="@{() -> viewModel.onLabelsClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -915,6 +959,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.appearanceYes}"
android:onClick="@{() -> viewModel.onAppearanceClick(true)}"
android:text="" />
</LinearLayout>
@@ -929,6 +975,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.appearanceNo}"
android:onClick="@{() -> viewModel.onAppearanceClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -962,6 +1010,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.threatYes}"
android:onClick="@{() -> viewModel.onThreatClick(true)}"
android:text="" />
</LinearLayout>
@@ -976,6 +1026,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.threatNo}"
android:onClick="@{() -> viewModel.onThreatClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -1009,6 +1061,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.highRiskYes}"
android:onClick="@{() -> viewModel.onHighRiskClick(true)}"
android:text="" />
</LinearLayout>
@@ -1023,6 +1077,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.highRiskNo}"
android:onClick="@{() -> viewModel.onHighRiskClick(false)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -1115,6 +1171,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.submitStatementYes}"
android:onClick="@{() -> viewModel.onSubmitStatementClick(1)}"
android:text="" />
</LinearLayout>
@@ -1129,6 +1187,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.submitStatementNA}"
android:onClick="@{() -> viewModel.onSubmitStatementClick(2)}"
android:text="" />
</LinearLayout>
@@ -1143,6 +1203,8 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@{viewModel.submitStatementNo}"
android:onClick="@{() -> viewModel.onSubmitStatementClick(0)}"
android:text="" />
</LinearLayout>
</LinearLayout>
@@ -1160,7 +1222,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="货站收运人员检查签字盖章:"
android:text='@{"货站收运人员检查签字盖章" + viewModel.dataBean.staOpName ?? ""}'
android:textColor="@color/color_33"
android:textSize="14sp" />
</LinearLayout>
@@ -1219,7 +1281,7 @@
android:textColor="@color/color_33"
android:textSize="14sp" />
<TextView
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -1236,7 +1298,7 @@
android:orientation="horizontal">
<TextView
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -1255,7 +1317,7 @@
android:textColor="@color/color_33"
android:textSize="14sp" />
<TextView
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"

View File

@@ -83,13 +83,16 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>

View File

@@ -297,15 +297,15 @@
</LinearLayout>
<!-- 备注 -->
<!-- 退回原因 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{true}"
inputHeight="@{80}"
title='@{"原因"}'
titleLength="@{5}"
hint=""
hint='@{"请输入退回原因"}'
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.remark}'
value='@={viewModel.returnReason}'
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp" />

View File

@@ -86,21 +86,25 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<!-- 搜索按钮 -->
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 筛选按钮 -->
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginStart="24dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.filterClick()}"
android:padding="5dp"
android:src="@drawable/img_filter" />
</LinearLayout>

View File

@@ -31,73 +31,79 @@
<!-- 航班日期 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}" />
value="@={viewModel.flightDate}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入航班号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{()-> viewModel.flightNoScanClick()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}" />
value="@={viewModel.flightNo}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 择代理 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择代理"}'
list="@{viewModel.agentList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.agentCode}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择代理"}'
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.agentCode}" />
android:layout_weight="1" />
<!-- 择特码 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择特码"}'
list="@{viewModel.spCodeList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.spCode}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择特码"}'
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.spCode}" />
android:layout_weight="1" />
<!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入运单号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{()-> viewModel.waybillNoScanClick()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.waybillNo}" />
value="@={viewModel.waybillNo}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 搜索和添加按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 添加按钮 -->
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginLeft="15dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.addClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
</LinearLayout>
@@ -113,10 +119,10 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_gjc_weighing" />
@@ -167,18 +173,15 @@
android:textStyle="bold"
tools:text="总重量100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总货重:"+viewModel.cargoWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold"
tools:text="总货重100" />
</LinearLayout>
<!-- 提前运抵按钮 -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.arrivedAhead()}"
android:text="提前运抵" />
<!-- 计重记录按钮 -->
<TextView
style="@style/tv_bottom_btn"

View File

@@ -166,15 +166,14 @@
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1dp" />
android:background="#e7e7e7"
android:layout_height="1px" />
<!-- 第二部分:计重记录列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="15dp"
android:paddingEnd="15dp"
tools:listitem="@layout/item_gjc_check_in_record" />
</LinearLayout>
@@ -227,7 +226,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`总件数:` + viewModel.totalPc}"
android:text="@{`总件数` + viewModel.totalPc}"
android:textColor="@color/text_gray"
android:textSize="16sp" />
@@ -236,7 +235,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@{`总重量:` + viewModel.totalWeight}"
android:text="@{`总重量` + viewModel.totalWeight}"
android:textColor="@color/text_gray"
android:textSize="16sp" />
@@ -245,7 +244,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@{`重量误差: ` + viewModel.weightError}"
android:text="@{`重量误差` + viewModel.weightError}"
android:textColor="@color/text_red"
android:textSize="16sp" />

View File

@@ -56,6 +56,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择代理"}'
list="@{viewModel.agentList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.agentCode}" />
@@ -65,6 +66,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择特码"}'
list="@{viewModel.spCodeList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.spCode}" />
@@ -84,12 +86,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
@@ -159,16 +164,6 @@
android:textStyle="bold"
tools:text="总重量100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总货重:"+viewModel.cargoWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold"
tools:text="总货重100" />
</LinearLayout>
<!-- 运抵申报按钮 -->

View File

@@ -11,19 +11,23 @@
type="com.lukouguoji.gjc.viewModel.GjcWeighingStartViewModel" />
</data>
<LinearLayout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
android:background="@color/color_f2">
<include layout="@layout/title_tool_bar" />
<!-- 主内容区域 -->
<ScrollView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 主内容区域 -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
@@ -36,7 +40,7 @@
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="15dp">
android:padding="8dp">
<!-- 第一部分前2行表单左侧2列+ 地磅称重(右侧) -->
<LinearLayout
@@ -59,10 +63,11 @@
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入运单号"}'
required="@{true}"
title='@{"运单号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.no}'
value='@={viewModel.maWbBean.wbNo}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -70,6 +75,7 @@
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择通道号"}'
list="@{viewModel.channelList}"
required="@{true}"
title='@{"通 道 号"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
@@ -94,7 +100,7 @@
title='@{"代 理 人"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.dataBean.agentCode}'
value='@={viewModel.maWbBean.agentCode}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -105,7 +111,7 @@
title='@{"特 码"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.dataBean.spCode}'
value='@={viewModel.maWbBean.spCode}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -126,12 +132,12 @@
<!-- 黄色标题栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_height="36dp"
android:background="@drawable/bg_shouyun_dbcz"
android:gravity="center"
android:text="地磅称重"
android:textColor="@color/black"
android:textSize="20sp"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 青色重量显示区域 -->
@@ -139,8 +145,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_shouyun_dbzl"
android:minHeight="60dp"
android:padding="8dp">
android:minHeight="60dp">
<TextView
android:id="@+id/tvWeight"
@@ -182,7 +187,7 @@
title='@{"航班日期"}'
titleLength="@{5}"
type="@{DataLayoutType.DATE}"
value='@={viewModel.dataBean.fdate}'
value='@={viewModel.flightDate}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -192,7 +197,7 @@
title='@{"航 班 号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.fno}'
value='@={viewModel.maWbBean.fno}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -203,7 +208,7 @@
title='@{"航 程"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.range}'
value='@={viewModel.maWbBean.range}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -223,7 +228,7 @@
title='@{"预配件数"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.pc)}'
value='@{String.valueOf(viewModel.maWbBean.pc)}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -233,7 +238,7 @@
title='@{"预配重量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.weight)}'
value='@{String.valueOf(viewModel.maWbBean.weight)}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -244,7 +249,7 @@
title='@{"预配体积"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.volume)}'
value='@{String.valueOf(viewModel.maWbBean.volume)}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -260,32 +265,35 @@
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
hint='@{"请输入实时件数"}'
title='@{"实时件数"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.realTimePc}'
value='@{viewModel.realTimePc}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
hint='@{"请输入实时重量"}'
title='@{"实时重量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.realTimeWeight}'
value='@{viewModel.realTimeWeight}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
hint='@{"请输入实时体积"}'
title='@{"实时体积"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.realTimeVolume}'
value='@{viewModel.realTimeVolume}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -346,7 +354,7 @@
title='@{"托盘车号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.carId}'
value='@={viewModel.maWbBean.carId}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -368,7 +376,7 @@
title='@{"业务类型"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.dataBean.businessType}'
value='@={viewModel.maWbBean.businessType}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
@@ -383,7 +391,7 @@
title='@{"备 注"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.remark}'
value='@={viewModel.maWbBean.remark}'
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp" />
@@ -428,4 +436,46 @@
</LinearLayout>
<!-- 浮动按钮组 -->
<!-- 遮罩层(点击收起) -->
<View
android:id="@+id/maskView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<!-- 子按钮1 -->
<View
android:id="@+id/subButton1"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_gravity="bottom|end"
android:layout_marginEnd="25dp"
android:layout_marginBottom="70dp"
android:background="@drawable/bg_float_button"
android:visibility="gone" />
<!-- 子按钮2 -->
<View
android:id="@+id/subButton2"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_gravity="bottom|end"
android:layout_marginEnd="70dp"
android:layout_marginBottom="25dp"
android:background="@drawable/bg_float_button"
android:visibility="gone" />
<!-- 主浮动按钮 -->
<ImageView
android:id="@+id/mainFloatButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="bottom|end"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/ic_float_button_weighing_start" />
</FrameLayout>
</layout>

View File

@@ -75,14 +75,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:background="@null"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>

View File

@@ -73,39 +73,45 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入组装人"}'
type="@{SearchLayoutType.INPUT}"
hint='@{"请选择组装人"}'
list="@{viewModel.assemblerList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.assembler}" />
<!-- 搜索按钮 -->
<!-- 操作按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<!-- 搜索按钮 -->
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 加号按钮 -->
<!-- <EFBFBD><EFBFBD><EFBFBD>按钮 -->
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.onAddClick()}"
android:src="@drawable/img_add"
android:layout_marginLeft="15dp" />
android:padding="4dp"
android:src="@drawable/img_add" />
<!-- 删除按钮 -->
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.onDeleteClick()}"
android:src="@drawable/img_delete"
android:layout_marginLeft="15dp" />
android:padding="4dp"
android:src="@drawable/img_delete" />
</LinearLayout>

View File

@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpAssembleStartViewModel" />
@@ -33,30 +38,29 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical">
<!-- 搜索框 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayoutNew
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
hint='@{"请输入搜索内容"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.searchText}" />
<!-- 组装信息和组装位置卡片 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="8dp">
android:layout_weight="3"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical">
<!-- ULD搜索框 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayoutNew
hint='@{"请输入ULD编号"}'
icon="@{@drawable/img_search}"
setRefreshCallBack="@{viewModel::onUldSearchInputComplete}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.uldSearchText}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp" />
<!-- 组装信息标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:text="组装信息"
android:textColor="@color/text_normal"
android:textSize="16sp"
@@ -74,13 +78,25 @@
android:id="@+id/rv_assemble_info"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="16dp" />
android:layout_marginHorizontal="8dp"
android:layout_marginBottom="16dp"
android:layout_weight="0.6" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_weight="2"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="8dp">
<!-- 组装位置标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:text="组装位置"
android:textColor="@color/text_normal"
android:textSize="16sp"
@@ -93,53 +109,114 @@
android:layout_marginBottom="8dp"
app:dividerColor="@color/line" />
<!-- 组装位置列表 -->
<!-- 组装位置列表 - 固定高度2/5支持滚动 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_assemble_position"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="0dp"
android:layout_marginHorizontal="8dp"
android:layout_weight="0.4" />
</LinearLayout>
</LinearLayout>
<!-- ========== 右侧区域70%========== -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:layout_weight="0.7"
android:layout_marginStart="10dp"
android:orientation="vertical">
<!-- 运单列表 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.4"
android:layout_marginBottom="8dp"
android:layout_weight="0.4"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingHorizontal="8dp">
android:orientation="vertical">
<!-- 搜索框 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayoutNew
android:id="@+id/tvWbSearch"
hint='@{"请输入运单号"}'
icon="@{@drawable/img_search}"
setOnSearchListener="@{viewModel::loadWaitingAssembleWaybills}"
setSearchIconClickListener="@{viewModel::loadWaitingAssembleWaybills}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.searchText}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
hint='@{"请输入搜索内容"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.searchText}" />
android:layout_margin="4dp" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:dividerColor="@color/line" />
<!-- 运单列表表头 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="28dp"
android:background="@color/color_f2"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="8dp">
<!-- 选择列占位 -->
<Space
android:layout_width="64dp"
android:layout_height="wrap_content"
android:gravity="center" />
<!-- 运单号 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="运单号"
android:textColor="@color/text_normal"
android:textSize="13sp" />
<!-- 件数 -->
<TextView
android:layout_width="120dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="件数"
android:textColor="@color/text_normal"
android:textSize="13sp" />
<!-- 重量 -->
<TextView
android:layout_width="120dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="重量"
android:textColor="@color/text_normal"
android:textSize="13sp" />
<!-- 配载航班 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.2"
android:gravity="center"
android:text="配载航班"
android:textColor="@color/text_normal"
android:textSize="13sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_waybill_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
android:layout_weight="1"
tools:listitem="@layout/item_assemble_waybill"/>
</LinearLayout>
<!-- ULD信息卡片 -->
@@ -173,37 +250,39 @@
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}"
android:id="@+id/uldNoInput"
enable="@{!viewModel.isUldNoLocked}"
required="@{false}"
setRefreshCallBack="@{viewModel::onUldNoInputComplete}"
title='@{"ULD编号"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.uldInfo.uldNo}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.uldInfo.uldNo}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{true}"
required="@{true}"
title='@{"耗材重量:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.uldInfo.materialWeight}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.uldInfo.materialWeight}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
required="@{false}"
title='@{"ULD状态"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.uldInfo.uldStatus}" />
value="@={viewModel.uldInfo.uldStatus}"
valueTextColor="@{viewModel.uldInfo.uldStatus.equals(`正常`) ? @color/text_green : (viewModel.uldInfo.uldStatus.equals(`故障`) ? @color/red : @color/text_normal)}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
@@ -237,37 +316,37 @@
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}"
required="@{false}"
title='@{"运单号:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.waybillNo}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.waybillInfo.waybillNo}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
required="@{false}"
title='@{"运单件数:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.waybillPieces}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.waybillInfo.waybillPieces}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}"
required="@{false}"
title='@{"运单重量:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.waybillWeight}" />
value="@={viewModel.waybillInfo.waybillWeight}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
@@ -277,37 +356,38 @@
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}"
required="@{false}"
title='@{"组装件数:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.assembleCount}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.waybillInfo.assembleCount}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{true}"
required="@{true}"
required="@{false}"
title='@{"组装重量:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.assembleWeight}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
value="@={viewModel.waybillInfo.assembleWeight}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
required="@{false}"
title='@{"操作人:"}'
title='@{"组装人:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value="@={viewModel.waybillInfo.operator}" />
type="@{DataLayoutType.SPINNER}"
hint='@{"请选择组装人"}'
list="@{viewModel.assemblerList}"
value="@={viewModel.waybillInfo.operator}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
@@ -316,8 +396,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:layout_marginTop="8dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingHorizontal="16dp">
@@ -335,7 +415,7 @@
style="@style/tv_bottom_btn"
android:layout_width="120dp"
android:layout_height="44dp"
android:layout_marginStart="8dp"
android:layout_marginStart="32dp"
android:background="@drawable/bg_red_radius_4"
android:onClick="@{() -> viewModel.onLoadClick()}"
android:text="装货"

View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpLoadViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
<!-- 标题栏 -->
<include layout="@layout/title_tool_bar" />
<!-- 搜索区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航班日期 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}" />
<!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入航班号"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}" />
<!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入运单号"}'
icon="@{@drawable/scan_code}"
setOnIconClickListener="@{(v)-> viewModel.scanWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.waybillNo}" />
<!-- 分单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入分单号"}'
icon="@{@drawable/scan_code}"
setOnIconClickListener="@{(v)-> viewModel.scanHouseWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.houseWaybillNo}" />
<!-- 搜索按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
</LinearLayout>
<!-- 列表 -->
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_load" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- 底部统计和操作按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:paddingHorizontal="15dp">
<!-- 全选按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:onClick="@{()-> viewModel.checkAllClick()}"
android:orientation="horizontal">
<ImageView
android:id="@+id/checkIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="5dp"
android:src="@drawable/img_check_all" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全选"
android:textColor="@color/color_66"
android:textSize="18sp" />
</LinearLayout>
<!-- 统计信息 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"合计:"+viewModel.totalCount+"票"}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总重量:"+viewModel.totalWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 状态重置按钮 (蓝色) -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.resetDeclare()}"
android:text="状态重置" />
<!-- 删除申报按钮 (蓝色,暂不实现) -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.deleteLoad()}"
android:text="删除申报" />
<!-- 装载申报按钮 (红色) -->
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="15dp"
android:background="@drawable/bg_red_btn_bottom"
android:gravity="center"
android:onClick="@{()-> viewModel.declareLoad()}"
android:text="装载申报"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -88,13 +88,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
</LinearLayout>

View File

@@ -73,13 +73,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
@@ -158,15 +160,6 @@
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpTallyViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
<!-- 标题栏 -->
<include layout="@layout/title_tool_bar" />
<!-- 搜索区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航班日期 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}" />
<!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入航班号"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}" />
<!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入运单号"}'
icon="@{@drawable/scan_code}"
setOnIconClickListener="@{(v)-> viewModel.scanWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.waybillNo}" />
<!-- 分单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入分单号"}'
icon="@{@drawable/scan_code}"
setOnIconClickListener="@{(v)-> viewModel.scanHouseWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.houseWaybillNo}" />
<!-- 搜索按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
</LinearLayout>
</LinearLayout>
<!-- 列表 -->
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_tally" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- 底部统计和操作按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:paddingHorizontal="15dp">
<!-- 全选按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:onClick="@{()-> viewModel.checkAllClick()}"
android:orientation="horizontal">
<ImageView
android:id="@+id/checkIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="5dp"
android:src="@drawable/img_check_all" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全选"
android:textColor="@color/color_66"
android:textSize="18sp" />
</LinearLayout>
<!-- 统计信息 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"合计:"+viewModel.totalCount+"票"}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总重量:"+viewModel.totalWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 状态重置按钮 (蓝色) -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.resetDeclare()}"
android:text="状态重置" />
<!-- 删除申报按钮 (蓝色,暂不实现) -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.deleteTally()}"
android:text="删除申报" />
<!-- 理货申报按钮 (红色) -->
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="15dp"
android:background="@drawable/bg_red_btn_bottom"
android:gravity="center"
android:onClick="@{()-> viewModel.declareTally()}"
android:text="理货申报"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,84 @@
<?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.search.layout.SearchLayoutType"/>
<variable
name="model"
type="com.lukouguoji.gjc.dialog.GjcAssembleAllocateDialogModel" />
</data>
<LinearLayout
android:layout_width="500dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_dialog_radius_10"
android:gravity="center_horizontal"
android:orientation="vertical">
<!-- 标题栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_primary_radius_top_10"
android:gravity="center"
android:text="分配人员"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 航班信息显示 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="15dp"
android:text='@{"航班:" + model.flightInfo}'
android:textColor="@color/text_normal"
android:textSize="16sp"
android:textStyle="bold" />
<!-- 分配人下拉选择 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="分配人:"
android:textSize="16sp" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="240dp"
android:layout_height="wrap_content"
type="@{SearchLayoutType.SPINNER}"
list="@{model.assembleCompanyList}"
value="@={model.allocator}" />
</LinearLayout>
<!-- 底部按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginBottom="15dp">
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.dismiss()}"
android:text="取消" />
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.onConfirmClick()}"
android:text="确定" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,73 @@
<?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"/>
<variable
name="model"
type="com.lukouguoji.gjc.dialog.GjcInspectionRejectDialogModel" />
</data>
<LinearLayout
android:layout_width="600dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_dialog_f2_radius_10"
android:gravity="center_horizontal"
android:orientation="vertical">
<!-- 标题栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_primary_radius_top_10"
android:gravity="center"
android:text="是否确认退回?"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 表单内容 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="30dp"
android:layout_marginTop="30dp"
android:orientation="vertical">
<!-- 退回原因(多行输入) -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{true}"
inputHeight="@{120}"
title='@{"原因"}'
titleLength="@{5}"
hint='@{"请输入退回原因"}'
type="@{DataLayoutType.INPUT}"
value='@={model.rejectReason}'
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 底部按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginBottom="20dp">
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.dismiss()}"
android:text="取消" />
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.onConfirmClick()}"
android:text="保存" />
</LinearLayout>
</LinearLayout>
</layout>

Some files were not shown because too many files have changed in this diff Show More