diff --git a/.claude/settings.local.json b/.claude/settings.local.json index cced56b..2a2ef82 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -32,7 +32,10 @@ "Bash(adb:*)", "Bash(emulator:*)", "Bash(logcat:*)", - "Bash(grep:*)" + "Bash(grep:*)", + "Bash(sort:*)", + "Bash(ls:*)", + "Bash(xargs rm:*)" ], "deny": [], "ask": [] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 832d433..ca895f0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -104,6 +104,11 @@ android:configChanges="orientation|keyboardHidden" android:exported="false" android:screenOrientation="userLandscape" /> + { + ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_GJC_ASSEMBLE_ALLOCATE) + .navigation() + } /** * 国际进港 */ @@ -640,6 +645,14 @@ class HomeFragment : Fragment() { ) ) + list.add( + RightMenu( + Constant.AuthName.GjcAssembleAllocateActivity, + com.lukouguoji.module_base.R.drawable.img_gjc_banxiangzuzhuang, + "组装分配" + ) + ) + // list.add( // RightMenu( // Constant.AuthName.GjcWareHouseActivity, diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcAssembleAllocate.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcAssembleAllocate.kt new file mode 100644 index 0000000..da94c4d --- /dev/null +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcAssembleAllocate.kt @@ -0,0 +1,30 @@ +package com.lukouguoji.module_base.bean + +import androidx.databinding.ObservableBoolean +import com.lukouguoji.module_base.interfaces.ICheck + +/** + * 国际出港组装分配Bean + */ +data class GjcAssembleAllocate( + val abDate: String? = null, // 组装时间 + val abName: String? = null, // 组装公司(中文) + val abid: String? = null, // 组装公司ID + val acDate: String? = null, // 分配时间 + val acName: String? = null, // 分配人(中文) + val acid: String? = null, // 分配人ID + val fdate: String? = null, // 航班日期 + val fdep: String? = null, // 始发站 + val fdest: String? = null, // 目的站 + val fid: Long? = null, // 航班id + val fidList: List? = null, // 航班fid列表 + val fno: String? = null, // 航班号 + val id: Long? = null, // 主键 + val jtz: String? = null, // 经停站 + val range: String? = null, // 航程 + + // 用于UI的可观察选中状态 + val checked: ObservableBoolean = ObservableBoolean(false) +) : ICheck { + override fun getCheckObservable(): ObservableBoolean = checked +} diff --git a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt index 0d4a039..33a39d8 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt @@ -245,6 +245,7 @@ interface Constant { const val GjcGoodsListActivity = "AppIntExpGoods" //货物交接 const val GjcInspectionActivity = "AppIntExpInspection" //收运检查 const val GjcIntExpAssembleActivity = "AppIntExpAssemble" //出港组装 + const val GjcAssembleAllocateActivity = "AppIntExpAssembleAllocate" //组装分配 /** * 国际进港 diff --git a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt index 90c0f80..9e4c0ef 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt @@ -1,7 +1,6 @@ //package com.lukouguoji.module_base.http.net package com.lukouguoji.module_base.http.net -import com.alibaba.fastjson.JSONObject import com.lukouguoji.module_base.bean.AccidentVisaBean import com.lukouguoji.module_base.bean.AirportBean import com.lukouguoji.module_base.bean.AppUpdateResponse @@ -19,6 +18,7 @@ import com.lukouguoji.module_base.bean.FlatcarBean import com.lukouguoji.module_base.bean.FlightBean import com.lukouguoji.module_base.bean.FlightFilterBean import com.lukouguoji.module_base.bean.GbCarOrUldBean +import com.lukouguoji.module_base.bean.GjcAssembleAllocate import com.lukouguoji.module_base.bean.GjcBoxAddInsertBean import com.lukouguoji.module_base.bean.GjcBoxAssembleBean import com.lukouguoji.module_base.bean.GjcBoxDetailsBean @@ -27,6 +27,8 @@ import com.lukouguoji.module_base.bean.GjcCheckInRecord import com.lukouguoji.module_base.bean.GjcGoodsAddBean import com.lukouguoji.module_base.bean.GjcGoodsBean import com.lukouguoji.module_base.bean.GjcGoodsDetailsBean +import com.lukouguoji.module_base.bean.GjcInspectionBean +import com.lukouguoji.module_base.bean.GjcMaWb import com.lukouguoji.module_base.bean.GjcMove import com.lukouguoji.module_base.bean.GjcUldUseBean import com.lukouguoji.module_base.bean.GjcWarehouse @@ -35,8 +37,6 @@ import com.lukouguoji.module_base.bean.GjcWaybillDataBean import com.lukouguoji.module_base.bean.GjcWeighingBean import com.lukouguoji.module_base.bean.GjcWeighingRecordBean import com.lukouguoji.module_base.bean.GjcWeighingStatisticsBean -import com.lukouguoji.module_base.bean.GjcMaWb -import com.lukouguoji.module_base.bean.PageInfo import com.lukouguoji.module_base.bean.GjjGoodsBean import com.lukouguoji.module_base.bean.GjjGoodsDetailsBean import com.lukouguoji.module_base.bean.GjjGoodsTypeBean @@ -45,15 +45,11 @@ import com.lukouguoji.module_base.bean.GjjManifestBean import com.lukouguoji.module_base.bean.GjjPackTypeBean import com.lukouguoji.module_base.bean.GjjTallyBean import com.lukouguoji.module_base.bean.GjjTallyDetailsBean -import com.lukouguoji.module_base.bean.JianDataBean -import com.lukouguoji.module_base.bean.PacketParseBean import com.lukouguoji.module_base.bean.GjjTallyRecordBean import com.lukouguoji.module_base.bean.GncAssembleListBean import com.lukouguoji.module_base.bean.GncCunFangBean import com.lukouguoji.module_base.bean.GncDistributionBean import com.lukouguoji.module_base.bean.GncFuBangBean -import com.lukouguoji.module_base.bean.GjcInspectionBean -import com.lukouguoji.module_base.bean.ManifestTotalDto import com.lukouguoji.module_base.bean.GncInspectionBean import com.lukouguoji.module_base.bean.GncQueryBean import com.lukouguoji.module_base.bean.GncQueryDetailsBean @@ -67,10 +63,14 @@ import com.lukouguoji.module_base.bean.GnjStashBean import com.lukouguoji.module_base.bean.GnjUnloadListBean 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.ManifestTotalDto import com.lukouguoji.module_base.bean.MessageBean import com.lukouguoji.module_base.bean.MoveStashBean import com.lukouguoji.module_base.bean.PackageBean +import com.lukouguoji.module_base.bean.PacketParseBean +import com.lukouguoji.module_base.bean.PageInfo import com.lukouguoji.module_base.bean.SYWaybillBean import com.lukouguoji.module_base.bean.ShouYunSyncBean import com.lukouguoji.module_base.bean.SimpleResultBean @@ -86,7 +86,6 @@ import com.lukouguoji.module_base.ktx.toRequestBody import okhttp3.MultipartBody import okhttp3.RequestBody import okhttp3.ResponseBody -import retrofit2.Call import retrofit2.http.* /** @@ -448,6 +447,27 @@ interface Api { @POST("IntExpSearch/detail") suspend fun getGjcQueryDetails(@Query("maWbId") maWbId: Long): BaseResultBean> + /** + * 国际出港组装分配-分页查询 + * 接口路径: /IntExpAssemble/allocate/pageQuery + */ + @POST("IntExpAssemble/allocate/pageQuery") + suspend fun getGjcAssembleAllocateList(@Body params: RequestBody): BaseResultBean> + + /** + * 国际出港组装分配-分页合计统计 + * 接口路径: /IntExpAssemble/allocate/pageQueryTotal + */ + @POST("IntExpAssemble/allocate/pageQueryTotal") + suspend fun getGjcAssembleAllocateTotal(@Body params: RequestBody): BaseResultBean + + /** + * 国际出港组装分配-执行分配操作 + * 接口路径: /IntExpAssemble/allocate + */ + @POST("IntExpAssemble/allocate") + suspend fun allocateAssemble(@Body params: RequestBody): BaseResultBean + /** * 国际出港板箱过磅-分页搜索 * 接口路径: /IntExpWeighting/pageQuery diff --git a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt index e4f47d3..70ad383 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt @@ -141,6 +141,7 @@ object ARouterConstants { const val ACTIVITY_URL_INT_EXP_ASSEMBLE = "/gjc/IntExpAssembleActivity" //国际出港 出港组装 const val ACTIVITY_URL_INT_EXP_ASSEMBLE_START = "/gjc/IntExpAssembleStartActivity" //国际出港 开始组装 const val ACTIVITY_URL_INT_EXP_MOVE = "/gjc/IntExpMoveActivity" //国际出港 出港移库 + const val ACTIVITY_URL_GJC_ASSEMBLE_ALLOCATE = "/gjc/GjcAssembleAllocateActivity" //国际出港 组装分配 ///////////////// 国际进港模块 /** diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcAssembleAllocateActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcAssembleAllocateActivity.kt new file mode 100644 index 0000000..b0510f4 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcAssembleAllocateActivity.kt @@ -0,0 +1,66 @@ +package com.lukouguoji.gjc.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.alibaba.android.arouter.facade.annotation.Route +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.databinding.ActivityGjcAssembleAllocateBinding +import com.lukouguoji.gjc.viewModel.GjcAssembleAllocateViewModel +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.getLifecycleOwner +import com.lukouguoji.module_base.router.ARouterConstants + +/** + * 国际出港组装分配列表页 + */ +@Route(path = ARouterConstants.ACTIVITY_URL_GJC_ASSEMBLE_ALLOCATE) +class GjcAssembleAllocateActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_gjc_assemble_allocate + + override fun viewModelClass() = GjcAssembleAllocateViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("组装分配") + + binding.viewModel = viewModel + + // 绑定分页逻辑 + viewModel.pageModel + .bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner()) + + // 监听刷新事件 + FlowBus.with(ConstantEvent.EVENT_REFRESH) + .observe(this) { + viewModel.refresh() + } + + // 监听checkbox状态变化事件 + FlowBus.with(ConstantEvent.EVENT_CHECK_CHANGED) + .observe(this) { + viewModel.onItemCheckChanged() + } + + // 监听全选状态变化,更新图标 + viewModel.isAllChecked.observe(this) { isAllChecked -> + // 通过alpha值表示全选状态:全选时alpha=1.0,未全选时alpha=0.5 + binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f + } + + // 初始加载 + viewModel.refresh() + } + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, GjcAssembleAllocateActivity::class.java) + context.startActivity(starter) + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/GjcAssembleAllocateViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/GjcAssembleAllocateViewHolder.kt new file mode 100644 index 0000000..bfdcd3f --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/GjcAssembleAllocateViewHolder.kt @@ -0,0 +1,26 @@ +package com.lukouguoji.gjc.holder + +import android.view.View +import com.lukouguoji.gjc.databinding.ItemGjcAssembleAllocateBinding +import com.lukouguoji.module_base.base.BaseViewHolder +import com.lukouguoji.module_base.bean.GjcAssembleAllocate + +/** + * 国际出港组装分配列表ViewHolder + */ +class GjcAssembleAllocateViewHolder(view: View) : + BaseViewHolder(view) { + + override fun onBind(item: Any?, position: Int) { + val bean = getItemBean(item) ?: return + binding.bean = bean + binding.executePendingBindings() + + // 选中图标点击事件 + binding.ivIcon.setOnClickListener { + bean.checked.set(!bean.checked.get()) + // 通知adapter刷新item + binding.executePendingBindings() + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleAllocateViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleAllocateViewModel.kt new file mode 100644 index 0000000..0482993 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleAllocateViewModel.kt @@ -0,0 +1,195 @@ +package com.lukouguoji.gjc.viewModel + +import android.app.AlertDialog +import android.widget.EditText +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.holder.GjcAssembleAllocateViewHolder +import com.lukouguoji.module_base.base.BasePageViewModel +import com.lukouguoji.module_base.bean.GjcAssembleAllocate +import com.lukouguoji.module_base.common.ConstantEvent +import com.lukouguoji.module_base.http.net.NetApply +import com.lukouguoji.module_base.impl.FlowBus +import com.lukouguoji.module_base.ktx.commonAdapter +import com.lukouguoji.module_base.ktx.launchCollect +import com.lukouguoji.module_base.ktx.launchLoadingCollect +import com.lukouguoji.module_base.ktx.showToast +import com.lukouguoji.module_base.ktx.toRequestBody +import com.lukouguoji.module_base.util.CheckUtil +import kotlinx.coroutines.launch + +/** + * 国际出港组装分配 ViewModel + */ +class GjcAssembleAllocateViewModel : BasePageViewModel() { + + // 搜索条件 + val flightDate = MutableLiveData("") // 航班日期 + val flightNo = MutableLiveData("") // 航班号 + val destAirport = MutableLiveData("") // 目的站 + val assembler = MutableLiveData("") // 组装人 + val allocator = MutableLiveData("") // 分配人 + + // 适配器配置 + val itemViewHolder = GjcAssembleAllocateViewHolder::class.java + val itemLayoutId = R.layout.item_gjc_assemble_allocate + + // 统计数据 + val totalCount = MutableLiveData("0") // 合计票数 + val totalPc = MutableLiveData("0") // 总件数 + val totalWeight = MutableLiveData("0") // 总重量 + + // 全选状态 + val isAllChecked = MutableLiveData(false) + + /////////////////////////////////////////////////////////////////////////// + // 方法区 + /////////////////////////////////////////////////////////////////////////// + + /** + * 搜索按钮点击 + */ + fun searchClick() { + refresh() + } + + /** + * 获取列表数据 + */ + override fun getData() { + // 构建查询参数(列表接口) + val listParams = mapOf( + "page" to pageModel.page, + "limit" to pageModel.limit, + "fdate" to flightDate.value!!.ifEmpty { null }, + "fno" to flightNo.value!!.ifEmpty { null }, + "dest" to destAirport.value!!.ifEmpty { null }, + "abId" to assembler.value!!.ifEmpty { null }, + "acName" to allocator.value!!.ifEmpty { null } + ).toRequestBody() + + // 构建查询参数(统计接口 - 使用相同的搜索条件) + val totalParams = mapOf( + "fdate" to flightDate.value!!.ifEmpty { null }, + "fno" to flightNo.value!!.ifEmpty { null }, + "dest" to destAirport.value!!.ifEmpty { null }, + "abId" to assembler.value!!.ifEmpty { null }, + "acName" to allocator.value!!.ifEmpty { null } + ).toRequestBody() + + // 获取列表数据(显示loading) + launchLoadingCollect({ + NetApply.api.getGjcAssembleAllocateList(listParams) + }) { + onSuccess = { result -> + // 将 PageInfo 转换为 BaseListBean + result.data?.let { pageModel.handleListBean(it.toBaseListBean()) } + } + } + + // 获取统计数据(后台调用,不显示loading) + launchCollect({ + NetApply.api.getGjcAssembleAllocateTotal(totalParams) + }) { + onSuccess = { result -> + val data = result.data + totalCount.value = (data?.wbNumber ?: 0).toString() + totalPc.value = (data?.totalPc ?: 0).toString() + totalWeight.value = (data?.totalWeight ?: 0.0).toString() + } + } + } + + /** + * 全选/全不选 + */ + fun checkAllClick() { + val list = pageModel.rv!!.commonAdapter()!!.items as List + CheckUtil.handleAllCheck(list) + updateCheckAllStatus() + } + + /** + * 更新全选状态 + */ + fun updateCheckAllStatus() { + val list = pageModel.rv?.commonAdapter()?.items as? List + if (list != null && list.isNotEmpty()) { + isAllChecked.value = list.all { it.checked.get() } + } else { + isAllChecked.value = false + } + } + + /** + * 单个item点击事件(用于更新全选状态) + */ + fun onItemCheckChanged() { + updateCheckAllStatus() + } + + /** + * 分配按钮点击 + */ + fun allocateClick() { + val list = pageModel.rv!!.commonAdapter()!!.items as List + val selectedItems = list.filter { it.checked.get() } + + if (selectedItems.isEmpty()) { + showToast("请选择要分配的航班") + return + } + + // 显示分配人输入对话框 + showAllocatorInputDialog(selectedItems) + } + + /** + * 显示分配人输入对话框 + */ + private fun showAllocatorInputDialog(items: List) { + val activity = getTopActivity() + val editText = EditText(activity) + editText.hint = "请输入分配人姓名" + + AlertDialog.Builder(activity) + .setTitle("分配人员") + .setView(editText) + .setPositiveButton("确定") { dialog, _ -> + val allocatorName = editText.text.toString().trim() + if (allocatorName.isEmpty()) { + showToast("请输入分配人姓名") + } else { + performAllocate(items, allocatorName) + dialog.dismiss() + } + } + .setNegativeButton("取消") { dialog, _ -> + dialog.dismiss() + } + .show() + } + + /** + * 执行分配操作 + */ + private fun performAllocate(items: List, allocatorName: String) { + val fidList = items.mapNotNull { it.fid } + + val requestData = mapOf( + "fidList" to fidList, // 航班ID列表 + "acName" to allocatorName // 分配人姓名 + ).toRequestBody() + + launchLoadingCollect({ NetApply.api.allocateAssemble(requestData) }) { + onSuccess = { + showToast("分配成功") + viewModelScope.launch { + FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() + } + } + } +} diff --git a/module_gjc/src/main/res/layout/activity_gjc_assemble_allocate.xml b/module_gjc/src/main/res/layout/activity_gjc_assemble_allocate.xml new file mode 100644 index 0000000..8014fc9 --- /dev/null +++ b/module_gjc/src/main/res/layout/activity_gjc_assemble_allocate.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_gjc_assemble_allocate.xml b/module_gjc/src/main/res/layout/item_gjc_assemble_allocate.xml new file mode 100644 index 0000000..c5731ea --- /dev/null +++ b/module_gjc/src/main/res/layout/item_gjc_assemble_allocate.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +