From 2309f454c0e1df3c43fde66002a1d009c0b8f479 Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期二, 01 四月 2025 11:34:35 +0800
Subject: [PATCH] add : 收入逻辑

---
 app/src/main/java/com/example/firstapp/activity/PickupActivity.kt            |   55 ++++
 app/src/main/res/layout/activity_phone_login.xml                             |    2 
 app/src/main/java/com/example/firstapp/model/StationGroup.kt                 |    6 
 app/src/main/java/com/example/firstapp/adapter/IncomeAdapter.kt              |  111 +++++++++++
 app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt |   11 +
 app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt               |  116 ++++++++---
 app/src/main/res/layout/item_income_package_home.xml                         |   47 ++++
 app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt               |   18 +
 app/src/main/res/layout/item_income_group.xml                                |   56 +++++
 app/src/main/res/layout/fragment_home.xml                                    |    3 
 app/src/main/java/com/example/firstapp/model/IncomeGroup.kt                  |   14 +
 app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt              |  158 +++++++--------
 12 files changed, 466 insertions(+), 131 deletions(-)

diff --git a/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt b/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt
index d7dda6d..48a6dc1 100644
--- a/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt
+++ b/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt
@@ -14,11 +14,23 @@
 class PickupActivity : AppCompatActivity() {
     private lateinit var binding: ActivityPickupBinding
     private lateinit var expressAdapter: ExpressPackageAdapter
+    
+    // 添加类型常量
+    companion object {
+        const val TYPE_EXPRESS = "express"
+        const val TYPE_REPAYMENT = "repayment"
+        const val TYPE_INCOME = "income"
+    }
+    
+    private var pageType = TYPE_EXPRESS
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         binding = ActivityPickupBinding.inflate(layoutInflater)
         setContentView(binding.root)
+
+        // 获取页面类型
+        pageType = intent.getStringExtra("page_type") ?: TYPE_EXPRESS
 
         initViews()
         loadData()
@@ -39,17 +51,37 @@
             finish()
         }
 
-        // 修改底部按钮点击事件
-        binding.btnPickupAll.setOnClickListener {
-            showPickupConfirmDialog()
+        // 设置底部按钮文本并添加点击事件
+        binding.btnPickupAll.apply {
+            text = getButtonText()
+            setOnClickListener {
+                showPickupConfirmDialog()
+            }
         }
+    }
 
+    private fun getConfirmMessage(): String {
+        return when (pageType) {
+            TYPE_EXPRESS -> "是否确认取出所有包裹?"
+            TYPE_REPAYMENT -> "是否确认处理所有还款?"
+            TYPE_INCOME -> "是否确认处理所有收入?"
+            else -> "是否确认处理所有项目?"
+        }
+    }
+
+    private fun getButtonText(): String {
+        return when (pageType) {
+            TYPE_EXPRESS -> "全部取件"
+            TYPE_REPAYMENT -> "全部还款"
+            TYPE_INCOME -> "全部收款"
+            else -> "全部处理"
+        }
     }
 
     private fun showPickupConfirmDialog() {
         AlertDialog.Builder(this)
-            .setTitle("确认取件")
-            .setMessage("是否确认取出所有包裹?")
+            .setTitle(getButtonText())
+            .setMessage(getConfirmMessage())
             .setPositiveButton("确认") { _, _ ->
                 handlePickupAll()
             }
@@ -84,7 +116,7 @@
                 // 清空列表
                 expressAdapter.submitList(emptyList())
                 // 更新包裹数量显示
-                binding.tvPackageCount.text = "共0个包裹"
+                binding.tvPackageCount.text = getCountText(0)
                 // 通知MainActivity刷新
                 setResult(RESULT_OK)
             } catch (e: Exception) {
@@ -92,6 +124,15 @@
                 // 如果出错则重新加载数据
                 loadData()
             }
+        }
+    }
+
+    private fun getCountText(count: Int): String {
+        return when (pageType) {
+            TYPE_EXPRESS -> "共${count}个包裹"
+            TYPE_REPAYMENT -> "共${count}笔还款"
+            TYPE_INCOME -> "共${count}笔收入"
+            else -> "共${count}个"
         }
     }
 
@@ -112,7 +153,7 @@
             
             expressAdapter.submitList(packages)
             binding.tvStationName.text = stationName
