Compare commits

...

41 Commits

Author SHA1 Message Date
6c4e97945b feat: fix form 2026-03-20 15:30:12 +08:00
a663609eeb feat: input required check 2026-03-20 15:18:56 +08:00
74e9f5a827 feat: reset status dialog 2026-03-20 15:09:27 +08:00
d6f72186a3 feat: opt views 2026-03-20 12:46:52 +08:00
b2ea79512c feat: fix issues 2026-03-19 18:31:40 +08:00
8b666364ae feat: opt form 2026-03-18 22:36:05 +08:00
aac2c860c6 feat: opt ui 2026-03-18 20:54:13 +08:00
c2b5e74156 feat: opt uld mgr 2026-03-18 16:18:57 +08:00
093314d601 feat: ii visa add/edit 2026-03-17 11:38:15 +08:00
9b089d51b1 feat: 国际事故签证新增/编辑页面及列表侧滑菜单
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 11:37:26 +08:00
8ced5be7a9 feat: fix issues 2026-03-16 18:29:02 +08:00
da50aa9794 fix: 事故签证列表页新增/删除按钮间距和padding修正
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 12:53:16 +08:00
47cef6ee59 feat: 国际进港查询运单修改页面及列表侧滑菜单
- 新增运单修改页面(编辑表单:代理人/特码/包装类型/运单类型/锁定状态/备注)
- 查询列表添加侧滑"修改"按钮入口
- 详情和修改页接口传参改用 prefix+no
- 详情页和修改页移除"库位"表单项
- 仓库信息入库时间取值改为 opDate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 12:18:35 +08:00
baaa9c5615 feat: 国际进港查询详情页面(三Tab:运单/仓库/库位信息)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 11:34:20 +08:00
edb1f576b7 fix: 国际进港查询列表运单号自动查询及字段布局修正
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:59:53 +08:00
8b0043d2f5 fix: 国际进港出库列表页面优化及交互完善
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:52:42 +08:00
5ccb971c61 feat: 国际进港提取记录费用修改页面及列表侧滑菜单
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:13:45 +08:00
6278d9738d fix: 提取记录清除提货弹框改用自定义ConfirmDialogModel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:49:30 +08:00
0b25e9c68c fix: 国际进港提取记录接口路径及字段对齐后端优化
- API路径 IntImpPickUpRecord/* 修正为 IntImpPickup/*
- Bean字段名全部对齐后端schema(checkWeight→cashWeight等)
- 请求参数名修正(paymentDateStart→beginDate, pageNum→page等)
- 缴费日期起默认值设为当天
- 详情页改为携带列表数据,不再调用接口
- 运单号搜索框添加autoQuery自动查询
- 列表项布局按规范优化(箭头、列宽、completeSpace对齐)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:43:06 +08:00
a4095d6e72 fix: 国际进港仓库接口路径修复及操作逻辑优化
- API路径从 IntImpStorageUse 修正为 IntImpStorage
- 清仓/入库接口参数改为 Query + Body 分离传递
- 清仓/出库/入库支持勾选运单号全选所有库位
- 出库确认弹框改为自定义 ConfirmDialogModel
- 搜索增加清仓综合结果筛选参数

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:06:07 +08:00
d31e78ff49 feat: 国际进港理货报告四个操作按钮功能实现
实现人工放行、状态重置、删除理货、理货申报四个按钮的完整业务逻辑,
新增删除申报和状态重置弹框组件,对接后端API接口。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:44:19 +08:00
43b1b6f44f feat: opt claude conf 2026-03-13 12:25:22 +08:00
f4d5904003 feat: 国际进港理货报告详情页面
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:23:09 +08:00
4b3c31252b feat: 国际进港理货报告展开子单功能及舱单展开优化
- 理货报告列表增加展开分单功能(嵌套子列表、全选联动)
- 运单号搜索框增加自动查询(4位触发)
- 舱单/理货展开查询传递完整主单参数
- 统一空数据展示为"暂无分单数据"UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:08:29 +08:00
f61302a1f6 feat: 国际进港舱单分单新增与编辑页面
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:32:10 +08:00
a64b963d03 feat: 国际进港舱单详情页面
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:49:42 +08:00
634dd96ac6 feat: 国际进港舱单货物发放改为库位选择弹框
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:19:41 +08:00
93939ed411 feat: 国际进港舱单增删改查接口对齐及交互优化
- 新增/编辑接口切换至新路径,删除统一使用批量删除接口
- 新增模式下航班日期、航班号等字段可编辑,支持航班级联查询自动填充
- 编辑模式下从列表页传入航班日期和航班号进行回显
- 修复编辑模式标题显示错误、航班号大写限制、DATE类型hint不显示等问题

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:51:18 +08:00
06d0244e24 fix: 国际进港装机单修改库位及入库接口修正
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:06:29 +08:00
f04cf81ff2 feat: 国际进港装机单编辑页面及列表侧滑优化
- 新增装机单编辑页面(Activity/ViewModel/布局)
- 装机单列表项添加侧滑编辑按钮,点击跳转编辑页
- 修复舱单列表项侧滑按钮未覆盖展开按钮的问题
- 修复装机单列表项两行同列completeSpace不一致

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:51:22 +08:00
d31a408ddc feat: dev 2026-03-09 19:40:55 +08:00
ce080f04a7 feat: 国际进港舱单货物发放、装机单查询参数对齐及运单号自动查询
- 实现货物发放功能,对接 /IntImpManifest/putUpCargo 接口
- 装机单列表查询参数改为与父页面一致(fid + fdep)
- 修复装机单列表接口返回类型(PageInfo 无需 BaseResultBean 包装)
- 舱单和装机单页面运单号输入框支持4位以上自动查询

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:38:01 +08:00
5a9dd6f97a refactor: 国际进港舱单列表项布局优化及分单按需加载
- 主列表项从4行改为2行5列标准KV布局
- 展开按钮移入白色卡片内,始终显示
- 分单数据改为点击展开时按需加载
- 子列表列宽调整,品名支持goodsCn优先显示
- 子列表所有列加单行省略号

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:47:43 +08:00
8c774ef3a3 refactor: 国际进港舱单列表改为通过FID查询
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:48:57 +08:00
af49cf4fb6 refactor: 国际进港原始舱单主子列表改为独立选择
移除主单↔分单勾选联动,改为独立选择模式;
提取公共方法 getSelectedItems() 分别收集选中的主单和分单;
补充信息操作仅校验主单选中状态;详情页品名字段增加中文品名回退逻辑。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:33:20 +08:00
76f55597db chore: 删除.playwright-mcp并加入gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:40:25 +08:00
fada4b3231 feat: enable mcp 2026-03-09 10:33:24 +08:00
15e13e8e12 feat: 国际进港原始舱单列表页优化
- 运单号搜索支持输入4位自动查询,带航班日期和航班号额外参数
- 自动查询框架扩展extraParamsProvider,向后兼容旧业务
- 展开按钮移入白色卡片内部,统一为单卡片四圆角
- 子列表品名字段支持goodsCn为空时fallback到goods
- 子列表调整列宽,品名列加大,其余列缩小并支持省略号截断

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:32:46 +08:00
03a6e75d68 feat: 新增日志查询页面及操作日志详情页
废弃旧日志查询页面,新建日志查询列表页和操作日志详情页。
详情页包含运单信息、流转状态进度条和操作详情时间线。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:55:21 +08:00
2729e18043 refactor: 航班详情页升级为PadDataLayoutNew组件并优化布局
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:11:25 +08:00
abac0d28fa feat: 新增航班管理列表页并支持时间格式化与跨日"+1"显示
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:56:05 +08:00
159 changed files with 11007 additions and 2430 deletions

View File

@@ -69,7 +69,38 @@
"Bash(python3:*)",
"mcp__apifox__read_project_oas_ukz3j4",
"mcp__apifox__read_project_oas_ref_resources_ukz3j4",
"mcp__apifox__refresh_project_oas_ukz3j4"
"mcp__apifox__refresh_project_oas_ukz3j4",
"mcp__playwright__browser_click",
"mcp__playwright__browser_take_screenshot",
"mcp__playwright__browser_snapshot",
"Bash(/tmp/communicate_type_findings.md:*)",
"Read(//tmp/**)",
"mcp__apifox__read_project_oas_3gn3lx",
"mcp__apifox__read_project_oas_ref_resources_3gn3lx",
"mcp__apifox__refresh_project_oas_3gn3lx",
"Bash(cp \"/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/Warp 2026-03-13 09.54.13.tiff\" /tmp/screenshot.png)",
"Read(//private/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/**)",
"mcp__apifox__read_project_oas_2s2uhx",
"mcp__apifox__read_project_oas_ref_resources_2s2uhx",
"mcp__apifox__refresh_project_oas_2s2uhx",
"Bash(find /Users/kid/Development/Fusion/Projects/aerologic-app -path \"*/build\" -prune -o -type f \\\\\\( -name \"*manifest*\" -o -name \"*bean*\" \\\\\\) | grep -i \"gjj\\\\|tally\" | grep -E \"\\\\.\\(kt\\)$\" | sort)",
"mcp__apifox__read_project_oas_9otrai",
"mcp__apifox__read_project_oas_ref_resources_9otrai",
"Bash(cd:*)",
"mcp__apifox__read_project_oas_tua249",
"mcp__apifox__read_project_oas_ref_resources_tua249",
"mcp__apifox__read_project_oas_heib77",
"mcp__apifox__read_project_oas_ref_resources_heib77",
"Bash(export JAVA_HOME=\"/Applications/Android Studio.app/Contents/jbr/Contents/Home\")",
"Bash(export PATH=\"$JAVA_HOME/bin:$PATH\")",
"Read(//Library/Java/JavaVirtualMachines/**)",
"Read(//usr/local/**)",
"Read(//opt/homebrew/opt/**)",
"Bash(/Users/kid/.vfox/sdks/java/bin/java -version 2>&1)",
"Bash(export JAVA_HOME=/Users/kid/.vfox/sdks/java)",
"mcp__apifox__read_project_oas_kcl8s7",
"mcp__apifox__refresh_project_oas_kcl8s7",
"mcp__apifox__read_project_oas_ref_resources_kcl8s7"
],
"deny": [],
"ask": []

1
.gitignore vendored
View File

@@ -203,3 +203,4 @@ fabric.properties
.worktrees/
.security-key
logs/security/
.playwright-mcp/

View File

@@ -1,2 +1,2 @@
[tools]
java = "17.0.17+10-amzn"
java = "17+35-amzn"

View File

@@ -1 +1 @@
/Users/kid/.version-fox/cache/java/v-17.0.17+10-amzn/java-17.0.17+10-amzn
/Users/kid/.vfox/cache/java/v-17+35-amzn/java-17+35-amzn

View File

@@ -124,11 +124,12 @@ class XxxViewModel : BasePageViewModel() {
<LinearLayout orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 搜索区PadSearchLayout 横排 -->
<!-- 搜索区PadSearchLayout 横排 + 操作按钮(如有) -->
<LinearLayout orientation="horizontal">
<PadSearchLayout type="@{SearchLayoutType.DATE}" value="@={viewModel.flightDate}" />
<PadSearchLayout type="@{SearchLayoutType.INPUT}" value="@={viewModel.flightNo}" />
<ImageView style="@style/iv_search_action" android:onClick="@{()-> viewModel.searchClick()}" />
<!-- 如需新增/删除按钮,尺寸规范见「开发原则」工具栏图标尺寸规范 -->
</LinearLayout>
<!-- 分页列表 -->
@@ -842,6 +843,7 @@ companion object {
- 标题栏统一用 `title_tool_bar` — 禁止手动编写 Toolbar
- 优先使用 PadDataLayoutNew 和 PadSearchLayout 组件
- 在每个页面布局时,如有截图,务必尽可能还原图片上的页面设计,而不是推测假想。如有困难一律要询问,禁止自己想象
- 工具栏图标尺寸规范: `img_search` 36dp + padding 2dp`img_add` 40dp 无 padding使用 `drawable/img_add.xml` 矢量图,`drawable-xhdpi/img_add.png` 已废弃删除)
- 常用资源: `bg_white_radius_8``colorPrimary``text_normal``text_gray``color_bottom_layout`
### 环境配置

View File

@@ -306,6 +306,14 @@
android:name=".page.log.list.LogListActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userLandscape" />
<activity
android:name=".page.log.list.LogQueryActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userLandscape" />
<activity
android:name=".page.log.detail.LogDetailActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userLandscape" />
<activity
android:name=".page.transportLog.list.TransportLogActivity"
android:configChanges="orientation|keyboardHidden"
@@ -417,6 +425,20 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-进港舱单分单编辑 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpManifestSubEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-进港舱单详情 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpManifestDetailsActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-装机单(分拣理货) -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpLoadingListActivity"
@@ -424,6 +446,13 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-装机单编辑 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpLoadingListEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-理货报告 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpTallyActivity"
@@ -431,6 +460,12 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<activity
android:name="com.lukouguoji.gjj.activity.IntImpTallyDetailsActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-仓库 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpStorageUseActivity"
@@ -452,6 +487,13 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-费用修改 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpPickUpChargeEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-提取出库 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDLVActivity"
@@ -466,6 +508,20 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-查询详情 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-运单修改 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpQueryEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<!-- 国际进港-事故签证 -->
<activity
android:name="com.lukouguoji.gjj.activity.IntImpAccidentVisaActivity"
@@ -473,6 +529,12 @@
android:exported="false"
android:screenOrientation="userLandscape" />
<activity
android:name="com.lukouguoji.gjj.activity.IntImpAccidentVisaEditActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="userLandscape" />
<service android:name="com.huitao.printer.service.PrinterService" />
<service android:name="com.lukouguoji.gnc.bluetooth.service.AncillaryService" />
<service android:name="com.lukouguoji.gnc.bluetooth.service.MyService" />

View File

@@ -3,12 +3,15 @@ package com.lukouguoji.aerologic.page.flight.query.details
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.aerologic.R
import com.lukouguoji.aerologic.databinding.ActivityFlightQueryDetailsBinding
import com.lukouguoji.aerologic.databinding.ActivityGnjStashDetailsBinding
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
@Route(path = ARouterConstants.ACTIVITY_URL_FLIGHT_QUERY_DETAILS)
class FlightQueryDetailsActivity :
BaseBindingActivity<ActivityFlightQueryDetailsBinding, FlightQueryDetailsViewModel>() {

View File

@@ -9,6 +9,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.getLifecycleOwner
@Deprecated("使用 module_hangban 中的 HbQueryListActivity 替代")
class FlightQueryListActivity :
BaseBindingActivity<ActivityFlightQueryListBinding, FlightQueryListViewModel>() {
override fun layoutId() = R.layout.activity_flight_query_list

View File

@@ -0,0 +1,169 @@
package com.lukouguoji.aerologic.page.log.detail
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import com.alibaba.android.arouter.facade.annotation.Route
import com.google.gson.Gson
import com.lukouguoji.aerologic.R
import com.lukouguoji.aerologic.databinding.ActivityLogDetailBinding
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.LogBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
@Route(path = ARouterConstants.ACTIVITY_URL_LOG_DETAIL)
class LogDetailActivity : BaseBindingActivity<ActivityLogDetailBinding, LogDetailViewModel>() {
private val timelineAdapter = LogDetailTimelineAdapter()
override fun layoutId(): Int {
return R.layout.activity_log_detail
}
override fun viewModelClass(): Class<LogDetailViewModel> {
return LogDetailViewModel::class.java
}
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("操作日志详情")
binding.viewModel = viewModel
// 配置操作详情 RecyclerView垂直时间线
binding.rvTimeline.adapter = timelineAdapter
// 观察流转状态变化,程序化构建步骤进度条
viewModel.currentStepIndex.observe(this) { index ->
buildStepProgressBar(viewModel.allSteps, index)
}
viewModel.statusLogList.observe(this) { list ->
timelineAdapter.setData(list)
}
viewModel.initOnCreated(intent)
}
private fun buildStepProgressBar(steps: List<String>, currentIndex: Int) {
val container = binding.llSteps
container.removeAllViews()
val colorBlue = 0xFF1C8CF5.toInt()
val colorGray = 0xFFCCCCCC.toInt()
val colorGreen = 0xFF4CAF50.toInt()
val dotSize = dp(10)
val lineHeight = dp(2)
for (i in steps.indices) {
val isCompleted = i <= currentIndex
val isCurrent = i == currentIndex
val isFirst = i == 0
val isLast = i == steps.size - 1
// 每个步骤的根容器(等宽)
val stepLayout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER_HORIZONTAL
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
}
// 步骤名称(所有步骤统一 padding 确保高度一致)
val tvName = TextView(this).apply {
text = steps[i]
setTextSize(TypedValue.COMPLEX_UNIT_SP, 13f)
gravity = Gravity.CENTER
setPadding(dp(6), dp(2), dp(6), dp(2))
if (isCurrent) {
setBackgroundResource(R.drawable.bg_step_current_badge)
setTextColor(0xFFFFFFFF.toInt())
} else {
setTextColor(if (isCompleted) 0xFF333333.toInt() else 0xFF999999.toInt())
}
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
}
stepLayout.addView(tvName)
// 圆点和连线区域FrameLayout 叠加)
val dotLineContainer = FrameLayout(this).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, dp(20)
).apply { topMargin = dp(8) }
}
// 左半连线(从左边缘到中心,略超过中心以避免断层)
if (!isFirst) {
val lineLeft = View(this).apply {
setBackgroundColor(if (isCompleted) colorBlue else colorGray)
layoutParams = FrameLayout.LayoutParams(0, lineHeight).apply {
gravity = Gravity.CENTER_VERTICAL or Gravity.START
}
}
dotLineContainer.addView(lineLeft)
dotLineContainer.post {
lineLeft.layoutParams = FrameLayout.LayoutParams(
dotLineContainer.width / 2 + dotSize / 2, lineHeight
).apply { gravity = Gravity.CENTER_VERTICAL or Gravity.START }
}
}
// 右半连线(从中心到右边缘,略超过中心以避免断层)
if (!isLast) {
val rightLineColor = if (isCompleted && !isCurrent) colorBlue else colorGray
val lineRight = View(this).apply {
setBackgroundColor(rightLineColor)
layoutParams = FrameLayout.LayoutParams(0, lineHeight).apply {
gravity = Gravity.CENTER_VERTICAL or Gravity.END
}
}
dotLineContainer.addView(lineRight)
dotLineContainer.post {
lineRight.layoutParams = FrameLayout.LayoutParams(
dotLineContainer.width / 2 + dotSize / 2, lineHeight
).apply { gravity = Gravity.CENTER_VERTICAL or Gravity.END }
}
}
// 圆点(叠加在连线之上)
val dot = View(this).apply {
setBackgroundResource(
when {
isCurrent -> R.drawable.bg_step_dot_green
isCompleted -> R.drawable.bg_step_dot_blue
else -> R.drawable.bg_step_dot_gray
}
)
layoutParams = FrameLayout.LayoutParams(dotSize, dotSize).apply {
gravity = Gravity.CENTER
}
}
dotLineContainer.addView(dot)
stepLayout.addView(dotLineContainer)
container.addView(stepLayout)
}
}
private fun dp(value: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, value.toFloat(), resources?.displayMetrics
).toInt()
}
companion object {
@JvmStatic
fun start(context: Context, bean: LogBean) {
val starter = Intent(context, LogDetailActivity::class.java)
starter.putExtra(Constant.Key.DATA, Gson().toJson(bean))
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,76 @@
package com.lukouguoji.aerologic.page.log.detail
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.aerologic.R
class LogDetailStepAdapter : RecyclerView.Adapter<LogDetailStepAdapter.StepViewHolder>() {
private var steps: List<String> = emptyList()
private var currentIndex: Int = -1
fun setData(steps: List<String>, currentIndex: Int) {
this.steps = steps
this.currentIndex = currentIndex
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StepViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_log_step, parent, false)
return StepViewHolder(view)
}
override fun onBindViewHolder(holder: StepViewHolder, position: Int) {
val step = steps[position]
val isCompleted = position <= currentIndex
val isCurrent = position == currentIndex
val isFirst = position == 0
val isLast = position == steps.size - 1
// 步骤名称
if (isCurrent) {
holder.tvStepName.setBackgroundResource(R.drawable.bg_step_current_badge)
holder.tvStepName.setTextColor(0xFFFFFFFF.toInt())
} else {
holder.tvStepName.setBackgroundResource(0)
holder.tvStepName.setTextColor(
if (isCompleted) 0xFF333333.toInt() else 0xFF999999.toInt()
)
}
holder.tvStepName.text = step
// 圆点
holder.dotView.setBackgroundResource(
when {
isCurrent -> R.drawable.bg_step_dot_green
isCompleted -> R.drawable.bg_step_dot_blue
else -> R.drawable.bg_step_dot_gray
}
)
// 左侧连线
holder.lineLeft.visibility = if (isFirst) View.INVISIBLE else View.VISIBLE
holder.lineLeft.setBackgroundColor(
if (isCompleted) 0xFF1C8CF5.toInt() else 0xFFCCCCCC.toInt()
)
// 右侧连线
holder.lineRight.visibility = if (isLast) View.INVISIBLE else View.VISIBLE
holder.lineRight.setBackgroundColor(
if (isCompleted && position < currentIndex) 0xFF1C8CF5.toInt() else 0xFFCCCCCC.toInt()
)
}
override fun getItemCount(): Int = steps.size
class StepViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvStepName: TextView = view.findViewById(R.id.tv_step_name)
val dotView: View = view.findViewById(R.id.view_dot)
val lineLeft: View = view.findViewById(R.id.view_line_left)
val lineRight: View = view.findViewById(R.id.view_line_right)
}
}

View File

@@ -0,0 +1,56 @@
package com.lukouguoji.aerologic.page.log.detail
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.aerologic.R
import com.lukouguoji.module_base.bean.StatusLogBean
class LogDetailTimelineAdapter : RecyclerView.Adapter<LogDetailTimelineAdapter.TimelineViewHolder>() {
private var items: List<StatusLogBean> = emptyList()
fun setData(list: List<StatusLogBean>) {
items = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimelineViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_log_timeline, parent, false)
return TimelineViewHolder(view)
}
override fun onBindViewHolder(holder: TimelineViewHolder, position: Int) {
val item = items[position]
val isFirst = position == 0
val isLast = position == items.size - 1
holder.tvContent.text = item.content
holder.tvTime.text = item.opDate
// 最后一项(当前步骤)用绿色圆点
holder.dotView.setBackgroundResource(
if (isLast) R.drawable.bg_timeline_dot_green
else R.drawable.bg_timeline_dot_gray
)
// 第一项不显示顶部连线
holder.lineTop.visibility = if (isFirst) View.INVISIBLE else View.VISIBLE
// 最后一项不显示底部连线
holder.lineBottom.visibility = if (isLast) View.INVISIBLE else View.VISIBLE
}
override fun getItemCount(): Int = items.size
class TimelineViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val dotView: View = view.findViewById(R.id.view_dot)
val lineTop: View = view.findViewById(R.id.view_line_top)
val lineBottom: View = view.findViewById(R.id.view_line_bottom)
val tvContent: TextView = view.findViewById(R.id.tv_content)
val tvTime: TextView = view.findViewById(R.id.tv_time)
}
}

View File

@@ -0,0 +1,95 @@
package com.lukouguoji.aerologic.page.log.detail
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.LogBean
import com.lukouguoji.module_base.bean.StatusLogBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.toRequestBody
class LogDetailViewModel : BaseViewModel() {
val waybillNo = MutableLiveData("")
val waybillType = MutableLiveData("")
val statusLogList = MutableLiveData<List<StatusLogBean>>(emptyList())
// 流转状态步骤定义
val allSteps = listOf(
"预录入", "完成收运", "运抵申报", "海关放行",
"完成组装", "完成复磅", "装载申报", "航班关闭", "理货申报"
)
// 当前完成到哪一步(索引)
val currentStepIndex = MutableLiveData(-1)
fun initOnCreated(intent: Intent) {
val json = intent.getStringExtra(Constant.Key.DATA) ?: ""
if (json.isNotEmpty()) {
val bean = Gson().fromJson(json, LogBean::class.java)
waybillNo.value = bean.key
waybillType.value = getAwbTypeName(bean.logType)
loadStatusList(bean.key, bean.logType)
}
}
private fun loadStatusList(key: String, logType: String) {
if (key.isEmpty()) {
loadMockData()
return
}
launchCollect({
NetApply.api.getLogStatusList(
mapOf(
"key" to key,
"awbType" to logType
).toRequestBody()
)
}) {
onSuccess = {
val list = it.data ?: emptyList()
if (list.isNotEmpty()) {
statusLogList.value = list
val lastStatus = list.last().content
val index = allSteps.indexOfFirst { step ->
lastStatus.contains(step)
}
currentStepIndex.value = if (index >= 0) index else list.size - 1
} else {
loadMockData()
}
}
onFailed = { _, _ ->
loadMockData()
}
}
}
private fun loadMockData() {
// Mock 数据:模拟到"装载申报"步骤
currentStepIndex.value = 6 // "装载申报" 在 allSteps 中的索引
statusLogList.value = listOf(
StatusLogBean(content = "托书录入", opDate = "2017-04-01 12:00:00"),
StatusLogBean(content = "完成收运", opDate = "2017-04-01 12:00:00"),
StatusLogBean(content = "完成组装", opDate = "2017-04-01 12:00:00"),
StatusLogBean(content = "已复磅", opDate = "2017-04-01 12:00:00"),
StatusLogBean(content = "海关已放行", opDate = "2017-04-01 12:00:00"),
StatusLogBean(content = "装载申报", opDate = "2017-04-01 12:00:00")
)
}
private fun getAwbTypeName(logType: String): String {
return when (logType) {
"CI" -> "国内进港"
"CO" -> "国内出港"
"II" -> "国际进港"
"IO" -> "国际出港"
else -> logType
}
}
}

View File

@@ -0,0 +1,43 @@
package com.lukouguoji.aerologic.page.log.list
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.aerologic.R
import com.lukouguoji.aerologic.databinding.ActivityLogQueryBinding
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.ktx.getLifecycleOwner
import com.lukouguoji.module_base.router.ARouterConstants
@Route(path = ARouterConstants.ACTIVITY_URL_LOG_QUERY)
class LogQueryActivity : BaseBindingActivity<ActivityLogQueryBinding, LogQueryViewModel>() {
override fun layoutId(): Int {
return R.layout.activity_log_query
}
override fun viewModelClass(): Class<LogQueryViewModel> {
return LogQueryViewModel::class.java
}
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("日志查询")
binding.viewModel = viewModel
viewModel.pageModel.bindSmartRefreshLayout(
binding.srl,
binding.rv,
viewModel,
getLifecycleOwner()
)
viewModel.refresh()
}
companion object {
@JvmStatic
fun start(context: Context) {
val starter = Intent(context, LogQueryActivity::class.java)
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,18 @@
package com.lukouguoji.aerologic.page.log.list
import android.view.View
import com.lukouguoji.aerologic.databinding.ItemLogQueryBinding
import com.lukouguoji.aerologic.page.log.detail.LogDetailActivity
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.LogBean
class LogQueryViewHolder(view: View) : BaseViewHolder<LogBean, ItemLogQueryBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item)
binding.bean = bean
itemView.setOnClickListener {
bean?.let { LogDetailActivity.start(itemView.context, it) }
}
}
}

View File

@@ -0,0 +1,49 @@
package com.lukouguoji.aerologic.page.log.list
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.aerologic.R
import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.LogBean
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.toRequestBody
import dev.utils.common.DateUtils
class LogQueryViewModel : BasePageViewModel() {
val startDate = MutableLiveData(DateUtils.getCurrentTime().formatDate())
val endDate = MutableLiveData("")
val keyWord = MutableLiveData("")
val operatorId = MutableLiveData("")
val count = MutableLiveData(0)
val itemLayoutId = R.layout.item_log_query
val itemViewHolder = LogQueryViewHolder::class.java
fun searchClick() {
refresh()
}
override fun getData() {
launchLoadingCollect({
NetApply.api.getLogList(
mapOf(
"pageNum" to pageModel.page,
"pageSize" to pageModel.limit,
"startTime" to startDate.value,
"endTime" to endDate.value,
"key" to keyWord.value,
"opId" to operatorId.value,
).toRequestBody()
)
}) {
onSuccess = {
pageModel.handleListBean(it)
count.value = it.total
}
}
}
}

View File