-            binding.tvPackageCount.text = "共${packages.size}个包裹"
+            binding.tvPackageCount.text = getCountText(packages.size)
         }
     }
 } 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/adapter/IncomeAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/IncomeAdapter.kt
new file mode 100644
index 0000000..856ba45
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/adapter/IncomeAdapter.kt
@@ -0,0 +1,111 @@
+package com.example.firstapp.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.example.firstapp.databinding.ItemIncomeGroupBinding
+import com.example.firstapp.databinding.ItemIncomePackageHomeBinding
+import com.example.firstapp.model.IncomeGroup
+import com.example.firstapp.model.IncomePackage
+
+class IncomeAdapter : ListAdapter<IncomeGroup, IncomeAdapter.ViewHolder>(IncomeGroupDiffCallback()) {
+
+    private var onPackageClickListener: (IncomeGroup, IncomePackage) -> Unit = { _, _ -> }
+
+    fun setOnPackageClickListener(listener: (IncomeGroup, IncomePackage) -> Unit) {
+        onPackageClickListener = listener
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemIncomeGroupBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+        )
+        return ViewHolder(binding)
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val group = getItem(position)
+        holder.bind(group)
+    }
+
+    inner class ViewHolder(private val binding: ItemIncomeGroupBinding) :
+        RecyclerView.ViewHolder(binding.root) {
+        private val packagesAdapter = IncomePackageHomeAdapter { pack ->
+            currentGroup?.let { group ->
+                onPackageClickListener(group, pack)
+            }
+        }
+        private var currentGroup: IncomeGroup? = null
+
+        init {
+            binding.rvPackages.apply {
+                layoutManager = LinearLayoutManager(context)
+                adapter = packagesAdapter
+            }
+        }
+
+        fun bind(group: IncomeGroup) {
+            currentGroup = group
+            binding.tvStationName.text = group.stationName
+            binding.tvPackageCount.text = "共${group.packages.size}笔收入"
+            packagesAdapter.submitList(group.packages)
+        }
+    }
+}
+
+class IncomePackageHomeAdapter(private val onPackageClick: (IncomePackage) -> Unit) :
+    ListAdapter<IncomePackage, IncomePackageHomeAdapter.ViewHolder>(IncomePackageDiffCallback()) {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemIncomePackageHomeBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+        )
+        return ViewHolder(binding)
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val pack = getItem(position)
+        holder.bind(pack)
+    }
+
+    inner class ViewHolder(private val binding: ItemIncomePackageHomeBinding) :
+        RecyclerView.ViewHolder(binding.root) {
+
+        init {
+            binding.root.setOnClickListener {
+                val pack = getItem(adapterPosition)
+                onPackageClick(pack)
+            }
+        }
+
+        fun bind(pack: IncomePackage) {
+            binding.tvCompany.text = pack.company
+            binding.tvCreateTime.text = pack.createTime
+            binding.tvTrackingNumber.text = "¥${pack.trackingNumber}"
+//            binding.tvBalance.text = "余额: ¥${pack.balance}"
+        }
+    }
+}
+
+private class IncomeGroupDiffCallback : DiffUtil.ItemCallback<IncomeGroup>() {
+    override fun areItemsTheSame(oldItem: IncomeGroup, newItem: IncomeGroup): Boolean {
+        return oldItem.stationName == newItem.stationName
+    }
+
+    override fun areContentsTheSame(oldItem: IncomeGroup, newItem: IncomeGroup): Boolean {
+        return oldItem == newItem
+    }
+}
+
+private class IncomePackageDiffCallback : DiffUtil.ItemCallback<IncomePackage>() {
+    override fun areItemsTheSame(oldItem: IncomePackage, newItem: IncomePackage): Boolean {
+        return oldItem.id == newItem.id
+    }
+
+    override fun areContentsTheSame(oldItem: IncomePackage, newItem: IncomePackage): Boolean {
+        return oldItem == newItem
+    }
+} 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
index f79e67a..c494471 100644
--- a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
+++ b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
@@ -10,6 +10,7 @@
 import com.example.firstapp.model.CourierStat
 import com.example.firstapp.model.DailyStat
 import com.example.firstapp.model.HeatmapStat