@@ -25,6 +25,7 @@ import com.lukouguoji.aerologic.page.gnj.query.list.GnjQueryListActivity
import com.lukouguoji.aerologic.page.gnj.stash.list.GnjStashListActivity
import com.lukouguoji.aerologic.page.gnj.unload.list.GnjUnloadListActivity
import com.lukouguoji.aerologic.page.log.list.LogListActivity
import com.lukouguoji.aerologic.page.log.list.LogQueryActivity
import com.lukouguoji.aerologic.page.message.list.MessageListActivity
import com.lukouguoji.aerologic.page.telegram.list.TelegramListActivity
import com.lukouguoji.aerologic.page.test.PrintActivity
@@ -106,7 +107,9 @@ class HomeFragment : Fragment() {
if (Constant.AuthName.Flight == leftMenuTemp.id) {
// ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_HANG_BAN_QUERY)
// .navigation(activity, Constant.RequestCode.home_left_hang_ban_query)
FlightQueryListActivity.start(requireContext())
// FlightQueryListActivity.start(requireContext()) // 已废弃
ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_HB_QUERY_LIST)
.navigation()
mPosition = oldPosition
}
//货物查询
@@ -548,7 +551,7 @@ class HomeFragment : Fragment() {
}
// 日志查询
Constant.AuthName.ComprehensiveLog -> {
LogListActivity.start(requireContext())
LogQueryActivity.start(requireContext())
}
// ULD管理
Constant.AuthName.ComprehensiveUld -> {

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#4CAF50" />
<corners android:radius="4dp" />
</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="#FF1C8CF5" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke
android:width="1.5dp"
android:color="#CCCCCC" />
<solid android:color="#FFFFFF" />
</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="#4CAF50" />
</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="#CCCCCC" />
</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="#4CAF50" />
</shape>

View File

@@ -13,265 +13,268 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/backgroud_gray"
android:background="@color/color_f2"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<androidx.core.widget.NestedScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_height="0dp">
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_height="match_parent">
android:padding="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"航班日期:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fdate}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
hint='@{" "}'
title='@{"航班号:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fno}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
hint='@{" "}'
title='@{"航程:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.range}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="15dp">
<!-- 第1行航班日期、航班号、航程 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"地区类型:"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@{viewModel.dataBean.countryType}'
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
title='@{"服务类型:"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@{viewModel.dataBean.serviceType}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"经停站:"}'
titleLength="@{5}"
title='@{"航班日期"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.jtz}'
value='@{viewModel.dataBean.fdate}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
enable="@{false}"
title='@{"航班号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fno}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"航程"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.range}' />
</LinearLayout>
<!-- 第2行地区类型、服务类型、经停站 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
hint='@{" "}'
title='@{"计划起飞:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.scheduledTackOff}'
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"预计起飞:"}'
titleLength="@{5}"
title='@{"地区类型"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.estimatedTakeOff}'
value='@{viewModel.dataBean.countryType}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"实际起飞:"}'
titleLength="@{5}"
title='@{"服务类型"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.actualTakeOff}'
value='@{viewModel.dataBean.serviceType}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
enable="@{false}"
title='@{"经停站"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.jtz}' />
</LinearLayout>
<!-- 第3行计划起飞、预计起飞、实际起飞 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"计划降落:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.scheduledArrival}'
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"预计降落:"}'
titleLength="@{5}"
title='@{"计划起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.estimatedArrival}'
value='@{viewModel.dataBean.scheduledTackOff}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"实际降落:"}'
titleLength="@{5}"
title='@{"预计起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.actualArrival}'
value='@{viewModel.dataBean.estimatedTakeOff}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
enable="@{false}"
title='@{"实际起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.actualTakeOff}' />
</LinearLayout>
<!-- 第4行计划降落、预计降落、实际降落 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"飞行状态:"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@{viewModel.dataBean.portCode}'
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"航班状态:"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@{viewModel.dataBean.flightStatus}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
hint='@{" "}'
title='@{"延误原因:"}'
titleLength="@{5}"
title='@{"计划降落"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.delayFreeText}'
value='@{viewModel.dataBean.scheduledArrival}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
enable="@{false}"
title='@{"预计降落"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.estimatedArrival}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"实际降落"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.actualArrival}' />
</LinearLayout>
<!-- 第5行飞行状态、航班状态、延误原因 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
enable="@{false}"
title='@{"机号:"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.registration}'
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"机型:"}'
titleLength="@{5}"
title='@{"飞行状态"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.aircraftCode}'
value='@{viewModel.dataBean.portCode}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
android:layout_weight="1"
enable="@{false}"
hint='@{" "}'
title='@{"机位:"}'
titleLength="@{5}"
title='@{"航班状态"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.standId}'
value='@{viewModel.dataBean.flightStatus}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="1"
enable="@{false}"
title='@{"延误原因"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.delayFreeText}' />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<!-- 第6行机号、机型、机位 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#5c6890"
android:gravity="center_vertical|end"
android:paddingHorizontal="15dp">
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"机号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.registration}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"机型"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.aircraftCode}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"机位"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.standId}' />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,159 @@
<?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">
<data>
<variable
name="viewModel"
type="com.lukouguoji.aerologic.page.log.detail.LogDetailViewModel" />
</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" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp">
<!-- 运单信息 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单信息"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单号: "
android:textColor="#666666"
android:textSize="14sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.waybillNo}"
android:textColor="#333333"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单类型: "
android:textColor="#666666"
android:textSize="14sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.waybillType}"
android:textColor="#333333"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 流转状态 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="流转状态"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/ll_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal" />
</LinearLayout>
<!-- 操作详情 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="操作详情"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_timeline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:nestedScrollingEnabled="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,119 @@
<?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.aerologic.page.log.list.LogQueryViewModel" />
</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">
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期起"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.startDate}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期止"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.endDate}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入关键字"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.keyWord}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入操作员ID"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.operatorId}"
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_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_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
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_log_query" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white"
android:gravity="center_vertical"
android:paddingHorizontal="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"合计:" + viewModel.count + "条"}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold"
tools:text="合计:1条" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -32,7 +32,7 @@
value="@={viewModel.status}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="0.33" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"选择所属航司"}'
@@ -41,7 +41,7 @@
value="@={viewModel.uldSuffix}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="0.33" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入ULD编号"}'
@@ -51,7 +51,7 @@
value="@={viewModel.uldNo}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="0.33" />
<LinearLayout
android:layout_width="0dp"
@@ -69,11 +69,10 @@
android:src="@drawable/img_search" />
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.onAddClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
</LinearLayout>

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="bean"
type="com.lukouguoji.module_base.bean.LogBean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginVertical="5dp"
android:background="@drawable/bg_item"
android:orientation="vertical"
android:padding="10dp">
<!-- 第一行:关键字 | 日志类型 | 操作员 | 操作时间 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关键字 " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.key}" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="日志类型 " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.logType}" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="操作员 " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.opId}" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.3"
android:gravity="center_vertical">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="操作时间 " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.opTime}" />
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>
<!-- 第二行:操作内容 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="操作内容 " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.content}" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="4dp">
<!-- 步骤名称 -->
<TextView
android:id="@+id/tv_step_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp" />
<!-- 圆点和连线区域 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="6dp">
<!-- 左侧连线 -->
<View
android:id="@+id/view_line_left"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/view_dot"
android:layout_alignParentLeft="true"
android:background="#FF1C8CF5" />
<!-- 圆点 -->
<View
android:id="@+id/view_dot"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_centerInParent="true"
android:background="@drawable/bg_step_dot_blue" />
<!-- 右侧连线 -->
<View
android:id="@+id/view_line_right"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/view_dot"
android:layout_alignParentRight="true"
android:background="#FF1C8CF5" />
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="15dp">
<!-- 左侧:圆点 + 连线 -->
<RelativeLayout
android:layout_width="24dp"
android:layout_height="match_parent"
android:layout_marginRight="12dp">
<!-- 顶部连线 -->
<View
android:id="@+id/view_line_top"
android:layout_width="1.5dp"
android:layout_height="8dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#E0E0E0" />
<!-- 圆点 -->
<View
android:id="@+id/view_dot"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_below="@+id/view_line_top"
android:layout_centerHorizontal="true"
android:background="@drawable/bg_timeline_dot_gray" />
<!-- 底部连线 -->
<View
android:id="@+id/view_line_bottom"
android:layout_width="1.5dp"
android:layout_height="match_parent"
android:layout_below="@+id/view_dot"
android:layout_centerHorizontal="true"
android:background="#E0E0E0" />
</RelativeLayout>
<!-- 右侧:内容 + 时间 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingBottom="20dp">
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#333333"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="#999999"
android:textSize="13sp" />
</LinearLayout>
</LinearLayout>

View File

@@ -6,7 +6,17 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 \
--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
kapt.use.worker.api=false
kapt.include.compile.classpath=false
# When configured, Gradle will run in incubating parallel mode.

View File

@@ -151,6 +151,46 @@ class FlightBean : ICheck {
).noNull(scheduledTackOff)
}
// 预计起飞时间-时分
val estimatedTakeOffHM: String
get() {
return DateUtils.parseString(
estimatedTakeOff,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(estimatedTakeOff)
}
// 计划降落时间-时分
val scheduledArrivalHM: String
get() {
return DateUtils.parseString(
scheduledArrival,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(scheduledArrival)
}
// 预计降落时间-时分
val estimatedArrivalHM: String
get() {
return DateUtils.parseString(
estimatedArrival,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(estimatedArrival)
}
// 实际降落时间-时分
val actualArrivalHM: String
get() {
return DateUtils.parseString(
actualArrival,
DevFinal.TIME.yyyyMMddHHmmss_HYPHEN,
"HH:mm"
).noNull(actualArrival)
}
// 航班服务种类(0:客机;1:货机;2:卡车)
var serviceType: String = ""
@@ -219,6 +259,50 @@ class FlightBean : ICheck {
return calendar.get(Calendar.DAY_OF_YEAR) > current.get(Calendar.DAY_OF_YEAR)
}
// 预计起飞 vs 计划起飞 是否跨日
fun isEstimatedTakeOffNextDay(): Boolean {
if (scheduledTackOff.isEmpty() || estimatedTakeOff.isEmpty()) return false
return try {
val calBase = DateUtils.getCalendar(DateUtils.parseDate(scheduledTackOff))
val calTarget = DateUtils.getCalendar(DateUtils.parseDate(estimatedTakeOff))
if (calTarget.get(Calendar.YEAR) > calBase.get(Calendar.YEAR)) true
else calTarget.get(Calendar.DAY_OF_YEAR) > calBase.get(Calendar.DAY_OF_YEAR)
} catch (e: Exception) { false }
}
// 实际起飞 vs 计划起飞 是否跨日
fun isActualTakeOffNextDay(): Boolean {
if (scheduledTackOff.isEmpty() || actualTakeOff.isEmpty()) return false
return try {
val calBase = DateUtils.getCalendar(DateUtils.parseDate(scheduledTackOff))
val calTarget = DateUtils.getCalendar(DateUtils.parseDate(actualTakeOff))
if (calTarget.get(Calendar.YEAR) > calBase.get(Calendar.YEAR)) true
else calTarget.get(Calendar.DAY_OF_YEAR) > calBase.get(Calendar.DAY_OF_YEAR)
} catch (e: Exception) { false }
}
// 预计降落 vs 计划降落 是否跨日
fun isEstimatedArrivalNextDay(): Boolean {
if (scheduledArrival.isEmpty() || estimatedArrival.isEmpty()) return false
return try {
val calBase = DateUtils.getCalendar(DateUtils.parseDate(scheduledArrival))
val calTarget = DateUtils.getCalendar(DateUtils.parseDate(estimatedArrival))
if (calTarget.get(Calendar.YEAR) > calBase.get(Calendar.YEAR)) true
else calTarget.get(Calendar.DAY_OF_YEAR) > calBase.get(Calendar.DAY_OF_YEAR)
} catch (e: Exception) { false }
}
// 实际降落 vs 计划降落 是否跨日
fun isActualArrivalNextDay(): Boolean {
if (scheduledArrival.isEmpty() || actualArrival.isEmpty()) return false
return try {
val calBase = DateUtils.getCalendar(DateUtils.parseDate(scheduledArrival))
val calTarget = DateUtils.getCalendar(DateUtils.parseDate(actualArrival))
if (calTarget.get(Calendar.YEAR) > calBase.get(Calendar.YEAR)) true
else calTarget.get(Calendar.DAY_OF_YEAR) > calBase.get(Calendar.DAY_OF_YEAR)
} catch (e: Exception) { false }
}
fun getCargoTypeName(): String {
return when (cargoType) {
"0" -> "国际货"

View File

@@ -0,0 +1,26 @@
package com.lukouguoji.module_base.bean
class GjAccidentVisaEditBean {
var id: Long = 0
var fdate: String = "" // 航班日期
var fno: String = "" // 航班号
var dep: String = "" // 始发站
var dest: String = "" // 目的站
var wbNo: String = "" // 运单号
var dpc: String = "" // 不正常件数
var pc: String = "" // 运单总件数
var weight: String = "" // 运单总重量
var reweight: String = "" // 复称重量
var goods: String = "" // 品名
var opacking: String = "" // 外包装
var damage: String = "" // 包装破损情况
var condition: String = "" // 内容物情况
var problem: String = "" // 不正常类型
var seachDate: String = "" // 发现时间
var photo: String = "" // 图片是否留底
var remarks: String = "" // 备注
var pic: String = "" // 缩略图
var originalPic: String = "" // 原图
var picNumber: String = "" // 图片数量
var idFlag: String = "1" // 国际标志固定为1=国际)
}

View File

@@ -50,7 +50,11 @@ class GjjWarehouse(
var volume: String? = "",
var wbNo: String? = "",
var weight: String? = "",
var whid: String? = ""
var whid: String? = "",
var splitFlag: String? = "",
var inDate: String? = "",
var clearNormal: String? = "",
var range: String? = ""
) {
fun getWaybillCode() = "${prefix}${no}"

View File

@@ -16,6 +16,7 @@ data class GjjHaWb(
var volume: Double = 0.0,
var cashWeight: Double = 0.0,
var goods: String = "",
var goodsCn: String = "",
var spCode: String = "",
var mftStatus: String = "",
var lastMftStatus: String = "",

View File

@@ -47,10 +47,14 @@ data class GjjImportManifest(
var dgrContactMame: String = "",
// 危险品收货人通讯方式
var dgrContactNumber: String = "",
// 航班日期
var fdate: String = "",
// 航班起始站
var fdep: String = "",
// 航班目的站
var fdest: String = "",
// 航班号
var fno: String = "",
// 航班id
var fid: Long = 0,
// 运费支付方式
@@ -114,6 +118,15 @@ data class GjjImportManifest(
// 重量
var weight: Double = 0.0
) : Serializable {
// 获取航班信息(日期去横杠/航班号)
fun getFlightSplit(): String {
if (fdate != "" && fno != "") {
val (year, mon, day) = fdate.split("-")
return "${year}${mon}${day}/${fno}"
}
return ""
}
// ========== UI扩展字段 ==========
// 选中状态
@Transient

View File

@@ -74,7 +74,27 @@ data class GjjImportTally(
// 体积(m³)
var volume: Double = 0.0,
// 重量(kg)
var weight: Double = 0.0
var weight: Double = 0.0,
// 品名(中文)
var goodsCn: String = "",
// 品名(英文)
var goodsEn: String = "",
// 放行模式(代码)
var relMode: String = "",
// 放行模式(名称)
var releaseMode: String = "",
// 放行时间(perDate)
var perDate: String = "",
// 放行时间
var releaseTime: String = "",
// 指令类型(comType)
var comType: String = "",
// 指令类型
var instructionType: String = "",
// 放行备注
var relRemark: String = "",
// 备注
var remark: String = ""
) : Serializable {
// 选中状态(用于多选功能)- 不参与序列化
@Transient
@@ -85,7 +105,24 @@ data class GjjImportTally(
get() = checked.get()
set(value) = checked.set(value)
// 展开/折叠状态 - 不参与序列化
@Transient
val showMore: ObservableBoolean = ObservableBoolean(false)
// 已加载的分单数据 - 不参与序列化
@Transient
var haWbList: MutableList<GjjImportTally>? = null
// 获取完整运单号
fun getWaybillNo() = "$prefix$no"
// 获取航班信息(日期去横杠/航班号)
fun getFlightSplit(): String {
if (fdate != "" && fno != "") {
val (year, mon, day) = fdate.split("-")
return "${year}${mon}${day}/${fno}"
}
return ""
}
}

View File

@@ -0,0 +1,23 @@
package com.lukouguoji.module_base.bean
import java.io.Serializable
/**
* 国际进港-库位使用记录Bean
* 对应接口: /IntImpSearch/detail 返回的 storageUseList 项
*/
data class GjjStorageUse(
var id: Long? = null, // 主键
var maWbId: Long? = null, // 运单id
var prefix: String? = null, // 运单前缀
var no: String? = null, // 运单号
var location: String? = null, // 库位号
var locationId: Long? = null, // 库位id
var inDate: String? = null, // 入库时间
var inOpId: String? = null, // 入库人ID
var inOpName: String? = null, // 入库人姓名
var outDate: String? = null, // 出库时间
var outOpId: String? = null, // 出库人ID
var outOpName: String? = null, // 出库人姓名
var cargoStatus: String? = null // 货物状态
) : Serializable

View File

@@ -38,6 +38,8 @@ class IntImpPickUpDLVBean : Serializable {
var efrCharge: Double = 0.0 // 冷藏费
var svlCharge: Double = 0.0 // 铲车费
var tallyCharge: Double = 0.0 // 理货费
var pipFee: Double = 0.0 // 精密仪器处理费
var lapFee: Double = 0.0 // 活体动物处理费
var chargeId: String = "" // 收费员
var chargeName: String = "" // 收费员名称
var dlvId: String = ""
@@ -54,6 +56,18 @@ class IntImpPickUpDLVBean : Serializable {
var awbPc: Long = 0
// ========== UI扩展字段 ==========
/**
* 航班信息展示:优先使用 flight 字段,否则用 fdate(去杠)/fno 拼接
* 格式示例20240204/MU2023
*/
val flightInfo: String
get() {
if (!flight.isNullOrEmpty()) return flight
val dateStr = fdate?.replace("-", "")?.take(8) ?: ""
val noStr = fno ?: ""
return if (dateStr.isNotEmpty() || noStr.isNotEmpty()) "$dateStr/$noStr" else ""
}
val checked: ObservableBoolean = ObservableBoolean(false)
var isSelected: Boolean

View File

@@ -5,28 +5,35 @@ import java.io.Serializable
/**
* 国际进港提取记录-列表数据Bean
* 对应API: IntImpPickUpRecord/pageQuery
* 对应API: IntImpPickup/pageQuery
*/
class IntImpPickUpRecordBean : Serializable {
var id: Long = 0 // 主键ID
var wbNo: String = "" // 运单号
var no: String = "" // 主单号
var prefix: String = "" // 前缀
var hno: String = "" // 分单号
var serialNo: String = "" // 序号
var pc: Int = 0 // 件数
var weight: Double = 0.0 // 重量
var checkWeight: Double = 0.0 // 计重量
var cashWeight: Double = 0.0 // 计重量
var agentCode: String = "" // 代理人
var spCode: String = "" // 特码
var serviceFee: Double = 0.0 // 服务费
var storageFee: Double = 0.0 // 仓储费
var totalAmount: Double = 0.0 // 总金额
var pickUpTime: String = "" // 提取时间
var pickUpNo: String = "" // 提货编号
var infoFee: Double = 0.0 // 信息费
var drawFee: Double = 0.0 // 抽单费
var coldFee: Double = 0.0 // 冷藏费
var forkliftFee: Double = 0.0 // 铲车费
var tallyFee: Double = 0.0 // 理货费
var operator: String = "" // 办理人
var outTime: String = "" // 出库时间
var optCharge: Double = 0.0 // 服务费
var whsCharge: Double = 0.0 // 仓储费
var amount: Double = 0.0 // 总金额
var chargeTime: String = "" // 缴费时间/提取时间
var pkId: String = "" // 提货编号
var tranCharge: Double = 0.0 // 信息费
var drawBillCharge: Double = 0.0 // 抽单费
var efrCharge: Double = 0.0 // 冷藏费
var svlCharge: Double = 0.0 // 铲车费
var tallyCharge: Double = 0.0 // 理货费
var pipFee: Double = 0.0 // 精密仪器处理费
var lapFee: Double = 0.0 // 活体动物处理费
var chargeName: String = "" // 办理人名称
var chargeId: String = "" // 收费员ID
var dlvTime: String = "" // 出库时间
// ========== UI扩展字段 ==========
val checked: ObservableBoolean = ObservableBoolean(false)

View File

@@ -0,0 +1,53 @@
package com.lukouguoji.module_base.bean
/**
* 国际进港运单修改-数据模型
* 对应接口:/IntImpSearch/modifyMaWb 的请求体 (GjjMaWb)
* 详情数据来源:/IntImpSearch/detail 返回的 maWb + maWbM + warehouseList
*/
data class IntImpQueryEditBean(
// ==================== 主键 ====================
var maWbId: Long? = null, // 主单主键ID
var activeId: Long? = null, // 有效值
// ==================== 运单号(禁用) ====================
var wbNo: String? = null, // 运单号(组合: prefix + no
var prefix: String? = null, // 运单号前缀
var no: String? = null, // 运单号主体
// ==================== 可编辑字段 ====================
var agentCode: String? = null, // 代理人code提交用
var agentName: String? = null, // 代理人名称(显示用)
var spCode: String? = null, // 特码
var packageType: String? = null, // 包装类型
var awbType: String? = null, // 运单类型code
var lockState: String? = null, // 锁定状态("0":未锁, "1":锁定)
var remark: String? = null, // 备注
// ==================== 禁用字段(仅显示) ====================
var awbPc: Long? = null, // 运单件数对应API: pc
var awbWeight: Double? = null, // 运单重量对应API: weight
var businessType: String? = null, // 业务类型code
var businessName: String? = null, // 业务类型名称
var inPc: Long? = null, // 入库件数
var inWeight: Double? = null, // 入库重量
var cashWeight: Double? = null, // 计费重量
var by1: String? = null, // 承运人
var range: String? = null, // 航程
var goodsCn: String? = null, // 品名(中)
var goods: String? = null, // 品名(英)
var unNumber: String? = null, // UN编号
// ==================== 提交时需要的额外字段 ====================
var fno: String? = null, // 航班号
var fdate: String? = null, // 航班日期
var flight: String? = null, // 航班
var pc: Long? = null, // 件数API用
var weight: Double? = null, // 重量API用
var volume: Double? = null, // 体积
var origin: String? = null, // 货源地
var dest: String? = null, // 目的地
var cargoType: String? = null, // 货物类型
var subCode: String? = null, // 子码
var carId: String? = null // 车牌号
)

View File

@@ -0,0 +1,11 @@
package com.lukouguoji.module_base.bean
data class StatusLogBean(
var id: Long = 0,
var key: String = "", // 关键字(运单号)
var awbType: String = "", // 运单类型CI:国内进港,CO:国内出港,II:国际进港,IO:国际出港)
var content: String = "", // 操作内容
var opDate: String = "", // 操作时间
var opId: String = "", // 操作人
var status: String = "" // 操作环节(运单状态)
)

View File

@@ -51,6 +51,7 @@ import com.lukouguoji.module_base.bean.GjjGoodsDetailsBean
import com.lukouguoji.module_base.bean.GjjGoodsTypeBean
import com.lukouguoji.module_base.bean.GjjHandoverRecordBean
import com.lukouguoji.module_base.bean.GjjImportTally
import com.lukouguoji.module_base.bean.GjAccidentVisaEditBean
import com.lukouguoji.module_base.bean.IntImpAccidentVisaBean
import com.lukouguoji.module_base.bean.IntImpPickUpDLVBean
import com.lukouguoji.module_base.bean.IntImpPickUpRecordBean
@@ -80,6 +81,7 @@ import com.lukouguoji.module_base.bean.GnjYiKuBean
import com.lukouguoji.module_base.bean.GoodsTransportBean
import com.lukouguoji.module_base.bean.JianDataBean
import com.lukouguoji.module_base.bean.LogBean
import com.lukouguoji.module_base.bean.StatusLogBean
import com.lukouguoji.module_base.bean.ManifestTotalDto
import com.lukouguoji.module_base.bean.MessageBean
import com.lukouguoji.module_base.bean.MoveStashBean
@@ -300,6 +302,18 @@ interface Api {
@POST("typeCode/countryType")
suspend fun getAreaTypeList(): DictListBean
/**
* 获取国家代码
*/
@POST("typeCode/countryCode")
suspend fun getCountryCodeList(): DictListBean
/**
* 获取通讯方式类型
*/
@POST("typeCode/communicateType")
suspend fun getCommunicateTypeList(): DictListBean
/**
* 查询平板车信息
*/
@@ -905,73 +919,73 @@ interface Api {
/**
* 国际进港仓库-分页查询
* 接口路径: /IntImpStorageUse/pageQuery
* 接口路径: /IntImpStorage/pageQuery
*/
@POST("IntImpStorageUse/pageQuery")
@POST("IntImpStorage/pageQuery")
suspend fun getIntImpStorageUseList(@Body data: RequestBody): PageInfo<GjcMaWb>
/**
* 国际进港仓库-分页合计
* 接口路径: /IntImpStorageUse/pageQueryTotal
* 接口路径: /IntImpStorage/pageQueryTotal
*/
@POST("IntImpStorageUse/pageQueryTotal")
@POST("IntImpStorage/pageQueryTotal")
suspend fun getIntImpStorageUseTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港库位操作-清仓
* 接口路径: /IntImpStorageUse/updateClear
* 接口路径: /IntImpStorage/updateClear
*/
@POST("IntImpStorageUse/updateClear")
suspend fun clearIntImpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
@POST("IntImpStorage/updateClear")
suspend fun clearIntImpStorage(@Query("clearNormal") clearNormal: String, @Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港库位操作-修改库位
* 接口路径: /IntImpStorageUse/modifyStorage
* 接口路径: /IntImpStorage/modifyStorage
*/
@POST("IntImpStorageUse/modifyStorage")
@POST("IntImpStorage/modifyStorage")
suspend fun modifyIntImpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港库位操作-出库
* 接口路径: /IntImpStorageUse/outStorage
* 接口路径: /IntImpStorage/outStorage
*/
@POST("IntImpStorageUse/outStorage")
@POST("IntImpStorage/outStorage")
suspend fun outIntImpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港库位操作-入库
* 接口路径: /IntImpStorageUse/inStorage
* 接口路径: /IntImpStorage/inStorage
*/
@POST("IntImpStorageUse/inStorage")
suspend fun inIntImpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
@POST("IntImpStorage/inStorage")
suspend fun inIntImpStorage(@Query("location") location: String, @Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港提取记录-分页查询
* 接口路径: /IntImpPickUpRecord/pageQuery
* 接口路径: /IntImpPickup/pageQuery
*/
@POST("IntImpPickUpRecord/pageQuery")
@POST("IntImpPickup/pageQuery")
suspend fun getIntImpPickUpRecordList(@Body data: RequestBody): PageInfo<IntImpPickUpRecordBean>
/**
* 国际进港提取记录-分页合计
* 接口路径: /IntImpPickUpRecord/pageQueryTotal
* 接口路径: /IntImpPickup/pageQueryTotal
*/
@POST("IntImpPickUpRecord/pageQueryTotal")
@POST("IntImpPickup/pageQueryTotal")
suspend fun getIntImpPickUpRecordTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港提取记录-清除提货
* 接口路径: /IntImpPickUpRecord/clearPickUp
* 接口路径: /IntImpPickup/clearPickup
*/
@POST("IntImpPickUpRecord/clearPickUp")
suspend fun clearIntImpPickUp(@Body data: RequestBody): BaseResultBean<Boolean>
@POST("IntImpPickup/clearPickup")
suspend fun clearIntImpPickUp(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港提取记录-详情
* 接口路径: /IntImpPickUpRecord/getDetails
* 国际进港提取记录-修改费用
* 接口路径: /IntImpPickup/modifyCharge
*/
@POST("IntImpPickUpRecord/getDetails")
suspend fun getIntImpPickUpRecordDetails(@Body data: RequestBody): BaseResultBean<IntImpPickUpRecordBean>
@POST("IntImpPickup/modifyCharge")
suspend fun modifyIntImpPickUpCharge(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港提取出库-分页查询
@@ -1008,6 +1022,20 @@ interface Api {
@POST("IntImpSearch/pageQueryTotal")
suspend fun getIntImpQueryTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港查询-详情
* 接口路径: /IntImpSearch/detail
*/
@POST("IntImpSearch/detail")
suspend fun getIntImpQueryDetails(@Body data: RequestBody): BaseResultBean<Map<String, Any>>
/**
* 国际进港查询-修改运单
* 接口路径: /IntImpSearch/modifyMaWb
*/
@POST("IntImpSearch/modifyMaWb")
suspend fun modifyIntImpMaWb(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际出港待计重-分页搜索
* 接口路径: /IntExpCheckIn/pageQuery
@@ -1247,21 +1275,21 @@ interface Api {
suspend fun getGjjManifestDetail(@Query("id") id: String): BaseResultBean<GjjManifestBean>
/**
* 删除-国际进-舱单-列表
* 批量删除-国际进舱单(请求体为 mfId 数组,如 [1,2,3]
*/
@POST("IntImpManiFest/deleteFestList")
suspend fun gjjManifestDelete(@Body data: RequestBody): BaseResultBean<Any>
suspend fun gjjManifestDeleteBatch(@Body data: RequestBody): BaseResultBean<Any>
/**
* 新增-国际进-舱单
* 新增-国际进舱单
*/
@POST("IntImpManiFest/saveFest")
@POST("IntImpManifest/addManifest")
suspend fun gjjManifestInsert(@Body data: RequestBody): BaseResultBean<Any>
/**
* 更新-国际进-舱单
* 修改-国际进舱单
*/
@POST("IntImpManiFest/updateFest")
@POST("IntImpManifest/modifyManifest")
suspend fun gjjManifestUpdate(@Body data: RequestBody): BaseResultBean<Any>
/**
@@ -1466,6 +1494,12 @@ interface Api {
@POST("log/pageQuery")
suspend fun getLogList(@Body data: RequestBody): BaseListBean<LogBean>
/**
* 获取-运单状态列表(关键词-运单号、运单类型必填)
*/
@POST("log/listStatus")
suspend fun getLogStatusList(@Body data: RequestBody): BaseResultBean<List<StatusLogBean>>
///////////////////////////////////////////////////////////////////////////
// 国内进港-舱单
///////////////////////////////////////////////////////////////////////////
@@ -1807,7 +1841,7 @@ interface Api {
* 国际进港舱单-分页查询
*/
@POST("IntImpManifest/pageQuery")
suspend fun getIntImpManifestList(@Body data: RequestBody): BaseResultBean<PageInfo<GjjManifest>>
suspend fun getIntImpManifestList(@Body data: RequestBody): PageInfo<GjjManifest>
/**
* 国际进港舱单-分页合计
@@ -1821,11 +1855,29 @@ interface Api {
@POST("IntImpManifest/listHaWbByManifest")
suspend fun getIntImpManifestHaWbList(@Body data: RequestBody): BaseResultBean<List<GjjHaWb>>
/**
* 国际进港舱单-新增分单
*/
@POST("IntImpManifest/addHaWb")
suspend fun intImpManifestAddHaWb(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港舱单-修改分单
*/
@POST("IntImpManifest/modifyHaWb")
suspend fun intImpManifestModifyHaWb(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港舱单-获取主单减去分单的件数重量
*/
@POST("IntImpManifest/getMaWbMinusHaWb")
suspend fun getMaWbMinusHaWb(@Body data: RequestBody): BaseResultBean<GjjHaWb>
/**
* 国际进港舱单-分拣理货(装机单)-分页查询
*/
@POST("IntImpManifest/pageQueryAir")
suspend fun getIntImpLoadingList(@Body data: RequestBody): BaseResultBean<PageInfo<GjjManifest>>
suspend fun getIntImpLoadingList(@Body data: RequestBody): PageInfo<GjjManifest>
/**
* 国际进港舱单-分拣理货(装机单)-分页合计
@@ -1833,6 +1885,26 @@ interface Api {
@POST("IntImpManifest/pageQueryAirTotal")
suspend fun getIntImpLoadingTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港舱单-分拣理货(装机单)-修改装机单
*/
@POST("IntImpManifest/modifyManifestAir")
suspend fun modifyIntImpLoadingList(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际进港舱单-分拣理货(装机单)-修改库位
* 接口路径: /IntImpManifest/modifyStorage
*/
@POST("IntImpManifest/modifyStorage")
suspend fun modifyIntImpLoadingStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港舱单-分拣理货(装机单)-入库
* 接口路径: /IntImpManifest/inStorage
*/
@POST("IntImpManifest/inStorage")
suspend fun inIntImpLoadingStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港理货报告-分页查询
*/
@@ -1845,6 +1917,42 @@ interface Api {
@POST("IntImpTally/pageQueryTotal")
suspend fun getIntImpTallyTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港理货报告-查询分单列表
*/
@POST("IntImpTally/listHaWb")
suspend fun getIntImpTallySubList(@Body data: RequestBody): BaseResultBean<List<GjjImportTally>>
/**
* 国际进港理货-人工放行
*/
@POST("IntImpTally/customCommand")
suspend fun intImpTallyCustomCommand(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港理货-状态重置
*/
@POST("IntImpTally/resetDeclare")
suspend fun intImpTallyResetDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港理货-删除申报
*/
@POST("IntImpTally/deleteDeclare")
suspend fun intImpTallyDeleteDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港理货-理货申报
*/
@POST("IntImpTally/declare")
suspend fun intImpTallyDeclare(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际进港舱单-货物发放
*/
@POST("IntImpManifest/putUpCargo")
suspend fun intImpManifestPutUpCargo(@Body data: RequestBody): BaseResultBean<String>
///////////////////////////////////////////////////////////////////////////
// 国际进港-事故签证
///////////////////////////////////////////////////////////////////////////
@@ -1861,6 +1969,42 @@ interface Api {
@POST("GjAccidentVisa/delete")
suspend fun deleteIntImpAccidentVisa(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际事故签证-新增
*/
@POST("GjAccidentVisa/saveVisa")
suspend fun saveGjAccidentVisa(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际事故签证-修改
*/
@POST("GjAccidentVisa/modifyVisa")
suspend fun modifyGjAccidentVisa(@Body data: RequestBody): BaseResultBean<String>
/**
* 国际事故签证-详情
*/
@POST("GjAccidentVisa/detail")
suspend fun getGjAccidentVisaDetail(@Query("id") id: Long): BaseResultBean<GjAccidentVisaEditBean>
/**
* 字典-破损情况
*/
@POST("typeCode/damageType")
suspend fun getDamageTypeList(): DictListBean
/**
* 字典-内容物情况
*/
@POST("typeCode/contentType")
suspend fun getContentTypeList(): DictListBean
/**
* 字典-不正常类型
*/
@POST("typeCode/unusualType")
suspend fun getUnusualTypeList(): DictListBean
///////////////////////////////////////////////////////////////////////////
// ULD管理
///////////////////////////////////////////////////////////////////////////

View File

@@ -175,6 +175,7 @@ object ARouterConstants {
const val ACTIVITY_URL_INT_ARR_AIR_MANIFEST_DETAILS = "/gjj/IntArrAirManifestDetailsActivity" //国际进港 原始舱单详情
const val ACTIVITY_URL_INT_ARR_SUPPLEMENT_INFO = "/gjj/IntArrSupplementInfoActivity" //国际进港 补充信息
const val ACTIVITY_URL_INT_IMP_MANIFEST = "/gjj/IntImpManifestActivity" //国际进港 进港舱单
const val ACTIVITY_URL_INT_IMP_MANIFEST_DETAILS = "/gjj/IntImpManifestDetailsActivity" //国际进港 进港舱单详情
const val ACTIVITY_URL_INT_IMP_LOADING_LIST = "/gjj/IntImpLoadingListActivity" //国际进港 装机单(分拣理货)
const val ACTIVITY_URL_INT_IMP_TALLY = "/gjj/IntImpTallyActivity" //国际进港 理货报告
const val ACTIVITY_URL_INT_IMP_PICK_UP_DLV = "/gjj/IntImpPickUpDLVActivity" //国际进港 提取出库
@@ -184,8 +185,10 @@ object ARouterConstants {
/**
* 航班查询模块
*/
const val ACTIVITY_URL_HANG_BAN_QUERY = "/hb/HangBanQueryActivity" //航班查询模块
const val ACTIVITY_URL_HANG_BAN_QUERY_INFO = "/hb/HangBanQueryInfoActivity" //航班查询模块
const val ACTIVITY_URL_HANG_BAN_QUERY = "/hb/HangBanQueryActivity" //航班查询模块(旧版)
const val ACTIVITY_URL_HANG_BAN_QUERY_INFO = "/hb/HangBanQueryInfoActivity" //航班查询模块(旧版)
const val ACTIVITY_URL_HB_QUERY_LIST = "/hb/HbQueryListActivity" //航班管理 列表(新版)
const val ACTIVITY_URL_FLIGHT_QUERY_DETAILS = "/app/FlightQueryDetailsActivity" //航班详情
///////////////// 货物追踪模块
/**
@@ -215,5 +218,7 @@ object ARouterConstants {
///////////////// 综合管理
const val ACTIVITY_URL_COLD_STORAGE = "/app/ColdStorageActivity" //冷库登记
const val ACTIVITY_URL_LOG_QUERY = "/app/LogQueryActivity" //日志查询
const val ACTIVITY_URL_LOG_DETAIL = "/app/LogDetailActivity" //操作日志详情
}

View File

@@ -36,7 +36,11 @@ data class AutoQueryConfig(
var title: String = "请选择",
/** 防抖延迟(毫秒,默认 300ms */
var debounceMillis: Long = 300L
var debounceMillis: Long = 300L,
/** 额外参数提供者(查询时动态获取额外参数,如航班日期、航班号等) */
@Transient
var extraParamsProvider: (() -> Map<String, String?>)? = null
) {
/**
* 验证配置是否有效

View File

@@ -113,8 +113,12 @@ class AutoQueryManager(
}
lastQueriedValue = value
// 构建查询参数
val params = mapOf(config.paramKey to value).toRequestBody()
// 构建查询参数(合并额外参数)
val baseParams = mutableMapOf<String, Any?>(config.paramKey to value)
config.extraParamsProvider?.invoke()?.forEach { (key, v) ->
if (!v.isNullOrEmpty()) baseParams[key] = v
}
val params = baseParams.toRequestBody()
// 发起网络请求
scope?.launchCollect({ NetApply.api.getWbNoList(config.url, params) }) {

View File

@@ -96,6 +96,7 @@ class PadDataLayoutNew : FrameLayout {
field = value
et.hint = value
tv.hint = value
bindAdapter(spinner, list, hint)
}

View File

@@ -119,8 +119,12 @@ class SearchAutoQueryManager(
}
lastQueriedValue = value
// 构建查询参数
val params = mapOf(config.paramKey to value).toRequestBody()
// 构建查询参数(合并额外参数)
val baseParams = mutableMapOf<String, Any?>(config.paramKey to value)
config.extraParamsProvider?.invoke()?.forEach { (key, v) ->
if (!v.isNullOrEmpty()) baseParams[key] = v
}
val params = baseParams.toRequestBody()
// 发起网络请求
scope?.launchCollect({ NetApply.api.getWbNoList(config.url, params) }) {

View File

@@ -102,6 +102,24 @@ object DictUtils {
}
}
/**
* 获取国际进港代理列表
*/
fun getIntImpAgentList(
addAll: Boolean = true,
checkedValue: String? = null,
callBack: (List<KeyValue>) -> Unit
) {
launchCollect({
NetApply.api
.getIntImpAgentList()
}) {
onSuccess = {
handleCallBack(it, checkedValue, addAll, callBack)
}
}
}
/**
* 获取仓管列表
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 B

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:width="200dp"
android:height="200dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -100,11 +100,10 @@
<!-- 添加按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.addClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
</LinearLayout>

View File

@@ -104,11 +104,10 @@
<!-- 添加按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.addClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
</LinearLayout>

View File

@@ -97,11 +97,10 @@
<!--<><E696B0><EFBFBD>按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:onClick="@{()-> viewModel.onAddClick()}"
android:padding="4dp"
android:src="@drawable/img_add" />
<!-- 删除按钮 -->

View File

@@ -11,6 +11,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
class GjjManifestAddActivity :
BaseBindingActivity<ActivityGjjManifestAddBinding, GjjManifestAddViewModel>() {
@@ -20,15 +21,16 @@ class GjjManifestAddActivity :
override fun viewModelClass() = GjjManifestAddViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
// 动态设置标题
val title = when {
viewModel.pageType.value == DetailsPageType.Modify -> "国际进港舱单编辑"
binding.viewModel = viewModel
binding.flightNoInput.et.setUpperCaseAlphanumericFilter()
viewModel.initOnCreated(intent)
// 动态设置标题(必须在 initOnCreated 之后pageType 已从 Intent 解析)
val title = when (viewModel.pageType.value) {
DetailsPageType.Modify -> "国际进港舱单编辑"
else -> "国际进港舱单新增"
}
setBackArrow(title)
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@@ -49,10 +51,17 @@ class GjjManifestAddActivity :
* 编辑舱单通过Bean对象
*/
@JvmStatic
fun startForEdit(context: Context, bean: com.lukouguoji.module_base.bean.GjjManifest) {
fun startForEdit(
context: Context,
bean: com.lukouguoji.module_base.bean.GjjManifest,
flightDate: String = "",
flightNo: String = ""
) {
val starter = Intent(context, GjjManifestAddActivity::class.java)
.putExtra(Constant.Key.PAGE_TYPE, DetailsPageType.Modify.name)
.putExtra(Constant.Key.BEAN, bean)
.putExtra("flightDate", flightDate)
.putExtra("flightNo", flightNo)
context.startActivity(starter)
}

View File

@@ -24,7 +24,7 @@ import com.lukouguoji.module_base.BaseActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO)
// @Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO) // 已替换为 IntImpQueryDetailsActivity
class GjjQueryInfoActivity : BaseActivity(), View.OnClickListener {
private lateinit var viewModel: GjjQueryInfoViewModel

View File

@@ -45,6 +45,13 @@ class IntArrAirManifestActivity :
viewModel.refresh()
}
// 设置运单号自动查询的额外参数(航班日期、航班号)
binding.pslWaybillNo.autoQueryConfig.extraParamsProvider = {
mapOf(
"fdate" to viewModel.flightDate.value,
"fno" to viewModel.flightNo.value
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@@ -8,10 +8,14 @@ import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaBinding
import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.IntImpAccidentVisaBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -19,7 +23,8 @@ import com.lukouguoji.module_base.router.ARouterConstants
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_ACCIDENT_VISA)
class IntImpAccidentVisaActivity :
BaseBindingActivity<ActivityIntImpAccidentVisaBinding, IntImpAccidentVisaViewModel>() {
BaseBindingActivity<ActivityIntImpAccidentVisaBinding, IntImpAccidentVisaViewModel>(),
IOnItemClickListener {
override fun layoutId() = R.layout.activity_int_imp_accident_visa
override fun viewModelClass() = IntImpAccidentVisaViewModel::class.java
@@ -34,6 +39,8 @@ class IntImpAccidentVisaActivity :
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
binding.rv.addOnItemClickListener(this)
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
@@ -48,4 +55,15 @@ class IntImpAccidentVisaActivity :
viewModel.searchClick()
}
}
override fun onItemClick(position: Int, type: Int) {
when (type) {
2000 -> {
// 侧滑菜单 - 修改
val bean = binding.rv.commonAdapter()?.getItem(position) as? IntImpAccidentVisaBean
?: return
IntImpAccidentVisaEditActivity.start(this, bean.id)
}
}
}
}

View File

@@ -0,0 +1,45 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaEditBinding
import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.addOnItemClickListener
/**
* 国际进港-事故签证新增/编辑
*/
class IntImpAccidentVisaEditActivity :
BaseBindingActivity<ActivityIntImpAccidentVisaEditBinding, IntImpAccidentVisaEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_accident_visa_edit
override fun viewModelClass() = IntImpAccidentVisaEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
binding.viewModel = viewModel
viewModel.rv = binding.rv
binding.rv.addOnItemClickListener(viewModel)
viewModel.initOnCreate(intent)
viewModel.pageType.observe(this) {
val title = if (it == DetailsPageType.Add) "国际事故签证新增" else "国际事故签证修改"
setBackArrow(title)
}
}
companion object {
@JvmStatic
fun start(context: Context, id: Long = 0) {
context.startActivity(
Intent(context, IntImpAccidentVisaEditActivity::class.java)
.putExtra(Constant.Key.ID, id)
)
}
}
}

View File

@@ -51,10 +51,19 @@ class IntImpLoadingListActivity :
viewModel.refresh()
}
// 接收从进港舱单传递的参数
// 设置运单号自动查询的额外参数FID、FDGP
binding.pslWaybillNo.autoQueryConfig.extraParamsProvider = {
mapOf(
"fid" to viewModel.fid,
"fdep" to viewModel.fdep
)
}
// 接收从进港舱单传递的参数FID和FDGP用于查询fdate/fno/fdest用于界面显示
intent.getStringExtra("fid")?.let { if (it.isNotEmpty()) viewModel.fid = it }
intent.getStringExtra("fdep")?.let { if (it.isNotEmpty()) viewModel.fdep = it }
intent.getStringExtra("fdate")?.let { if (it.isNotEmpty()) viewModel.flightDate.value = it }
intent.getStringExtra("fno")?.let { if (it.isNotEmpty()) viewModel.flightNo.value = it }
intent.getStringExtra("sendAddress")?.let { if (it.isNotEmpty()) viewModel.sendAddress.value = it }
intent.getStringExtra("fdest")?.let { if (it.isNotEmpty()) viewModel.fdest.value = it }
// 如果收到了航班号和日期参数,触发航班查询来构建始发站下拉列表

View File

@@ -0,0 +1,37 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.google.gson.Gson
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpLoadingListEditBinding
import com.lukouguoji.gjj.viewModel.IntImpLoadingListEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
/**
* 国际进港-装机单编辑页面
*/
class IntImpLoadingListEditActivity :
BaseBindingActivity<ActivityIntImpLoadingListEditBinding, IntImpLoadingListEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_loading_list_edit
override fun viewModelClass() = IntImpLoadingListEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("装机单编辑")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, bean: GjjManifest) {
val starter = Intent(context, IntImpLoadingListEditActivity::class.java)
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
context.startActivity(starter)
}
}
}

View File

@@ -44,6 +44,14 @@ class IntImpManifestActivity :
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
// 设置运单号自动查询的额外参数FID、FDGP
binding.pslWaybillNo.autoQueryConfig.extraParamsProvider = {
mapOf(
"fid" to viewModel.fid,
"fdep" to viewModel.fdep
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@@ -0,0 +1,39 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpManifestDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpManifestDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际进港舱单详情
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_MANIFEST_DETAILS)
class IntImpManifestDetailsActivity :
BaseBindingActivity<ActivityIntImpManifestDetailsBinding, IntImpManifestDetailsViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_manifest_details
override fun viewModelClass() = IntImpManifestDetailsViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("进港舱单详情")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, manifest: GjjManifest) {
val starter = Intent(context, IntImpManifestDetailsActivity::class.java)
.putExtra(Constant.Key.DATA, manifest)
context.startActivity(starter)
}
}
}

View File

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

View File

@@ -0,0 +1,37 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.google.gson.Gson
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpPickUpChargeEditBinding
import com.lukouguoji.gjj.viewModel.IntImpPickUpChargeEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.IntImpPickUpRecordBean
import com.lukouguoji.module_base.common.Constant
/**
* 国际进港-费用修改
*/
class IntImpPickUpChargeEditActivity :
BaseBindingActivity<ActivityIntImpPickUpChargeEditBinding, IntImpPickUpChargeEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_pick_up_charge_edit
override fun viewModelClass() = IntImpPickUpChargeEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港费用修改")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, bean: IntImpPickUpRecordBean) {
val starter = Intent(context, IntImpPickUpChargeEditActivity::class.java)
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
context.startActivity(starter)
}
}
}

View File

@@ -3,7 +3,6 @@ package com.lukouguoji.gjj.activity
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpPickUpRecordBinding
@@ -14,8 +13,11 @@ import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.model.ConfirmDialogModel
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -41,11 +43,35 @@ class IntImpPickUpRecordActivity :
// 绑定分页
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
// 设置列表项点击回调(侧滑修改按钮)
binding.rv.addOnItemClickListener(object : IOnItemClickListener {
override fun onItemClick(position: Int, type: Int) {
when (type) {
2000 -> {
// 侧滑修改操作
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val bean = list.getOrNull(position) as? IntImpPickUpRecordBean ?: return
IntImpPickUpChargeEditActivity.start(this@IntImpPickUpRecordActivity, bean)
}
}
}
})
// 监听刷新事件
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
// 运单号自动查询额外参数
binding.pslWbNo.autoQueryConfig.extraParamsProvider = {
mapOf(
"beginDate" to viewModel.paymentDateStart.value,
"endDate" to viewModel.paymentDateEnd.value,
"agentCode" to viewModel.agentCode.value,
"spCode" to viewModel.spCode.value
)
}
// 初始化下拉列表
viewModel.initAgentList()
viewModel.initSpecialCodeList()
@@ -68,14 +94,12 @@ class IntImpPickUpRecordActivity :
return
}
AlertDialog.Builder(this)
.setTitle("清除提货确认")
.setMessage("确定要清除选中的 ${selectedItems.size} 条提货记录吗?")
.setPositiveButton("确定") { _, _ ->
ConfirmDialogModel(
message = "确定要清除选中的 ${selectedItems.size} 条提货记录吗?",
title = "清除提货确认"
) {
viewModel.clearPickUp(selectedItems)
}
.setNegativeButton("取消", null)
.show()
}.show(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@@ -3,10 +3,12 @@ package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.google.gson.Gson
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpPickUpRecordDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpPickUpRecordDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.IntImpPickUpRecordBean
import com.lukouguoji.module_base.common.Constant
/**
@@ -26,9 +28,9 @@ class IntImpPickUpRecordDetailsActivity :
companion object {
@JvmStatic
fun start(context: Context, id: Long) {
fun start(context: Context, bean: IntImpPickUpRecordBean) {
val starter = Intent(context, IntImpPickUpRecordDetailsActivity::class.java)
.putExtra(Constant.Key.ID, id)
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
context.startActivity(starter)
}
}

View File

@@ -11,6 +11,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
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.ktx.getLifecycleOwner
import com.lukouguoji.module_base.router.ARouterConstants
@@ -33,11 +34,15 @@ class IntImpQueryActivity :
viewModel.pageModel
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
// 注册列表项点击事件
binding.rv.addOnItemClickListener(viewModel)
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
viewModel.initAgentList()
viewModel.initSpecialCodeList()
viewModel.refresh()
}

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpQueryDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.base.CustomVP2Adapter
import com.lukouguoji.module_base.router.ARouterConstants
/**
* 国际进港查询详情页面
*/
@Route(path = ARouterConstants.ACTIVITY_URL_GJJ_QUERY_INFO)
class IntImpQueryDetailsActivity :
BaseBindingActivity<ActivityIntImpQueryDetailsBinding, IntImpQueryDetailsViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_query_details
override fun viewModelClass() = IntImpQueryDetailsViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港查询详情")
binding.viewModel = viewModel
// 初始化ViewModel(传入maWbId)
viewModel.initOnCreated(intent)
// 配置ViewPager2
binding.vp.adapter = CustomVP2Adapter(
viewModel.fragmentList,
supportFragmentManager,
lifecycle
)
binding.vp.isUserInputEnabled = false // 禁用滑动
binding.vp.offscreenPageLimit = 3 // 预加载3个Fragment
// 监听Tab索引变化,切换Fragment
viewModel.currentTab.observe(this) {
binding.vp.setCurrentItem(it, false)
}
// 加载详情数据
viewModel.loadDetails()
}
companion object {
@JvmStatic
fun start(context: Context, prefix: String?, no: String?) {
val starter = Intent(context, IntImpQueryDetailsActivity::class.java)
.putExtra("prefix", prefix ?: "")
.putExtra("no", no ?: "")
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,37 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpQueryEditBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
/**
* 国际进港运单修改页面
*/
class IntImpQueryEditActivity :
BaseBindingActivity<ActivityIntImpQueryEditBinding, IntImpQueryEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_query_edit
override fun viewModelClass() = IntImpQueryEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港运单修改")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, maWbId: Long?, prefix: String?, no: String?) {
val starter = Intent(context, IntImpQueryEditActivity::class.java)
.putExtra("maWbId", maWbId ?: 0L)
.putExtra("prefix", prefix ?: "")
.putExtra("no", no ?: "")
context.startActivity(starter)
}
}
}

View File

@@ -3,7 +3,7 @@ package com.lukouguoji.gjj.activity
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import com.lukouguoji.module_base.model.ConfirmDialogModel
import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpStorageUseBinding
@@ -60,14 +60,19 @@ class IntImpStorageUseActivity :
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
val maWbListForClear = allItems.mapNotNull { maWb ->
if (maWb.isSelected) {
// 勾选运单号 → 默认全选该运单号下的所有库位
maWb.copy(storageUseList = maWb.storageUseList ?: emptyList())
} else {
// 勾选库位号 → 只对选择的库位进行操作
val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList()
if (selectedStorageList.isNotEmpty() || maWb.isSelected) {
if (selectedStorageList.isNotEmpty()) {
maWb.copy(storageUseList = selectedStorageList)
} else {
null
}
}
}
if (maWbListForClear.isEmpty()) {
showToast("请至少选择一个库位")
@@ -105,6 +110,7 @@ class IntImpStorageUseActivity :
val selectedStorage = selectedStorageUseList[0]
// 弹出库位选择弹框,选择后再调用接口
IntImpModifyStorageDialogModel { dialog ->
val locationName = dialog.locationName
val locationId = dialog.locationId
@@ -119,24 +125,32 @@ class IntImpStorageUseActivity :
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
val selectedStorageUseList = mutableListOf<com.lukouguoji.module_base.bean.GjcStorageUse>()
allItems.forEach { maWb ->
maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) }
val maWbListForOutStorage = allItems.mapNotNull { maWb ->
if (maWb.isSelected) {
// 勾选运单号 → 默认全选该运单号下的所有库位
maWb.copy(storageUseList = maWb.storageUseList ?: emptyList())
} else {
// 勾选库位号 → 只对选择的库位进行操作
val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList()
if (selectedStorageList.isNotEmpty()) {
maWb.copy(storageUseList = selectedStorageList)
} else {
null
}
}
}
if (selectedStorageUseList.isEmpty()) {
if (maWbListForOutStorage.isEmpty()) {
showToast("请选择要出库的库位")
return
}
AlertDialog.Builder(this)
.setTitle("出库确认")
.setMessage("确定要将选中的 ${selectedStorageUseList.size} 个库位执行出库操作吗?")
.setPositiveButton("确定") { _, _ ->
viewModel.performOutStorage(selectedStorageUseList)
}
.setNegativeButton("取消", null)
.show()
ConfirmDialogModel(
message = "是否确认出库?",
title = "出库确认"
) {
viewModel.performOutStorage(maWbListForOutStorage)
}.show(this)
}
/**
@@ -147,14 +161,19 @@ class IntImpStorageUseActivity :
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
val maWbListForInStorage = allItems.mapNotNull { maWb ->
if (maWb.isSelected) {
// 勾选运单号 → 默认全选该运单号下的所有库位
maWb.copy(storageUseList = maWb.storageUseList ?: emptyList())
} else {
// 勾选库位号 → 只对选择的库位进行操作
val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList()
if (selectedStorageList.isNotEmpty() || maWb.isSelected) {
if (selectedStorageList.isNotEmpty()) {
maWb.copy(storageUseList = selectedStorageList)
} else {
null
}
}
}
if (maWbListForInStorage.isEmpty()) {
showToast("请至少选择一个单据")

View File

@@ -0,0 +1,36 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpTallyDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpTallyDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjjImportTally
import com.lukouguoji.module_base.common.Constant
/**
* 国际进港理货报告详情
*/
class IntImpTallyDetailsActivity :
BaseBindingActivity<ActivityIntImpTallyDetailsBinding, IntImpTallyDetailsViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_tally_details
override fun viewModelClass() = IntImpTallyDetailsViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("理货报告详情")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, tally: GjjImportTally) {
val starter = Intent(context, IntImpTallyDetailsActivity::class.java)
.putExtra(Constant.Key.DATA, tally)
context.startActivity(starter)
}
}
}

View File

@@ -50,7 +50,7 @@ class IntImpInStorageDialogModel(
* 加载库位列表
*/
private fun loadLocationList() {
launchCollect({ NetApply.api.getLocationList(flag = 4) }) {
launchCollect({ NetApply.api.getLocationList(flag = 3) }) {
onSuccess = { result ->
val list = result.data?.map { it.toKeyValue() } ?: emptyList()
locationList.value = list

View File

@@ -50,7 +50,7 @@ class IntImpModifyStorageDialogModel(
* 加载库位列表
*/
private fun loadLocationList() {
launchCollect({ NetApply.api.getLocationList(flag = 4) }) {
launchCollect({ NetApply.api.getLocationList(flag = 3) }) {
onSuccess = { result ->
val list = result.data?.map { it.toKeyValue() } ?: emptyList()
locationList.value = list

View File

@@ -20,6 +20,7 @@ import dev.utils.app.info.KeyValue
*/
class IntImpQueryFilterDialogModel(
val spCode: MutableLiveData<String>,
val spCodeList: MutableLiveData<List<KeyValue>>,
val flightNo: MutableLiveData<String>,
val dest: MutableLiveData<String>,
val awbType: MutableLiveData<String>,

View File

@@ -0,0 +1,58 @@
package com.lukouguoji.gjj.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.DialogIntImpTallyDeleteBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际进港理货 - 删除申报对话框
*/
class IntImpTallyDeleteDialogModel(
val changeReasonList: List<KeyValue>, // 变更原因列表
private val callback: (IntImpTallyDeleteDialogModel) -> Unit
) : BaseDialogModel<DialogIntImpTallyDeleteBinding>(DIALOG_TYPE_CENTER) {
// 变更原因代码(存储的是 code
val changeReason = MutableLiveData("")
// 联系人姓名
val contactName = MutableLiveData("")
// 联系人电话
val contactPhone = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_int_imp_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

@@ -0,0 +1,66 @@
package com.lukouguoji.gjj.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.DialogIntImpTallyResetBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际进港理货 - 状态重置对话框
*/
class IntImpTallyResetDialogModel(
private val callback: (IntImpTallyResetDialogModel) -> Unit
) : BaseDialogModel<DialogIntImpTallyResetBinding>(DIALOG_TYPE_CENTER) {
// 重置状态列表
val resetStatusList = MutableLiveData<List<KeyValue>>()
// 选中的重置状态存储的是value
val selectedResetStatus = MutableLiveData("")
// 重置状态code (传给后端的restStatus参数)
var resetStatusCode: String? = null
override fun layoutId(): Int {
return R.layout.dialog_int_imp_tally_reset
}
override fun onDialogCreated(context: Context) {
binding.model = this
initResetStatusList()
// 监听选择变化更新resetStatusCode
selectedResetStatus.observeForever { value ->
resetStatusCode = when (value) {
"01" -> "01" // 正常
"02" -> null // 未申报
else -> null
}
}
}
/**
* 初始化重置状态列表
*/
private fun initResetStatusList() {
val list = listOf(
KeyValue("正常", "01"),
KeyValue("未申报", "02")
)
resetStatusList.value = list
}
/**
* 保存按钮点击
*/
fun onSaveClick() {
if (selectedResetStatus.value.verifyNullOrEmpty("请选择重置状态")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -0,0 +1,89 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryStorageBinding
import com.lukouguoji.gjj.holder.IntImpQueryStorageViewHolder
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.bean.GjjStorageUse
import com.lukouguoji.module_base.http.net.NetApply
/**
* 国际进港查询详情 - 库位信息Fragment
*/
class IntImpQueryStorageFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryStorageBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
private lateinit var adapter: CommonAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_storage,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
initRecyclerView()
observeData()
return binding.root
}
private fun initRecyclerView() {
adapter = CommonAdapter(
requireContext(),
R.layout.item_int_imp_query_storage,
IntImpQueryStorageViewHolder::class.java
)
binding.rvStorageList.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = this@IntImpQueryStorageFragment.adapter
}
}
private fun observeData() {
viewModel.storageUseList.observe(viewLifecycleOwner) { mapList ->
if (mapList.isEmpty()) {
binding.rvStorageList.visibility = View.GONE
binding.llEmpty.visibility = View.VISIBLE
} else {
val beanList = mapList.map { map ->
try {
val json = NetApply.gson.toJson(map)
NetApply.gson.fromJson(json, GjjStorageUse::class.java)
} catch (e: Exception) {
e.printStackTrace()
GjjStorageUse()
}
}
binding.rvStorageList.visibility = View.VISIBLE
binding.llEmpty.visibility = View.GONE
adapter.refresh(beanList)
}
}
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryStorageFragment().apply {
viewModel = vm
}
}
}

View File

@@ -0,0 +1,89 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryWarehouseBinding
import com.lukouguoji.gjj.holder.IntImpQueryWarehouseViewHolder
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.bean.GjjWarehouse
import com.lukouguoji.module_base.http.net.NetApply
/**
* 国际进港查询详情 - 仓库信息Fragment
*/
class IntImpQueryWarehouseFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryWarehouseBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
private lateinit var adapter: CommonAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_warehouse,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
initRecyclerView()
observeData()
return binding.root
}
private fun initRecyclerView() {
adapter = CommonAdapter(
requireContext(),
R.layout.item_int_imp_query_warehouse,
IntImpQueryWarehouseViewHolder::class.java
)
binding.rvWarehouseList.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = this@IntImpQueryWarehouseFragment.adapter
}
}
private fun observeData() {
viewModel.warehouseList.observe(viewLifecycleOwner) { mapList ->
if (mapList.isEmpty()) {
binding.rvWarehouseList.visibility = View.GONE
binding.llEmpty.visibility = View.VISIBLE
} else {
val beanList = mapList.map { map ->
try {
val json = NetApply.gson.toJson(map)
NetApply.gson.fromJson(json, GjjWarehouse::class.java)
} catch (e: Exception) {
e.printStackTrace()
GjjWarehouse()
}
}
binding.rvWarehouseList.visibility = View.VISIBLE
binding.llEmpty.visibility = View.GONE
adapter.refresh(beanList)
}
}
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryWarehouseFragment().apply {
viewModel = vm
}
}
}

View File

@@ -0,0 +1,44 @@
package com.lukouguoji.gjj.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.FragmentIntImpQueryWaybillBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
/**
* 国际进港查询详情 - 运单信息Fragment
*/
class IntImpQueryWaybillFragment : Fragment() {
private lateinit var binding: FragmentIntImpQueryWaybillBinding
private lateinit var viewModel: IntImpQueryDetailsViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_int_imp_query_waybill,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = viewModel
return binding.root
}
companion object {
@JvmStatic
fun newInstance(vm: IntImpQueryDetailsViewModel) =
IntImpQueryWaybillFragment().apply {
viewModel = vm
}
}
}

View File

@@ -1,10 +1,8 @@
package com.lukouguoji.gjj.holder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjj.databinding.ItemIntArrAirManifestSubBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjAirManifest
import com.lukouguoji.module_base.bean.GjjImportManifest
/**
@@ -19,18 +17,10 @@ class IntArrAirManifestSubViewHolder(view: View) :
binding.position = position
binding.executePendingBindings()
// 单选框点击切换选择状态
// 单选框点击切换选择状态(独立选择,不联动主列表)
binding.ivCheckbox.setOnClickListener {
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
// 反向联动主列表项(勾选子项时自动勾选父项)
if (newCheckedState) {
val recyclerView = itemView.parent as? RecyclerView ?: return@setOnClickListener
val parentBean = recyclerView.tag as? GjjAirManifest ?: return@setOnClickListener
parentBean.checked.set(true)
}
}
}
}

View File

@@ -26,14 +26,10 @@ class IntArrAirManifestViewHolder(view: View) :
// 整卡点击 - 跳转详情页
notifyItemClick(position, binding.ll)
// 图标点击 - 切换选择状态(联动子列表)
// 图标点击 - 切换选择状态(独立选择,不联动子列表)
binding.ivIcon.setOnClickListener {
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
// 联动子列表选中状态
bean.haWbList?.forEach { sub -> sub.checked.set(newCheckedState) }
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
binding.rvSub.adapter?.notifyDataSetChanged()
}
// 展开按钮点击事件
@@ -48,7 +44,6 @@ class IntArrAirManifestViewHolder(view: View) :
R.layout.item_int_arr_air_manifest_sub
)
// 设置父Bean引用用于子列表反向联动
binding.rvSub.tag = bean
binding.rvSub.refresh(bean.haWbList ?: emptyList())
}

View File

@@ -21,5 +21,11 @@ class IntImpAccidentVisaViewHolder(view: View) :
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
}
// 侧滑菜单 - 修改按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000) // type=2000表示修改操作
}
}
}

View File

@@ -22,5 +22,11 @@ class IntImpLoadingListViewHolder(view: View) :
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
}
// 侧滑菜单 - 编辑按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000)
}
}
}

View File

@@ -30,6 +30,9 @@ class IntImpManifestViewHolder(view: View) :
binding.rvSub.adapter?.notifyDataSetChanged()
}
// 整卡点击 - 跳转详情页
notifyItemClick(position, binding.llContent)
// 编辑按钮点击
binding.btnEdit.setOnClickListener {
clickListener?.onItemClick(position, 101) // 101=编辑
@@ -40,10 +43,15 @@ class IntImpManifestViewHolder(view: View) :
clickListener?.onItemClick(position, 102) // 102=删除
}
// 展开按钮点击事件
// 展开按钮点击事件 - 先加载分单数据,再切换展开状态
binding.ivShow.setOnClickListener {
if (!bean.showMore.get() && bean.haWbList.isNullOrEmpty()) {
// 首次展开且无数据,通知 ViewModel 加载分单
clickListener?.onItemClick(position, 103) // 103=加载分单
} else {
bean.showMore.set(!bean.showMore.get())
}
}
// 初始化分单子列表 RecyclerView
setCommonAdapter(
@@ -54,6 +62,29 @@ class IntImpManifestViewHolder(view: View) :
// 设置父Bean引用用于子列表反向联动
binding.rvSub.tag = bean
binding.rvSub.refresh(bean.haWbList ?: emptyList())
val subList = bean.haWbList ?: emptyList()
binding.rvSub.refresh(subList)
updateSubListVisibility(bean.haWbList != null, subList.isNotEmpty())
}
/**
* 根据分单数据状态,切换表头/列表与空数据提示的显隐
* @param loaded 是否已加载过数据haWbList != null
* @param hasData 是否有数据
*/
private fun updateSubListVisibility(loaded: Boolean, hasData: Boolean) {
if (!loaded || hasData) {
// 未加载或有数据:显示表头+列表,隐藏空提示
binding.llHeader.visibility = View.VISIBLE
binding.dividerHeader.visibility = View.VISIBLE
binding.rvSub.visibility = View.VISIBLE
binding.tvEmpty.visibility = View.GONE
} else {
// 已加载但无数据:隐藏表头+列表,显示空提示
binding.llHeader.visibility = View.GONE
binding.dividerHeader.visibility = View.GONE
binding.rvSub.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE
}
}
}

View File

@@ -25,8 +25,14 @@ class IntImpPickUpRecordViewHolder(view: View) :
}
// 列表项点击进入提取详情
itemView.setOnClickListener {
IntImpPickUpRecordDetailsActivity.start(itemView.context, bean.id)
binding.ll.setOnClickListener {
IntImpPickUpRecordDetailsActivity.start(itemView.context, bean)
}
// 侧滑菜单 - 修改按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000) // type=2000表示修改操作
}
}
}

View File

@@ -0,0 +1,20 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpQueryStorageBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjStorageUse
/**
* 国际进港查询详情-库位信息ViewHolder
*/
class IntImpQueryStorageViewHolder(view: View) :
BaseViewHolder<GjjStorageUse, ItemIntImpQueryStorageBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
}
}

View File

@@ -15,5 +15,14 @@ class IntImpQueryViewHolder(view: View) :
val bean = getItemBean(item)!!
binding.bean = bean
binding.executePendingBindings()
// 注册整行点击事件
notifyItemClick(position, binding.ll)
// 侧滑菜单 - 修改按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000) // type=2000表示修改操作
}
}
}

View File

@@ -0,0 +1,20 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.databinding.ItemIntImpQueryWarehouseBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjWarehouse
/**
* 国际进港查询详情-仓库信息ViewHolder
*/
class IntImpQueryWarehouseViewHolder(view: View) :
BaseViewHolder<GjjWarehouse, ItemIntImpQueryWarehouseBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.position = position
binding.executePendingBindings()
}
}

View File

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

View File

@@ -1,9 +1,17 @@
package com.lukouguoji.gjj.holder
import android.view.View
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ItemIntImpTallyBinding
import com.lukouguoji.gjj.activity.IntImpTallyDetailsActivity
import com.lukouguoji.module_base.adapter.setCommonAdapter
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjjImportTally
import com.google.gson.Gson
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.refresh
import com.lukouguoji.module_base.ktx.toRequestBody
/**
* 国际进港理货报告 ViewHolder
@@ -17,10 +25,84 @@ class IntImpTallyViewHolder(view: View) :
binding.position = position
binding.executePendingBindings()
// 选中图标点击 - 切换选择状态
// 选中图标点击 - 切换选择状态(联动子列表)
binding.ivIcon.setOnClickListener {
bean.checked.set(!bean.checked.get())
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
// 联动勾选/取消所有子列表项
bean.haWbList?.forEach { sub ->
sub.checked.set(newCheckedState)
}
binding.executePendingBindings()
binding.rvSub.adapter?.notifyDataSetChanged()
}
// 整个内容区域点击 - 跳转到详情页
binding.llContent.setOnClickListener {
IntImpTallyDetailsActivity.start(it.context, bean)
}
// 展开按钮点击事件
binding.ivShow.setOnClickListener {
if (bean.haWbList != null) {
// 已加载过数据,直接切换显隐
bean.showMore.set(!bean.showMore.get())
} else {
// 首次展开,调用接口加载分单数据
loadSubList(bean)
}
}
// 初始化分单子列表 RecyclerView
setCommonAdapter(
binding.rvSub,
IntImpTallySubViewHolder::class.java,
R.layout.item_int_imp_tally_sub
)
// 刷新分单数据传递父Bean引用用于反向联动
binding.rvSub.tag = bean
val subList = bean.haWbList ?: emptyList()
binding.rvSub.refresh(subList)
updateSubListVisibility(subList.isNotEmpty())
}
/**
* 加载分单列表数据(将主单整体作为请求参数)
*/
private fun loadSubList(bean: GjjImportTally) {
// 将 bean 转为 Map 并补充 wbNo 字段prefix + no
val map = Gson().fromJson(Gson().toJson(bean), HashMap::class.java) as HashMap<String, Any?>
map["wbNo"] = bean.getWaybillNo()
val params = map.toRequestBody()
launchCollect({ NetApply.api.getIntImpTallySubList(params) }) {
onSuccess = { result ->
val list = result.data?.toMutableList() ?: mutableListOf()
bean.haWbList = list
bean.showMore.set(true)
binding.rvSub.refresh(list)
updateSubListVisibility(list.isNotEmpty())
}
}
}
/**
* 根据分单数据是否为空,切换表头/列表与空数据提示的显隐
*/
private fun updateSubListVisibility(hasData: Boolean) {
if (hasData) {
binding.llHeader.visibility = View.VISIBLE
binding.dividerHeader.visibility = View.VISIBLE
binding.rvSub.visibility = View.VISIBLE
binding.tvEmpty.visibility = View.GONE
} else {
binding.llHeader.visibility = View.GONE
binding.dividerHeader.visibility = View.GONE
binding.rvSub.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE
}
}
}

View File

@@ -2,6 +2,7 @@ package com.lukouguoji.gjj.viewModel
import android.content.Intent
import android.view.View
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.module_base.base.BaseViewModel
@@ -38,12 +39,60 @@ class GjjManifestAddViewModel : BaseViewModel() {
// 航班号
val flightNo = MutableLiveData("")
// 航程
val range = MutableLiveData("")
// 运单号
val waybillNo = MutableLiveData("")
// ========== 航班级联查询 ==========
private var lastQueriedFlight = ""
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
queryFlightIfReady()
}
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
private fun queryFlightIfReady() {
val fdate = flightDate.value
val fno = flightNo.value
if (fdate.isNullOrEmpty() || fno.isNullOrEmpty()) return
val key = "$fdate-$fno"
if (key == lastQueriedFlight) return
lastQueriedFlight = key
launchCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
fid = flight.fid.noNull()
departure.value = flight.fdep.noNull()
destination.value = flight.fdest.noNull()
} else {
fid = ""
departure.value = ""
destination.value = ""
showToast(it.msg.noNull("获取航班信息失败"))
}
}
onFailed = { _, _ ->
fid = ""
departure.value = ""
destination.value = ""
}
}
}
// UN编号
val unNumber = MutableLiveData("")
@@ -65,6 +114,17 @@ class GjjManifestAddViewModel : BaseViewModel() {
// 目的港
val destination = MutableLiveData("")
// 航程(自动拼接:始发站-目的站)
val range = MediatorLiveData<String>().apply {
val update = {
val dep = departure.value ?: ""
val dest = destination.value ?: ""
value = if (dep.isNotEmpty() || dest.isNotEmpty()) "$dep-$dest" else ""
}
addSource(departure) { update() }
addSource(destination) { update() }
}
// 品名(中)
val goodsNameCn = MutableLiveData("")
@@ -100,10 +160,10 @@ class GjjManifestAddViewModel : BaseViewModel() {
val waybillType = MutableLiveData("")
init {
DictUtils.getAgentList(addAll = false) {
DictUtils.getIntImpAgentList(addAll = false) {
agentList.postValue(listOf(KeyValue("", "")) + it)
}
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "I") {
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") {
val list = arrayListOf<KeyValue>()
it.find { b -> b.key.contains("普通货物") }?.let { b ->
list.add(b)
@@ -114,7 +174,7 @@ class GjjManifestAddViewModel : BaseViewModel() {
DictUtils.getBusinessTypeList(addAll = false) {
businessTypeList.postValue(it)
}
DictUtils.getGjjPackageTypeList(addAll = false) {
DictUtils.getShouYunPackageTypeList {
packageTypeList.postValue(listOf(KeyValue("", "")) + it)
}
DictUtils.getGjjGoodsTypeList(addAll = false) {
@@ -146,6 +206,10 @@ class GjjManifestAddViewModel : BaseViewModel() {
// 编辑模式从Bean对象加载数据
if (pageType.value == DetailsPageType.Modify) {
// 回填航班日期和航班号Bean中不包含从列表页传入
flightDate.value = intent.getStringExtra("flightDate").noNull()
flightNo.value = intent.getStringExtra("flightNo").noNull()
val bean = intent.getSerializableExtra(Constant.Key.BEAN)
if (bean is com.lukouguoji.module_base.bean.GjjManifest) {
loadManifestFromBean(bean)
@@ -229,15 +293,14 @@ class GjjManifestAddViewModel : BaseViewModel() {
"mfId" to if (pageType.value == DetailsPageType.Modify) mfId else null,
"fid" to fid,
"wbNo" to waybillNo.value,
"agent" to agent.value,
"agentCode" to agent.value,
"spCode" to specialCode.value,
"businessType" to businessType.value,
"awbpc" to waybillNum.value,
"totalPc" to waybillNum.value,
"pc" to actualNum.value,
"weight" to actualWeight.value,
"planweight" to billingWeight.value,
"packagecode" to packageType.value,
"dep" to departure.value,
"cashWeight" to billingWeight.value,
"packageType" to packageType.value,
"origin" to departure.value,
"dest" to destination.value,
"goods" to goodsNameEn.value,

View File

@@ -110,7 +110,7 @@ class GjjManifestDetailsViewModel : BaseViewModel(), IGetData {
DictUtils.getAgentList(addAll = false, checkedValue = data.agent) {
agentList.postValue(it)
}
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "I", checkedValue = data.spCode) {
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "", checkedValue = data.spCode) {
specialCodeList.postValue(it)
}
DictUtils.getBusinessTypeList(

View File

@@ -266,7 +266,7 @@ class GjjManifestListViewModel : BasePageViewModel(), IOnItemClickListener {
private fun onDelete(list: List<GjjManifestBean>) {
showLoading()
launchCollect({
NetApply.api.gjjManifestDelete(
NetApply.api.gjjManifestDeleteBatch(
list.map { it.mfId }.toRequestBody()
)
}) {

View File

@@ -12,6 +12,7 @@ import com.lukouguoji.module_base.bean.GjjDeclareParam
import com.lukouguoji.module_base.bean.GjjImportManifest
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.gjj.dialog.IntImpTallyResetDialogModel
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.commonAdapter
@@ -113,32 +114,32 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.HNO)
}
/**
* 收集选中的主单和分单(独立选择,互不影响)
* @return Pair<主单列表, 分单列表>,如果无任何选中返回 null
*/
private fun getSelectedItems(emptyMsg: String): Pair<List<GjjImportManifest>, List<GjjImportManifest>>? {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjAirManifest> ?: return null
val maWbList = list.filter { it.isSelected }.mapNotNull { it.maWb }
val haWbList = list.flatMap { it.haWbList ?: emptyList() }.filter { it.isSelected }
if (maWbList.isEmpty() && haWbList.isEmpty()) {
showToast(emptyMsg)
return null
}
return Pair(maWbList, haWbList)
}
/**
* 状态重置按钮点击
*/
fun resetStatusClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjAirManifest> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要重置的舱单")
return
}
// 提取主单和分单
val maWbList = mutableListOf<GjjImportManifest>()
val haWbList = mutableListOf<GjjImportManifest>()
selectedItems.forEach { airManifest ->
airManifest.maWb?.let { maWbList.add(it) }
airManifest.haWbList?.let { haWbList.addAll(it) }
}
val (maWbList, haWbList) = getSelectedItems("请选择要重置的舱单") ?: return
val dialog = IntImpTallyResetDialogModel { dialogModel ->
val param = GjjDeclareParam(
maWbList = maWbList,
haWbList = haWbList,
restStatus = null, // 未申报状态
resetReason = "状态重置"
restStatus = dialogModel.resetStatusCode
)
launchLoadingCollect({ NetApply.api.resetIntArrManifestStatus(param.toRequestBody()) }) {
@@ -152,26 +153,24 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
}
}
dialog.show()
}
/**
* 补充信息按钮点击
* 补充信息按钮点击(只针对主单)
*/
fun supplementInfoClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjAirManifest> ?: return
val selectedItems = list.filter { it.isSelected }
val selectedMainItems = list.filter { it.isSelected }.mapNotNull { it.maWb }
if (selectedItems.isEmpty()) {
showToast("请选择要补充信息的")
if (selectedMainItems.isEmpty()) {
showToast("请选择要补充信息的")
return
}
// 收集所有选中项的主单数据
val manifestList = ArrayList(selectedItems.mapNotNull { it.maWb })
if (manifestList.isEmpty()) return
// 跳转到补充信息页面(传递完整列表)
com.lukouguoji.gjj.activity.IntArrSupplementInfoActivity.start(
getTopActivity(),
manifestList
ArrayList(selectedMainItems)
)
}
@@ -179,31 +178,14 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
* 删除申报按钮点击
*/
fun deleteDeclarationClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjAirManifest> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要删除申报的舱单")
return
}
val (maWbList, haWbList) = getSelectedItems("请选择要删除申报的舱单") ?: return
// 从接口获取删除原因列表
launchLoadingCollect({ NetApply.api.getDelReasonList() }) {
onSuccess = { result ->
val deleteReasonList = result.data?.map { it.toKeyValue() } ?: emptyList()
// 创建并显示弹框
val dialog = com.lukouguoji.gjj.dialog.IntArrManifestDeleteDialogModel(deleteReasonList) { dialogModel ->
// 弹框确认后的回调
// 提取主单和分单
val maWbList = mutableListOf<GjjImportManifest>()
val haWbList = mutableListOf<GjjImportManifest>()
selectedItems.forEach { airManifest ->
airManifest.maWb?.let { maWbList.add(it) }
airManifest.haWbList?.let { haWbList.addAll(it) }
}
val param = GjjDeclareParam(
dcode = dialogModel.deleteReason.value ?: "",
dcontactsName = dialogModel.contactName.value ?: "",
@@ -212,10 +194,7 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
haWbList = haWbList
)
val requestData = param.toRequestBody()
// 调用删除接口
launchLoadingCollect({ NetApply.api.deleteIntArrManifestDeclare(requestData) }) {
launchLoadingCollect({ NetApply.api.deleteIntArrManifestDeclare(param.toRequestBody()) }) {
onSuccess = {
showToast("删除申报成功")
viewModelScope.launch {
@@ -235,27 +214,9 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
* 舱单申报按钮点击
*/
fun declareClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjAirManifest> ?: return
val selectedItems = list.filter { it.isSelected }
val (maWbList, haWbList) = getSelectedItems("请选择要申报的舱单") ?: return
if (selectedItems.isEmpty()) {
showToast("请选择要申报的舱单")
return
}
// 提取主单和分单
val maWbList = mutableListOf<GjjImportManifest>()
val haWbList = mutableListOf<GjjImportManifest>()
selectedItems.forEach { airManifest ->
airManifest.maWb?.let { maWbList.add(it) }
airManifest.haWbList?.let { haWbList.addAll(it) }
}
val param = GjjDeclareParam(
maWbList = maWbList,
haWbList = haWbList
)
val param = GjjDeclareParam(maWbList = maWbList, haWbList = haWbList)
launchLoadingCollect({ NetApply.api.declareIntArrManifest(param.toRequestBody()) }) {
onSuccess = {
@@ -293,6 +254,19 @@ class IntArrAirManifestViewModel : BasePageViewModel() {
launchLoadingCollect({ NetApply.api.getIntArrAirManifestList(listParams) }) {
onSuccess = { result ->
isAllExpanded.value = false
// 如果接口未返回航班日期/航班号,用筛选条件填充
val fd = flightDate.value ?: ""
val fn = flightNo.value ?: ""
result.list?.forEach { airManifest ->
airManifest.maWb?.let {
if (it.fdate.isEmpty()) it.fdate = fd
if (it.fno.isEmpty()) it.fno = fn
}
airManifest.haWbList?.forEach {
if (it.fdate.isEmpty()) it.fdate = fd
if (it.fno.isEmpty()) it.fno = fn
}
}
pageModel.handleListBean(result.toBaseListBean())
}
}

View File

@@ -13,6 +13,7 @@ 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.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
@@ -56,7 +57,7 @@ class IntArrSupplementInfoViewModel : BaseViewModel() {
* 加载国家代码下拉列表
*/
private fun loadCountryCodeList() {
launchCollect({ NetApply.api.getAreaTypeList() }) {
launchCollect({ NetApply.api.getCountryCodeList() }) {
onSuccess = { result ->
val keyValueList = result.data?.mapNotNull { bean ->
if (bean.code != null && bean.name != null) {
@@ -69,13 +70,18 @@ class IntArrSupplementInfoViewModel : BaseViewModel() {
}
/**
* 加载通讯方式下拉列表(本地固定值)
* 加载通讯方式下拉列表
*/
private fun loadComTypeList() {
comTypeList.value = listOf(
KeyValue("电话TE", "TE"),
KeyValue("传真FX", "FX")
)
launchCollect({ NetApply.api.getCommunicateTypeList() }) {
onSuccess = { result ->
comTypeList.value = result.data?.mapNotNull { bean ->
if (bean.code != null && bean.name != null) {
KeyValue(bean.name, bean.code)
} else null
} ?: emptyList()
}
}
}
/**
@@ -91,6 +97,17 @@ class IntArrSupplementInfoViewModel : BaseViewModel() {
fun save() {
val formBean = dataBean.value ?: return
// 收货人必填校验
if (formBean.consigneeName.verifyNullOrEmpty("收货人名称不能为空")) return
if (formBean.consigneeCountryCode.verifyNullOrEmpty("收货人国家代码不能为空")) return
if (formBean.consigneeComType.verifyNullOrEmpty("收货人通讯方式不能为空")) return
if (formBean.consigneePNum.verifyNullOrEmpty("收货人联系号码不能为空")) return
// 发货人必填校验
if (formBean.consignorName.verifyNullOrEmpty("发货人名称不能为空")) return
if (formBean.consignorCountryCode.verifyNullOrEmpty("发货人国家代码不能为空")) return
if (formBean.consignorComType.verifyNullOrEmpty("发货人通讯方式不能为空")) return
if (formBean.consignorPNum.verifyNullOrEmpty("发货人联系号码不能为空")) return
if (manifestList.isEmpty()) {
showToast("无可保存的数据")
return

View File

@@ -0,0 +1,271 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjj.R
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.bean.GjAccidentVisaEditBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.ImageSelectViewHolder
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
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.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.util.MediaUtil
import com.lukouguoji.module_base.util.UploadUtil
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
class IntImpAccidentVisaEditViewModel : BaseViewModel(), IOnItemClickListener {
var id: Long = 0
val pageType = MutableLiveData(DetailsPageType.Add)
val dataBean = MutableLiveData(GjAccidentVisaEditBean())
// 图片列表
val itemLayoutId = R.layout.item_image_select
val itemViewHolder = ImageSelectViewHolder::class.java
var rv: RecyclerView? = null
// 下拉列表
val outerPackageList = MutableLiveData<List<KeyValue>>(emptyList())
val damageTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val contentTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val unusualTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val photoList = MutableLiveData(
listOf(KeyValue("", ""), KeyValue("", ""))
)
// 航班级联查询
private var lastQueriedFlight = ""
///////////////////////////////////////////////////////////////////////////
// 初始化
///////////////////////////////////////////////////////////////////////////
fun initOnCreate(intent: Intent) {
id = intent.getLongExtra(Constant.Key.ID, 0)
pageType.value = if (id == 0L) DetailsPageType.Add else DetailsPageType.Modify
loadDropdownLists()
if (id != 0L) {
loadDetail()
}
rv?.post {
rv?.commonAdapter()?.addItem(FileBean())
}
}
private fun loadDropdownLists() {
launchCollect({ NetApply.api.getPackTypeList() }) {
onSuccess = { result ->
outerPackageList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getDamageTypeList() }) {
onSuccess = { result ->
damageTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getContentTypeList() }) {
onSuccess = { result ->
contentTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getUnusualTypeList() }) {
onSuccess = { result ->
unusualTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
}
private fun loadDetail() {
launchLoadingCollect({ NetApply.api.getGjAccidentVisaDetail(id) }) {
onSuccess = {
dataBean.value = it.data ?: GjAccidentVisaEditBean()
// 渲染图片
val bean = dataBean.value!!
val picList = bean.pic.split(",")
.filter { url -> url.isNotEmpty() }
.map { url -> FileBean(MediaUtil.fillUrl(url), url) }
val originalList = bean.originalPic.split(",")
.filter { url -> url.isNotEmpty() }
.map { url -> FileBean(MediaUtil.fillUrl(url)) }
for ((index, fileBean) in picList.withIndex()) {
if (index < originalList.size) {
picList[index].originalPic = originalList[index].path
}
}
rv?.commonAdapter()?.loadMore(picList)
}
}
}
///////////////////////////////////////////////////////////////////////////
// 航班级联查询
///////////////////////////////////////////////////////////////////////////
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
queryFlightIfReady()
}
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
private fun queryFlightIfReady() {
val bean = dataBean.value ?: return
val fdate = bean.fdate
val fno = bean.fno
if (fdate.isEmpty() || fno.isEmpty()) return
val key = "$fdate-$fno"
if (key == lastQueriedFlight) return
lastQueriedFlight = key
launchCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = flight.fdep.noNull()
b.dest = flight.fdest.noNull()
dataBean.value = b
} else {
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = ""
b.dest = ""
dataBean.value = b
showToast(it.msg.noNull("获取航班信息失败"))
}
}
onFailed = { _, _ ->
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = ""
b.dest = ""
dataBean.value = b
}
}
}
///////////////////////////////////////////////////////////////////////////
// 保存
///////////////////////////////////////////////////////////////////////////
fun onSaveClick() {
val bean = dataBean.value ?: return
if (bean.fdate.verifyNullOrEmpty("请输入航班日期")) return
if (bean.fno.verifyNullOrEmpty("请输入航班号")) return
if (bean.wbNo.verifyNullOrEmpty("请输入运单号")) return
(rv?.commonAdapter()?.items ?: emptyList())
.asFlow()
.map { it as FileBean }
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
.onEach {
val data = UploadUtil.upload(it.path).data
it.url = data?.newName ?: ""
it.originalPic = data?.zipFileName ?: ""
}
.flowOn(Dispatchers.IO)
.onStart { showLoading() }
.catch {
showToast(it.message.noNull("上传图片失败"))
dismissLoading()
}
.onCompletion {
launchLoadingCollect({
val list = (rv?.commonAdapter()?.items as List<FileBean>)
.filter { it.path.isNotEmpty() }
bean.picNumber = list.size.toString()
bean.originalPic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.url) }
bean.pic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.originalPic) }
bean.idFlag = "1"
if (pageType.value == DetailsPageType.Add) {
NetApply.api.saveGjAccidentVisa(bean.toRequestBody())
} else {
NetApply.api.modifyGjAccidentVisa(bean.toRequestBody())
}
}) {
onSuccess = {
showToast(it.msg.noNull("${pageType.value!!.title}成功"))
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
}
}
}
.launchIn(viewModelScope)
}
fun onCancelClick() {
getTopActivity().finish()
}
///////////////////////////////////////////////////////////////////////////
// 图片操作
///////////////////////////////////////////////////////////////////////////
override fun onItemClick(position: Int, type: Int) {
val adapter = rv!!.commonAdapter()!!
val bean = adapter.getItem(position) as FileBean
when (type) {
R.id.rl -> {
bean.canDelete.set(!bean.canDelete.get())
}
R.id.iv_delete -> {
adapter.removeItem(position)
}
else -> {}
}
}
}

View File

@@ -123,6 +123,10 @@ class IntImpAccidentVisaViewModel : BasePageViewModel() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL)
}
fun addClick() {
com.lukouguoji.gjj.activity.IntImpAccidentVisaEditActivity.start(getTopActivity())
}
fun searchClick() {
refresh()
}

View File

@@ -0,0 +1,86 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import kotlinx.coroutines.launch
/**
* 国际进港装机单编辑 ViewModel
*/
class IntImpLoadingListEditViewModel : BaseViewModel() {
val dataBean = MutableLiveData(GjjManifest())
// 可编辑数值字段String 用于双向绑定)
val location = MutableLiveData("")
val totalPcStr = MutableLiveData("")
val pcStr = MutableLiveData("")
val weightStr = MutableLiveData("")
val cashWeightStr = MutableLiveData("")
fun initOnCreated(intent: Intent) {
val jsonData = intent.getStringExtra(Constant.Key.DATA) ?: ""
if (jsonData.isNotEmpty()) {
try {
val bean = Gson().fromJson(jsonData, GjjManifest::class.java)
dataBean.value = bean
// 初始化可编辑字段
location.value = bean.location
totalPcStr.value = bean.totalPc.toString()
pcStr.value = bean.pc.toString()
weightStr.value = bean.weight.toString()
cashWeightStr.value = bean.cashWeight.toString()
} catch (e: Exception) {
showToast("数据解析失败")
getTopActivity().finish()
}
} else {
showToast("未接收到数据")
getTopActivity().finish()
}
}
/**
* 保存修改
*/
fun submit() {
val bean = dataBean.value ?: return
// 同步可编辑字段回 bean
bean.location = location.value ?: ""
bean.totalPc = totalPcStr.value?.toLongOrNull() ?: 0
bean.pc = pcStr.value?.toLongOrNull() ?: 0
bean.weight = weightStr.value?.toDoubleOrNull() ?: 0.0
bean.cashWeight = cashWeightStr.value?.toDoubleOrNull() ?: 0.0
launchLoadingCollect({
NetApply.api.modifyIntImpLoadingList(bean.toRequestBody())
}) {
onSuccess = {
showToast("修改成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
}
}
}
/**
* 取消
*/
fun cancel() {
getTopActivity().finish()
}
}

View File

@@ -10,6 +10,7 @@ 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.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
@@ -23,7 +24,7 @@ import kotlinx.coroutines.launch
/**
* 国际进港装机单 ViewModel
*/
class IntImpLoadingListViewModel : BasePageViewModel() {
class IntImpLoadingListViewModel : BasePageViewModel(), IOnItemClickListener {
// ========== 搜索条件 ==========
val flightDate = MutableLiveData("") // 航班日期
@@ -35,7 +36,8 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
// ========== 航班级联查询 ==========
private var lastQueriedFlight = ""
private var fid = ""
var fid = ""
var fdep = ""
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
@@ -68,6 +70,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
fid = flight.fid.noNull()
fdep = flight.fdep.noNull()
fdest.value = flight.fdest.noNull()
// 构建始发站下拉列表fdep + jtz经停港
@@ -81,6 +84,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
sendAddress.value = flight.fdep.noNull()
} else {
fid = ""
fdep = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
@@ -90,6 +94,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
onFailed = { _, _ ->
fid = ""
fdep = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
@@ -120,10 +125,67 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
/**
* 搜索按钮点击
* 先查询航班信息获取FID再刷新列表与父页面逻辑保持一致
*/
fun searchClick() {
val fdate = flightDate.value
val fno = flightNo.value
if (!fdate.isNullOrEmpty() && !fno.isNullOrEmpty()) {
val key = "$fdate-$fno"
if (key != lastQueriedFlight || fid.isEmpty()) {
// 先查询航班信息获取FID
lastQueriedFlight = key
launchLoadingCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
fid = flight.fid.noNull()
fdep = flight.fdep.noNull()
fdest.value = flight.fdest.noNull()
val list = mutableListOf(
KeyValue(flight.fdep.noNull(), flight.fdep.noNull()),
)
if (!flight.jtz.isNullOrEmpty()) {
list.add(KeyValue(flight.jtz.noNull(), flight.jtz.noNull()))
}
sendAddressList.value = list
sendAddress.value = flight.fdep.noNull()
} else {
fid = ""
fdep = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
showToast(it.msg.noNull("获取航班信息失败"))
}
refresh()
}
onFailed = { _, _ ->
fid = ""
fdep = ""
fdest.value = ""
sendAddressList.value = emptyList()
sendAddress.value = ""
refresh()
}
}
} else {
refresh()
}
} else {
fid = ""
fdep = ""
refresh()
}
}
/**
* 全选按钮点击(切换全选状态)
@@ -165,7 +227,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
"manifestList" to selectedItems
).toRequestBody()
launchLoadingCollect({ NetApply.api.modifyIntImpStorage(params) }) {
launchLoadingCollect({ NetApply.api.modifyIntImpLoadingStorage(params) }) {
onSuccess = {
showToast("修改库位成功")
viewModelScope.launch {
@@ -203,7 +265,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
"manifestList" to selectedItems
).toRequestBody()
launchLoadingCollect({ NetApply.api.inIntImpStorage(params) }) {
launchLoadingCollect({ NetApply.api.inIntImpLoadingStorage(params) }) {
onSuccess = {
showToast("入库成功")
viewModelScope.launch {
@@ -217,16 +279,29 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
}
}
/**
* 列表项点击回调(侧滑菜单)
*/
override fun onItemClick(position: Int, type: Int) {
when (type) {
2000 -> {
// 编辑操作
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
val bean = list.getOrNull(position) ?: return
com.lukouguoji.gjj.activity.IntImpLoadingListEditActivity.start(getTopActivity(), bean)
}
}
}
/**
* 获取数据重写BasePageViewModel
* 查询参数与父页面国际进港舱单保持一致使用FID和FDGP
*/
override fun getData() {
// 构建搜索条件
// 构建搜索条件与父页面一致fid + fdep + wbNo
val filterParams = mapOf(
"fdate" to flightDate.value?.ifEmpty { null },
"fno" to flightNo.value?.ifEmpty { null },
"sendAddress" to sendAddress.value?.ifEmpty { null },
"fdest" to fdest.value?.ifEmpty { null },
"fid" to fid.ifEmpty { null },
"fdep" to fdep.ifEmpty { null },
"wbNo" to waybillNo.value?.ifEmpty { null }
)
@@ -242,19 +317,7 @@ class IntImpLoadingListViewModel : BasePageViewModel() {
// 获取列表带Loading
launchLoadingCollect({ NetApply.api.getIntImpLoadingList(listParams) }) {
onSuccess = { result ->
// 处理PageInfo结构
val pageInfo = result.data
if (pageInfo != null) {
val list = pageInfo.list ?: emptyList()
val pages = pageInfo.pages ?: 1
// 处理分页数据
pageModel.handleDataList(list)
pageModel.haveMore.postValue(pages > pageModel.page)
} else {
pageModel.handleDataList(emptyList())
pageModel.haveMore.postValue(false)
}
pageModel.handleListBean(result.toBaseListBean())
}
}

View File

@@ -0,0 +1,26 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjjManifest
import com.lukouguoji.module_base.common.Constant
/**
* 国际进港舱单详情 ViewModel
*/
class IntImpManifestDetailsViewModel : BaseViewModel() {
// 舱单数据
val dataBean = MutableLiveData(GjjManifest())
/**
* 初始化数据(从列表项携带的数据)
*/
fun initOnCreated(intent: Intent) {
val manifest = intent.getSerializableExtra(Constant.Key.DATA) as? GjjManifest
if (manifest != null) {
dataBean.value = manifest
}
}
}

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