+import com.example.firstapp.model.StationGroup
 import io.reactivex.Completable
 import kotlinx.coroutines.flow.Flow
 
@@ -261,4 +262,21 @@
     WHERE strftime('%Y', createTime) = strftime('%Y', datetime(:date/1000, 'unixepoch', 'localtime'))
 """)
     fun getCurrentYearStats(date: Long): Flow<List<DailyStat>>
+
+    @Query("""
+        SELECT oneLevel as stationName, COUNT(*) as count
+        FROM Code 
+        WHERE category = :type AND pickup = '0'
+        GROUP BY oneLevel
+        ORDER BY createTime DESC
+    """)
+    fun getStationsByType(type: String): List<StationGroup>
+
+    @Query("""
+        SELECT * FROM Code 
+        WHERE category = :type AND pickup = '0'
+        AND oneLevel = :stationName
+        ORDER BY createTime DESC
+    """)
+    fun getPackagesByTypeAndStation(type: String, stationName: String): List<Code>
 }
diff --git a/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt b/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
index a9352e2..c7ccd88 100644
--- a/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
+++ b/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
@@ -3,6 +3,7 @@
 import androidx.annotation.WorkerThread
 import com.example.firstapp.database.dao.CodeDao
 import com.example.firstapp.database.entity.Code
+import com.example.firstapp.model.StationGroup
 import kotlinx.coroutines.flow.Flow
 
 
@@ -75,4 +76,14 @@
 
     fun getCurrentYearStats(date: Long) = codeDao.getCurrentYearStats(date)
 
+    @WorkerThread
+    fun getStationsByType(type: String): List<StationGroup> {
+        return codeDao.getStationsByType(type)
+    }
+
+    @WorkerThread
+    fun getPackagesByTypeAndStation(type: String, stationName: String): List<Code> {
+        return codeDao.getPackagesByTypeAndStation(type, stationName)
+    }
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/model/IncomeGroup.kt b/app/src/main/java/com/example/firstapp/model/IncomeGroup.kt
new file mode 100644
index 0000000..d76f9f7
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/model/IncomeGroup.kt
@@ -0,0 +1,14 @@
+package com.example.firstapp.model
+
+data class IncomeGroup(
+    val stationName: String,  // 银行名称
+    val packages: List<IncomePackage>
+)
+
+data class IncomePackage(
+    var id: Long,
+    val company: String,    // 交易对方
+    val trackingNumber: String,  // 金额
+    val createTime: String,  // 交易时间
+    val balance: String     // 账户余额
+) 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/model/StationGroup.kt b/app/src/main/java/com/example/firstapp/model/StationGroup.kt
new file mode 100644
index 0000000..c37e008
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/model/StationGroup.kt
@@ -0,0 +1,6 @@
+package com.example.firstapp.model
+
+data class StationGroup(
+    val stationName: String,
+    val count: Int
+) 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
index 72b4b45..0841d30 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
@@ -17,13 +17,17 @@
 import androidx.recyclerview.widget.LinearLayoutManager
 import com.bumptech.glide.Glide
 import com.example.firstapp.R
+import com.example.firstapp.activity.ContentDetailActivity
 import com.example.firstapp.activity.PickupActivity
 import com.example.firstapp.adapter.ExpressAdapter
 import com.example.firstapp.adapter.FinanceAdapter
 import com.example.firstapp.adapter.CategorySelectorAdapter
+import com.example.firstapp.adapter.IncomeAdapter
 import com.example.firstapp.database.service.RetrofitClient
 import com.example.firstapp.databinding.FragmentHomeBinding
 import com.example.firstapp.databinding.DialogCategorySelectorBinding
+import com.example.firstapp.model.IncomeGroup
+import com.example.firstapp.model.IncomePackage
 import com.example.firstapp.utils.PreferencesManager
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import kotlinx.coroutines.launch
@@ -39,7 +43,7 @@
     private lateinit var homeViewModel: HomeViewModel
     private lateinit var expressAdapter: ExpressAdapter
     private lateinit var financeAdapter: FinanceAdapter
-    private lateinit var incomeAdapter: FinanceAdapter
+    private lateinit var incomeAdapter: IncomeAdapter
     private lateinit var flightAdapter: FinanceAdapter
     private lateinit var trainAdapter: FinanceAdapter
     private lateinit var dataUpdateReceiver: BroadcastReceiver
@@ -62,12 +66,11 @@
 //        val userId = getUserId() // 需要实现这个方法
         val userId ="123456"
         homeViewModel.initialize(requireContext(), userId)
-        
-        //调用这个方法来设置 RecyclerView用于设置 RecyclerView 的布局和适配器。
-        setupRecyclerViews()
+
+        // 设置点击监听事件
+        setupAdapters()
         setupTabSwitching()
-        //调用这个方法来观察 ViewModel 中的数据变化
-        observeViewModelData()
+        setupObservers()
         setupCategorySelector()
     }
 
@@ -85,7 +88,7 @@
         }
     }
 
-    private fun setupRecyclerViews() {
+    private fun setupAdapters() {
         binding.expressRecycler.apply {
             layoutManager = LinearLayoutManager(context)
             expressAdapter = ExpressAdapter()
@@ -97,6 +100,7 @@
                 val intent = Intent(requireContext(), PickupActivity::class.java).apply {
                     putExtra("station_name", group.stationName)
                     putExtra("company", pack.company)
+                    putExtra("page_type", PickupActivity.TYPE_EXPRESS)
                 }
                 startActivity(intent)
             }
@@ -117,6 +121,8 @@
                 val intent = Intent(requireContext(), PickupActivity::class.java).apply {
                     putExtra("station_name", group.stationName)
                     putExtra("company", pack.company)
+                    putExtra("page_type", PickupActivity.TYPE_REPAYMENT)
+
                 }
                 startActivity(intent)
             }
@@ -125,9 +131,22 @@
         // 添加新的 RecyclerView
         binding.incomeRecycler.apply {
             layoutManager = LinearLayoutManager(context)
-            incomeAdapter = FinanceAdapter()
+            incomeAdapter = IncomeAdapter()
             adapter = incomeAdapter
-            visibility = View.GONE
+
+            // 设置初始状态 - 添加这行
+            binding.incomeRecycler.visibility = View.GONE
+
+            // 设置点击监听
+            incomeAdapter.setOnPackageClickListener { group, pack ->
+                // 跳转到取件页面
+                val intent = Intent(requireContext(), PickupActivity::class.java).apply {
+                    putExtra("station_name", group.stationName)
+                    putExtra("company", pack.company)
+                    putExtra("page_type", PickupActivity.TYPE_INCOME)
+                }
+                startActivity(intent)
+            }
         }
 
         binding.flightRecycler.apply {
@@ -151,7 +170,7 @@
             tabExpress.setTextColor(ContextCompat.getColor(requireContext(), R.color.tab_selected))
             tabFinance.setTextColor(ContextCompat.getColor(requireContext(), R.color.gray))
 
-            // 快递标签点击事件
+            // 快递标签点击事件 - 快递功能所有用户都可以使用
             tabExpress.setOnClickListener {
                 hideAllRecyclers()
                 expressRecycler.visibility = View.VISIBLE
@@ -159,33 +178,60 @@
                 homeViewModel.loadExpressData()
             }
             
-            // 财务标签点击事件
-            tabFinance.setOnClickListener {
-                hideAllRecyclers()
-                financeRecycler.visibility = View.VISIBLE
-                updateTabStyles(tabFinance)
-                homeViewModel.loadFinanceData()
-            }
+            // 其他标签点击事件需要检查会员状态
+            val memberOnlyTabs = mapOf(
+                tabFinance to { homeViewModel.loadFinanceData() },
+                tabIncome to { homeViewModel.loadIncomeData() },
+                tabFlight to { homeViewModel.loadFlightData() },
+                tabTrain to { homeViewModel.loadTrainData() }
+            )
 
-            tabIncome.setOnClickListener {
-                hideAllRecyclers()
-                incomeRecycler.visibility = View.VISIBLE
-                updateTabStyles(tabIncome)
-                homeViewModel.loadIncomeData()
+            memberOnlyTabs.forEach { (tab, loadAction) ->
+                tab.setOnClickListener {
+                    checkMembershipAndExecute(tab) {
+                        hideAllRecyclers()
+                        when (tab) {
+                            tabFinance -> financeRecycler.visibility = View.VISIBLE
+                            tabIncome -> incomeRecycler.visibility = View.VISIBLE
+                            tabFlight -> flightRecycler.visibility = View.VISIBLE
+                            tabTrain -> trainRecycler.visibility = View.VISIBLE
+                        }
+                        updateTabStyles(tab)
+                        loadAction()
+                    }
+                }
             }
+        }
+    }
 
-            tabFlight.setOnClickListener {
-                hideAllRecyclers()
-                flightRecycler.visibility = View.VISIBLE
-                updateTabStyles(tabFlight)
-                homeViewModel.loadFlightData()
-            }
+    private fun checkMembershipAndExecute(tab: TextView, action: () -> Unit) {
+        // 从本地获取保存的手机号
+        val savedPhone = PreferencesManager.getPhone()
+        if (savedPhone.isNullOrEmpty()) {
+            Toast.makeText(requireContext(), "请先登录", Toast.LENGTH_SHORT).show()
+            return
+        }
 
-            tabTrain.setOnClickListener {
-                hideAllRecyclers()
-                trainRecycler.visibility = View.VISIBLE
-                updateTabStyles(tabTrain)
-                homeViewModel.loadTrainData()
+        // 使用协程检查会员状态
+        lifecycleScope.launch {
+            try {
+                val response = RetrofitClient.apiService.getUserInfo(savedPhone)
+                if (response.code == "0" && response.data != null) {
+                    if (response.data.isMember) {
+                        action()
+                    } else {
+                        Toast.makeText(requireContext(), "该功能仅对会员开放", Toast.LENGTH_SHORT).show()
+                        // 切回快递标签
+                        binding.tabExpress.performClick()
+                    }
+                } else {
+                    Toast.makeText(requireContext(), "获取用户信息失败", Toast.LENGTH_SHORT).show()
+                    binding.tabExpress.performClick()
+                }
+            } catch (e: Exception) {
+                e.printStackTrace()
+                Toast.makeText(requireContext(), "网络错误,请稍后重试", Toast.LENGTH_SHORT).show()
+                binding.tabExpress.performClick()
             }
         }
     }
@@ -211,8 +257,7 @@
         }
     }
 
-    //这个方法用于观察 homeViewModel 中的 expressItems 数据。
-    private fun observeViewModelData() {
+    private fun setupObservers() {
         //当 expressItems 数据发生变化时,更新 RecyclerView 的数据。
         homeViewModel.expressItems.observe(viewLifecycleOwner) { items ->
             //将新的数据列表提交给适配器,以更新 RecyclerView 的显示内容。
@@ -223,6 +268,7 @@
             financeAdapter.submitList(items)
         }
 
+        // 观察收入数据变化
         homeViewModel.incomeItems.observe(viewLifecycleOwner) { items ->
             incomeAdapter.submitList(items)
         }
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
index d8c92f2..f915575 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
@@ -14,6 +14,8 @@
 import com.example.firstapp.model.ExpressPackage
 import com.example.firstapp.model.FinanceGroup
 import com.example.firstapp.model.FinancePackage
+import com.example.firstapp.model.IncomeGroup
+import com.example.firstapp.model.IncomePackage
 import com.example.firstapp.util.SecureStorage
 import kotlinx.coroutines.launch
 
@@ -21,13 +23,13 @@
 
     private val _expressItems = MutableLiveData<List<ExpressGroup>>()
     private val _financeItems = MutableLiveData<List<FinanceGroup>>()
-    private val _incomeItems = MutableLiveData<List<FinanceGroup>>()
+    private val _incomeItems = MutableLiveData<List<IncomeGroup>>()
     private val _flightItems = MutableLiveData<List<FinanceGroup>>()
     private val _trainItems = MutableLiveData<List<FinanceGroup>>()
     
     val expressItems: LiveData<List<ExpressGroup>> = _expressItems
     val financeItems: LiveData<List<FinanceGroup>> = _financeItems
-    val incomeItems: LiveData<List<FinanceGroup>> = _incomeItems
+    val incomeItems: LiveData<List<IncomeGroup>> = _incomeItems
     val flightItems: LiveData<List<FinanceGroup>> = _flightItems
     val trainItems: LiveData<List<FinanceGroup>> = _trainItems
 
@@ -56,106 +58,90 @@
         _categories.value?.let { updateVisibleCategories(it) }
     }
 
-    fun loadExpressData() {
+    private fun loadDataByType(type: String) {
         viewModelScope.launch {
-            // 1. 获取所有驿站类型的提醒设置
-            val stations = Core.reminder.getByType("快递")
-
-            // 2. 按驿站分组获取包裹信息
-            val groups = stations.map { station ->
-                val packages = Core.code.getByKeyword(station.nickname).map { code ->
-                    ExpressPackage(
-                        id = code.id, //ID
-                        company = code.secondLevel, //快递公司
-                        trackingNumber = code.code, // 取件码
-                        createTime = code.createTime  //快递时间
-                    )
+            try {
+                // 获取该类型下的所有站点分组
+                val stations = Core.code.getStationsByType(type)
+                
+                when (type) {
+                    "快递" -> {
+                        // 处理快递类型
+                        val groups = stations.map { station ->
+                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
+                                ExpressPackage(
+                                    id = code.id,
+                                    company = code.secondLevel,
+                                    trackingNumber = code.code,
+                                    createTime = code.createTime
+                                )
+                            }
+                            ExpressGroup(stationName = station.stationName, packages = packages)
+                        }
+                        _expressItems.postValue(groups)
+                    }
+                    "收入" -> {
+                        // 特殊处理收入类型
+                        val groups = stations.map { station ->
+                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
+                                IncomePackage(
+                                    id = code.id,
+                                    company = code.secondLevel,  // 交易对方
+                                    trackingNumber = code.code,  // 金额
+                                    createTime = code.createTime,
+                                    balance = code.remarks.replace("余额", "") // 去掉"余额"前缀
+                                )
+                            }
+                            IncomeGroup(stationName = station.stationName, packages = packages)
+                        }
+                        _incomeItems.postValue(groups)
+                    }
+                    else -> {
+                        // 处理其他类型(还款、航班、火车票)
+                        val groups = stations.map { station ->
+                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
+                                FinancePackage(
+                                    id = code.id,
+                                    company = code.secondLevel,
+                                    trackingNumber = code.code,
+                                    createTime = code.createTime
+                                )
+                            }
+                            FinanceGroup(stationName = station.stationName, packages = packages)
+                        }
+                        
+                        // 根据类型更新对应的 LiveData
+                        when (type) {
+                            "还款" -> _financeItems.postValue(groups)
+                            "航班" -> _flightItems.postValue(groups)
+                            "火车票" -> _trainItems.postValue(groups)
+                        }
+                    }
                 }
-                ExpressGroup(
-                    stationName = station.nickname, packages = packages
-                )
+            } catch (e: Exception) {
+                Log.e("HomeViewModel", "Failed to load $type data: ${e.message}")
             }
-
-            _expressItems.postValue(groups)
         }
+    }
+
+    fun loadExpressData() {
+        loadDataByType("快递")
     }
 
     fun loadFinanceData() {
-        viewModelScope.launch {
-            // 1. 获取所有驿站类型的提醒设置
-            val stations = Core.reminder.getByType("还款")
-
-            // 2. 按驿站分组获取包裹信息
-            val groups = stations.map { station ->
-                val packages = Core.code.getByKeyword(station.nickname).map { code ->
-                    FinancePackage(
-                        id = code.id, //ID
-                        company = code.secondLevel, //快递公司
-                        trackingNumber = code.code, // 取件码
-                        createTime = code.createTime  //快递时间
-                    )
-                }
-                FinanceGroup(
-                    stationName = station.nickname, packages = packages
-                )
-            }
-
-            _financeItems.postValue(groups)
-        }
+        loadDataByType("还款")
     }
 
     fun loadIncomeData() {
-        viewModelScope.launch {
-            val stations = Core.reminder.getByType("收入")
-            val groups = stations.map { station ->
-                val packages = Core.code.getByKeyword(station.nickname).map { code ->
-                    FinancePackage(
-                        id = code.id,
-                        company = code.secondLevel,
-                        trackingNumber = code.code,
-                        createTime = code.createTime
-                    )
-                }
-                FinanceGroup(stationName = station.nickname, packages = packages)
-            }
-            _incomeItems.postValue(groups)
-        }
+        loadDataByType("收入")
     }
 
     fun loadFlightData() {
-        viewModelScope.launch {
-            val stations = Core.reminder.getByType("航班")
-            val groups = stations.map { station ->
-                val packages = Core.code.getByKeyword(station.nickname).map { code ->
-                    FinancePackage(
-                        id = code.id,
-                        company = code.secondLevel,
-                        trackingNumber = code.code,
-                        createTime = code.createTime
-                    )
-                }
-                FinanceGroup(stationName = station.nickname, packages = packages)
-            }
-            _flightItems.postValue(groups)
-        }
+        loadDataByType("航班")
     }
 
     fun loadTrainData() {
-        viewModelScope.launch {
-            val stations = Core.reminder.getByType("火车票")
-            val groups = stations.map { station ->
-                val packages = Core.code.getByKeyword(station.nickname).map { code ->
-                    FinancePackage(
-                        id = code.id,
-                        company = code.secondLevel,
-                        trackingNumber = code.code,
-                        createTime = code.createTime
-                    )
-                }
-                FinanceGroup(stationName = station.nickname, packages = packages)
-            }
-            _trainItems.postValue(groups)
-        }
+        loadDataByType("火车票")
     }
 
     fun loadCategories() {
diff --git a/app/src/main/res/layout/activity_phone_login.xml b/app/src/main/res/layout/activity_phone_login.xml
index 757b041..74d5644 100644
--- a/app/src/main/res/layout/activity_phone_login.xml
+++ b/app/src/main/res/layout/activity_phone_login.xml
@@ -43,7 +43,7 @@
             android:layout_height="wrap_content"
             android:background="@null"
             android:hint="请输入手机号"
-            android:text="17712345678"
+            android:text="15288241342"
             android:inputType="phone"
             android:maxLength="11"
             android:textSize="16sp"
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 17014a8..8fbd422 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -119,8 +119,7 @@
                     android:id="@+id/income_recycler"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:padding="8dp"
-                    android:visibility="gone" />
+                    android:padding="8dp" />
 
                 <androidx.recyclerview.widget.RecyclerView
                     android:id="@+id/flight_recycler"
diff --git a/app/src/main/res/layout/item_income_group.xml b/app/src/main/res/layout/item_income_group.xml
new file mode 100644
index 0000000..6ae5c47
--- /dev/null
+++ b/app/src/main/res/layout/item_income_group.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.material.card.MaterialCardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginHorizontal="12dp"
+    android:layout_marginVertical="6dp"
+    app:cardCornerRadius="8dp"
+    app:cardElevation="2dp"
+    app:cardBackgroundColor="@android:color/white"
+    app:strokeColor="#FF000000"
+    app:strokeWidth="2dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:padding="16dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginBottom="12dp">
+
+            <ImageView
+                android:id="@+id/iv_station_icon"
+                android:layout_width="20dp"
+                android:layout_height="20dp"
+                android:layout_gravity="center_vertical"
+                android:src="@drawable/location"/>
+
+            <TextView
+                android:id="@+id/tv_station_name"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginStart="8dp"
+                android:textSize="16sp"
+                android:textColor="#333333"/>
+
+            <TextView
+                android:id="@+id/tv_package_count"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="14sp"
+                android:textColor="#666666"/>
+        </LinearLayout>
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/rv_packages"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</com.google.android.material.card.MaterialCardView> 
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_income_package_home.xml b/app/src/main/res/layout/item_income_package_home.xml
new file mode 100644
index 0000000..ef12f23
--- /dev/null
+++ b/app/src/main/res/layout/item_income_package_home.xml
@@ -0,0 +1,47 @@
+<?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:padding="12dp"
+    android:gravity="center_vertical">
+
+    <ImageView
+        android:id="@+id/iv_company_logo"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:layout_marginEnd="6dp"/>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_company"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="12sp"
+            android:textColor="#333333"
+            android:textStyle="bold"/>
+
+        <TextView
+            android:id="@+id/tv_create_time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="10sp"
+            android:textColor="#666666"
+            android:layout_marginTop="4dp"/>
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/tv_tracking_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="25sp"
+        android:textColor="#333333"
+        android:layout_marginStart="12dp"
+        android:textStyle="bold"/>
+
+</LinearLayout> 
\ No newline at end of file

--
Gitblit v1.9.3