cloudroam
2025-04-16 ca8bc638ba9cbca3f5f6a4d497d45f92e70064f3
add: 火车票和航班处理
已修改7个文件
已添加10个文件
1031 ■■■■■ 文件已修改
app/src/main/java/com/example/firstapp/MainActivity.kt 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/activity/PickupActivity.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/model/FlightGroup.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/model/TrainGroup.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_phone_login.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_flight.xml 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_flight_group.xml 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_flight_package_home.xml 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_train.xml 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_train_group.xml 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_train_package_home.xml 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/firstapp/MainActivity.kt
@@ -44,8 +44,7 @@
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            when {
                permissions.getOrDefault(
                    Manifest.permission.RECEIVE_SMS,
                    false
                    Manifest.permission.RECEIVE_SMS, false
                ) && permissions.getOrDefault(Manifest.permission.READ_SMS, false) -> {
                    // 两个权限都获得授权
                    registerSmsReceiver()
@@ -77,7 +76,7 @@
        // 重置提醒计划并检查是否有错过的提醒
        resetReminders()
        // 检查权限
        if (ContextCompat.checkSelfPermission(
                this, Manifest.permission.RECEIVE_SMS
@@ -174,7 +173,7 @@
                while (cursor.moveToNext()) {
                    val messageBody = cursor.getString(cursor.getColumnIndexOrThrow("body"))
                    val datetime = cursor.getLong(cursor.getColumnIndexOrThrow("date"))
                    // 转换为 Date 对象
                    val date = Date(datetime)
                    val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
@@ -193,19 +192,21 @@
                    // 使用协程处理API调用和数据库操作
                    CoroutineScope(Dispatchers.IO).launch {
                        try {
                            val response = RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody))
                            val response =
                                RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody))
                            synchronized(syncLock) {
                                if (response.status == "success") {
                                    when (response.data.category) {
                                        "快递" -> {
                                            val pickupCode = response.data.details.pickupCode ?: ""
                                            if (pickupCode.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    pickupCode,
                                                    dateString
                                                )
                                                val existingCode =
                                                    Core.code.queryByTypeAndCodeAndDate(
                                                        response.data.category,
                                                        pickupCode,
                                                        dateString
                                                    )
                                                if (existingCode == null) {
                                                    val code = Code(
@@ -217,32 +218,40 @@
                                                        msgId = msgId,
                                                        createTime = dateString,
                                                        oneLevel = response.data.details.post ?: "",
                                                        secondLevel = response.data.details.company ?: "",
                                                        secondLevel = response.data.details.company
                                                            ?: "",
                                                        code = pickupCode,
                                                        pickup = 0,
                                                        pickupTime = "",
                                                        overTime = "",
                                                        address = response.data.details.address ?: "",
                                                        address = response.data.details.address
                                                            ?: "",
                                                        remarks = response.data.details.time ?: "",
                                                    )
//                                                    if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                    if(code.oneLevel.isNotEmpty()  && code.code.isNotEmpty()) {
                                                    if (code.oneLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史快递短信已保存: $pickupCode")
                                                        android.util.Log.d(
                                                            "MainActivity",
                                                            "历史快递短信已保存: $pickupCode"
                                                        )
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复快递短信,跳过保存: $pickupCode")
                                                    android.util.Log.d(
                                                        "MainActivity",
                                                        "发现重复快递短信,跳过保存: $pickupCode"
                                                    )
                                                }
                                            }
                                        }
                                        "还款" -> {
                                            val amount = response.data.details.amount ?: ""
                                            if (amount.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    amount,
                                                    dateString
                                                )
                                                val existingCode =
                                                    Core.code.queryByTypeAndCodeAndDate(
                                                        response.data.category, amount, dateString
                                                    )
                                                if (existingCode == null) {
                                                    val code = Code(
@@ -254,31 +263,39 @@
                                                        msgId = msgId,
                                                        createTime = dateString,
                                                        oneLevel = response.data.details.type ?: "",
                                                        secondLevel = response.data.details.bank ?: "",
                                                        secondLevel = response.data.details.bank
                                                            ?: "",
                                                        code = amount,
                                                        pickup = 0,
                                                        pickupTime = "",
                                                        overTime = response.data.details.date ?: "",
                                                        address = response.data.details.address ?: "",
                                                        address = response.data.details.address
                                                            ?: "",
                                                        remarks = "最小还款金额${response.data.details.min_amount}还款卡号${response.data.details.number}"
                                                    )
                                                    if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                    if (code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史还款短信已保存: $amount")
                                                        android.util.Log.d(
                                                            "MainActivity",
                                                            "历史还款短信已保存: $amount"
                                                        )
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount")
                                                    android.util.Log.d(
                                                        "MainActivity",
                                                        "发现重复还款短信,跳过保存: $amount"
                                                    )
                                                }
                                            }
                                        }
                                        "收入" -> {
                                            val amount = response.data.details.amount ?: ""
                                            if (amount.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    amount,
                                                    dateString
                                                )
                                                val existingCode =
                                                    Core.code.queryByTypeAndCodeAndDate(
                                                        response.data.category, amount, dateString
                                                    )
                                                if (existingCode == null) {
                                                    val code = Code(
@@ -290,21 +307,114 @@
                                                        msgId = msgId,
                                                        createTime = dateString,
                                                        oneLevel = response.data.details.bank ?: "",
                                                        secondLevel = response.data.details.bank ?: "",
                                                        secondLevel = response.data.details.bank
                                                            ?: "",
                                                        code = amount,
                                                        pickup = 0, // 0-未取件,1-已取件
                                                        pickupTime = "", // 取件时间为空
                                                        overTime = response.data.details.datetime
                                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                                        address = response.data.details.address ?: "",
                                                        remarks = "余额" + response.data.details.balance ?: "",
                                                        address = response.data.details.address
                                                            ?: "",
                                                        remarks = "余额" + response.data.details.balance
                                                            ?: "",
                                                    )
                                                    if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                    if (code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史还款短信已保存: $amount")
                                                        android.util.Log.d(
                                                            "MainActivity",
                                                            "历史还款短信已保存: $amount"
                                                        )
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount")
                                                    android.util.Log.d(
                                                        "MainActivity",
                                                        "发现重复还款短信,跳过保存: $amount"
                                                    )
                                                }
                                            }
                                        }
                                        "航班" -> {
                                            val flight = response.data.details.flight ?: ""
                                            if (flight.isNotEmpty()) {
                                                val existingCode =
                                                    Core.code.queryByTypeAndCodeAndDate(
                                                        response.data.category, flight, dateString
                                                    )
                                                if (existingCode == null) {
                                                    val code = Code(
                                                        id = 0,
                                                        category = response.data.category,
                                                        categoryId = 4, // 4-航班类型
                                                        typeId = 1,     //暂时没有根据type分类
                                                        ruleId = 2,     //1-还款类型
                                                        msgId = msgId,
                                                        createTime = dateString,
                                                        oneLevel = response.data.details.company
                                                            ?: "",
                                                        secondLevel = response.data.details.start + response.data.details.end
                                                            ?: "",
                                                        code = flight,
                                                        pickup = 0, // 0-未取件,1-已取件
                                                        pickupTime = "", // 取件时间为空
                                                        overTime = response.data.details.time
                                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                                        address = response.data.details.address
                                                            ?: "",
                                                        remarks = response.data.details.seat ?: "",
                                                    )
                                                    if (code.oneLevel != "" && code.secondLevel != "" && code.code != "") {
                                                        Core.code.insert(code)
                                                    }
                                                } else {
                                                    android.util.Log.d(
                                                        "MainActivity",
                                                        "发现重复还款短信,跳过保存: $flight"
                                                    )
                                                }
                                            }
                                        }
                                        "火车票" -> {
                                            val seat = response.data.details.seat ?: ""
                                            if (seat.isNotEmpty()) {
                                                val existingCode =
                                                    Core.code.queryByTypeAndCodeAndDate(
                                                        response.data.category, seat, dateString
                                                    )
                                                if (existingCode == null) {
                                                    val code = Code(
                                                        id = 0,
                                                        category = response.data.category,
                                                        categoryId = 5, // 5-火车票类型
                                                        typeId = 1,     //暂时没有根据type分类
                                                        ruleId = 2,     //1-还款类型
                                                        msgId = msgId,
                                                        createTime = dateString,
                                                        oneLevel = response.data.details.company
                                                            ?: "",
                                                        secondLevel = response.data.details.company
                                                            ?: "",
                                                        code = seat,
                                                        pickup = 0, // 0-未取件,1-已取件
                                                        pickupTime = "", // 取件时间为空
                                                        overTime = response.data.details.time
                                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                                        address = response.data.details.address
                                                            ?: "",
                                                        remarks = response.data.details.trips ?: "",
                                                    )
                                                    if (code.oneLevel != "" && code.secondLevel != "" && code.code != "") {
                                                        Core.code.insert(code)
                                                    }
                                                } else {
                                                    android.util.Log.d(
                                                        "MainActivity",
                                                        "发现重复还款短信,跳过保存: $seat"
                                                    )
                                                }
                                            }
                                        }
@@ -332,16 +442,16 @@
        try {
            // 取消所有现有的提醒任务
            androidx.work.WorkManager.getInstance(this).cancelAllWorkByTag("reminder_worker")
            // 清除旧的提醒偏好设置
            getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE).edit().clear().apply()
            // 重新设置提醒任务
            (application as App).setupReminderWorker()
            // 检查是否有错过的提醒
            com.example.firstapp.service.ReminderWorker.checkMissedReminders(this)
            android.util.Log.d("MainActivity", "已重置提醒计划")
        } catch (e: Exception) {
            android.util.Log.e("MainActivity", "重置提醒计划失败: ${e.message}")
app/src/main/java/com/example/firstapp/activity/PickupActivity.kt
@@ -20,6 +20,8 @@
        const val TYPE_EXPRESS = "express"
        const val TYPE_REPAYMENT = "repayment"
        const val TYPE_INCOME = "income"
        const val TYPE_TRAIN = "train"
        const val TYPE_FLIGHT = "flight"
    }
    
    private var pageType = TYPE_EXPRESS
@@ -65,6 +67,8 @@
            TYPE_EXPRESS -> "是否确认取出所有包裹?"
            TYPE_REPAYMENT -> "是否确认处理所有还款?"
            TYPE_INCOME -> "是否确认处理所有收入?"
            TYPE_TRAIN -> "是否确认处理所有火车票?"
            TYPE_FLIGHT -> "是否确认处理所有机票?"
            else -> "是否确认处理所有项目?"
        }
    }
@@ -74,6 +78,8 @@
            TYPE_EXPRESS -> "全部取件"
            TYPE_REPAYMENT -> "全部还款"
            TYPE_INCOME -> "全部收款"
            TYPE_TRAIN -> "全部处理票务"
            TYPE_FLIGHT -> "全部处理机票"
            else -> "全部处理"
        }
    }
@@ -132,6 +138,8 @@
            TYPE_EXPRESS -> "共${count}个包裹"
            TYPE_REPAYMENT -> "共${count}笔还款"
            TYPE_INCOME -> "共${count}笔收入"
            TYPE_TRAIN -> "共${count}张车票"
            TYPE_FLIGHT -> "共${count}张机票"
            else -> "共${count}个"
        }
    }
app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt
对比新文件
@@ -0,0 +1,173 @@
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.R
import com.example.firstapp.databinding.ItemFlightGroupBinding
import com.example.firstapp.databinding.ItemFlightPackageHomeBinding
import com.example.firstapp.databinding.ItemFlightBinding
import com.example.firstapp.model.FlightGroup
import com.example.firstapp.model.FlightPackage
class FlightAdapter :
    ListAdapter<FlightGroup, FlightAdapter.ViewHolder>(FlightGroupDiffCallback()) {
    private var onPackageClickListener: (FlightGroup, FlightPackage) -> Unit = { _, _ -> }
    fun setOnPackageClickListener(listener: (FlightGroup, FlightPackage) -> Unit) {
        onPackageClickListener = listener
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemFlightGroupBinding.inflate(
            LayoutInflater.from(parent.context), parent, false
        )
        return ViewHolder(binding)
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val group = getItem(position)
        holder.bind(group)
        holder.setOnPackageClickListener(onPackageClickListener)
    }
    inner class ViewHolder(private val binding: ItemFlightGroupBinding) :
        RecyclerView.ViewHolder(binding.root) {
        private val packagesAdapter = FlightPackageHomeAdapter { pack ->
            currentGroup?.let { group ->
                onPackageClickListener(group, pack)
            }
        }
        private var currentGroup: FlightGroup? = null
        init {
            binding.rvPackages.apply {
                layoutManager = LinearLayoutManager(context)
                adapter = packagesAdapter
            }
        }
        fun bind(group: FlightGroup) {
            currentGroup = group
            binding.tvStationName.text = group.stationName
            binding.tvPackageCount.text = "共${group.packages.size}张机票"
            packagesAdapter.submitList(group.packages)
        }
        fun setOnPackageClickListener(listener: (FlightGroup, FlightPackage) -> Unit) {
            // 这个方法可以移除,因为我们在构造 FlightPackageHomeAdapter 时已经处理了点击事件
            // 或者保留这个方法但不做任何操作
        }
    }
}
// 首页使用的机票适配器 - 简化版本
class FlightPackageHomeAdapter(private val onPackageClick: (FlightPackage) -> Unit) :
    ListAdapter<FlightPackage, FlightPackageHomeAdapter.ViewHolder>(FlightPackageDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemFlightPackageHomeBinding.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: ItemFlightPackageHomeBinding) :
        RecyclerView.ViewHolder(binding.root) {
        init {
            binding.root.setOnClickListener {
                val pack = getItem(adapterPosition)
                onPackageClick(pack)
            }
        }
        fun bind(pack: FlightPackage) {
            binding.tvCompany.text = pack.company
            binding.tvCreateTime.text = pack.createTime
            binding.tvTrackingNumber.text = pack.trackingNumber
        }
    }
}
// 取件页面使用的机票适配器
class FlightPackageAdapter(private val onPackagePickup: (FlightPackage) -> Unit = { _ -> }) :
    ListAdapter<FlightPackage, FlightPackageAdapter.ViewHolder>(FlightPackageDiffCallback()) {
    private var onPackageClickListener: (FlightPackage) -> Unit = {}
    private var stationName: String = ""
    fun setStationInfo(station: String) {
        stationName = station
    }
    fun setOnPackageClickListener(listener: (FlightPackage) -> Unit) {
        onPackageClickListener = listener
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemFlightBinding.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: ItemFlightBinding) :
        RecyclerView.ViewHolder(binding.root) {
        init {
            binding.ivPackageStatus.setOnClickListener {
                val pack = getItem(adapterPosition)
                onPackagePickup(pack)
            }
            binding.root.setOnClickListener(null)
        }
        fun bind(pack: FlightPackage) {
            binding.tvPackageId.text = pack.id.toString()
            binding.tvCompany.text = pack.company
            binding.tvCreateTime.text = pack.createTime
            binding.tvTrackingNumber.text = pack.trackingNumber
            binding.ivPackageStatus.setImageResource(
                R.drawable.circle
            )
        }
    }
}
private class FlightGroupDiffCallback : DiffUtil.ItemCallback<FlightGroup>() {
    override fun areItemsTheSame(oldItem: FlightGroup, newItem: FlightGroup): Boolean {
        return oldItem.stationName == newItem.stationName
    }
    override fun areContentsTheSame(oldItem: FlightGroup, newItem: FlightGroup): Boolean {
        return oldItem == newItem
    }
}
private class FlightPackageDiffCallback : DiffUtil.ItemCallback<FlightPackage>() {
    override fun areItemsTheSame(oldItem: FlightPackage, newItem: FlightPackage): Boolean {
        return oldItem.trackingNumber == newItem.trackingNumber
    }
    override fun areContentsTheSame(oldItem: FlightPackage, newItem: FlightPackage): Boolean {
        return oldItem == newItem
    }
}
app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt
对比新文件
@@ -0,0 +1,173 @@
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.R
import com.example.firstapp.databinding.ItemTrainGroupBinding
import com.example.firstapp.databinding.ItemTrainPackageHomeBinding
import com.example.firstapp.databinding.ItemTrainBinding
import com.example.firstapp.model.TrainGroup
import com.example.firstapp.model.TrainPackage
class TrainAdapter :
    ListAdapter<TrainGroup, TrainAdapter.ViewHolder>(TrainGroupDiffCallback()) {
    private var onPackageClickListener: (TrainGroup, TrainPackage) -> Unit = { _, _ -> }
    fun setOnPackageClickListener(listener: (TrainGroup, TrainPackage) -> Unit) {
        onPackageClickListener = listener
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemTrainGroupBinding.inflate(
            LayoutInflater.from(parent.context), parent, false
        )
        return ViewHolder(binding)
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val group = getItem(position)
        holder.bind(group)
        holder.setOnPackageClickListener(onPackageClickListener)
    }
    inner class ViewHolder(private val binding: ItemTrainGroupBinding) :
        RecyclerView.ViewHolder(binding.root) {
        private val packagesAdapter = TrainPackageHomeAdapter { pack ->
            currentGroup?.let { group ->
                onPackageClickListener(group, pack)
            }
        }
        private var currentGroup: TrainGroup? = null
        init {
            binding.rvPackages.apply {
                layoutManager = LinearLayoutManager(context)
                adapter = packagesAdapter
            }
        }
        fun bind(group: TrainGroup) {
            currentGroup = group
            binding.tvStationName.text = group.stationName
            binding.tvPackageCount.text = "共${group.packages.size}张车票"
            packagesAdapter.submitList(group.packages)
        }
        fun setOnPackageClickListener(listener: (TrainGroup, TrainPackage) -> Unit) {
            // 这个方法可以移除,因为我们在构造 TrainPackageHomeAdapter 时已经处理了点击事件
            // 或者保留这个方法但不做任何操作
        }
    }
}
// 首页使用的车票适配器 - 简化版本
class TrainPackageHomeAdapter(private val onPackageClick: (TrainPackage) -> Unit) :
    ListAdapter<TrainPackage, TrainPackageHomeAdapter.ViewHolder>(TrainPackageDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemTrainPackageHomeBinding.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: ItemTrainPackageHomeBinding) :
        RecyclerView.ViewHolder(binding.root) {
        init {
            binding.root.setOnClickListener {
                val pack = getItem(adapterPosition)
                onPackageClick(pack)
            }
        }
        fun bind(pack: TrainPackage) {
            binding.tvCompany.text = pack.company
            binding.tvCreateTime.text = pack.createTime
            binding.tvTrackingNumber.text = pack.trackingNumber
        }
    }
}
// 取件页面使用的车票适配器
class TrainPackageAdapter(private val onPackagePickup: (TrainPackage) -> Unit = { _ -> }) :
    ListAdapter<TrainPackage, TrainPackageAdapter.ViewHolder>(TrainPackageDiffCallback()) {
    private var onPackageClickListener: (TrainPackage) -> Unit = {}
    private var stationName: String = ""
    fun setStationInfo(station: String) {
        stationName = station
    }
    fun setOnPackageClickListener(listener: (TrainPackage) -> Unit) {
        onPackageClickListener = listener
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemTrainBinding.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: ItemTrainBinding) :
        RecyclerView.ViewHolder(binding.root) {
        init {
            binding.ivPackageStatus.setOnClickListener {
                val pack = getItem(adapterPosition)
                onPackagePickup(pack)
            }
            binding.root.setOnClickListener(null)
        }
        fun bind(pack: TrainPackage) {
            binding.tvPackageId.text = pack.id.toString()
            binding.tvCompany.text = pack.company
            binding.tvCreateTime.text = pack.createTime
            binding.tvTrackingNumber.text = pack.trackingNumber
            binding.ivPackageStatus.setImageResource(
                R.drawable.circle
            )
        }
    }
}
private class TrainGroupDiffCallback : DiffUtil.ItemCallback<TrainGroup>() {
    override fun areItemsTheSame(oldItem: TrainGroup, newItem: TrainGroup): Boolean {
        return oldItem.stationName == newItem.stationName
    }
    override fun areContentsTheSame(oldItem: TrainGroup, newItem: TrainGroup): Boolean {
        return oldItem == newItem
    }
}
private class TrainPackageDiffCallback : DiffUtil.ItemCallback<TrainPackage>() {
    override fun areItemsTheSame(oldItem: TrainPackage, newItem: TrainPackage): Boolean {
        return oldItem.trackingNumber == newItem.trackingNumber
    }
    override fun areContentsTheSame(oldItem: TrainPackage, newItem: TrainPackage): Boolean {
        return oldItem == newItem
    }
}
app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt
@@ -28,4 +28,9 @@
    val number: String?,
    val datetime: String?,
    val balance: String?,
    val seat: String?,
    val trips: String?,
    val start: String?,
    val end: String?,
    val flight: String?,
)
app/src/main/java/com/example/firstapp/model/FlightGroup.kt
对比新文件
@@ -0,0 +1,13 @@
package com.example.firstapp.model
data class FlightGroup(
    val stationName: String,
    val packages: List<FlightPackage>
)
data class FlightPackage(
    var id: Long,
    val company: String,
    val trackingNumber: String,
    val createTime: String
)
app/src/main/java/com/example/firstapp/model/TrainGroup.kt
对比新文件
@@ -0,0 +1,13 @@
package com.example.firstapp.model
data class TrainGroup(
    val stationName: String,
    val packages: List<TrainPackage>
)
data class TrainPackage(
    var id: Long,
    val company: String,
    val trackingNumber: String,
    val createTime: String
)
app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt
@@ -142,6 +142,52 @@
                                        Core.code.insert(code)
                                    }
                                }
                                "航班" -> {
                                    val code = Code(
                                        id = 0,
                                        category = response.data.category,
                                        categoryId = 4, // 4-航班类型
                                        typeId = 1,     //暂时没有根据type分类
                                        ruleId = 2,     //1-还款类型
                                        msgId = msgId,
                                        createTime = createtime,
                                        oneLevel = response.data.details.company ?: "",
                                        secondLevel = response.data.details.start +response.data.details.end?: "",
                                        code = response.data.details.seat ?: "",
                                        pickup = 0, // 0-未取件,1-已取件
                                        pickupTime = "", // 取件时间为空
                                        overTime = response.data.details.time
                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                        address = response.data.details.address ?: "",
                                        remarks = response.data.details.seat ?: "",
                                    )
                                    if(code.oneLevel!=""  && code.secondLevel!="" && code.code!="") {
                                        Core.code.insert(code)
                                    }
                                }
                                "火车票" -> {
                                    val code = Code(
                                        id = 0,
                                        category = response.data.category,
                                        categoryId = 5, // 5-火车票类型
                                        typeId = 1,     //暂时没有根据type分类
                                        ruleId = 2,     //1-还款类型
                                        msgId = msgId,
                                        createTime = createtime,
                                        oneLevel = response.data.details.company ?: "",
                                        secondLevel = response.data.details.company ?: "",
                                        code = response.data.details.seat ?: "",
                                        pickup = 0, // 0-未取件,1-已取件
                                        pickupTime = "", // 取件时间为空
                                        overTime = response.data.details.time
                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                        address = response.data.details.address ?: "",
                                        remarks = response.data.details.trips ?: "",
                                    )
                                    if(code.oneLevel!=""  && code.secondLevel!="" && code.code!="") {
                                        Core.code.insert(code)
                                    }
                                }
                            }
                            // 发送广播通知数据已更新
app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
@@ -22,6 +22,8 @@
import com.example.firstapp.adapter.FinanceAdapter
import com.example.firstapp.adapter.CategorySelectorAdapter
import com.example.firstapp.adapter.IncomeAdapter
import com.example.firstapp.adapter.TrainAdapter
import com.example.firstapp.adapter.FlightAdapter
import com.example.firstapp.database.service.RetrofitClient
import com.example.firstapp.databinding.FragmentHomeBinding
import com.example.firstapp.databinding.DialogCategorySelectorBinding
@@ -45,8 +47,8 @@
    private lateinit var expressAdapter: ExpressAdapter
    private lateinit var financeAdapter: FinanceAdapter
    private lateinit var incomeAdapter: IncomeAdapter
    private lateinit var flightAdapter: FinanceAdapter
    private lateinit var trainAdapter: FinanceAdapter
    private lateinit var flightAdapter: FlightAdapter
    private lateinit var trainAdapter: TrainAdapter
    private lateinit var dataUpdateReceiver: BroadcastReceiver
    private lateinit var reminderUpdateReceiver: BroadcastReceiver
    private var reminderBadge: TextView? = null
@@ -185,16 +187,38 @@
        binding.flightRecycler.apply {
            layoutManager = LinearLayoutManager(context)
            flightAdapter = FinanceAdapter()
            flightAdapter = FlightAdapter()
            adapter = flightAdapter
            visibility = View.GONE
            // 设置点击监听
            flightAdapter.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_FLIGHT)
                }
                startActivity(intent)
            }
        }
        binding.trainRecycler.apply {
            layoutManager = LinearLayoutManager(context)
            trainAdapter = FinanceAdapter()
            trainAdapter = TrainAdapter()
            adapter = trainAdapter
            visibility = View.GONE
            // 设置点击监听
            trainAdapter.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_TRAIN)
                }
                startActivity(intent)
            }
        }
    }
app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
@@ -21,20 +21,24 @@
import kotlinx.coroutines.launch
import com.example.firstapp.database.repository.ReminderRecordRepository
import com.example.firstapp.database.entity.ReminderRecord
import com.example.firstapp.model.TrainGroup
import com.example.firstapp.model.TrainPackage
import com.example.firstapp.model.FlightGroup
import com.example.firstapp.model.FlightPackage
class HomeViewModel : ViewModel() {
    private val _expressItems = MutableLiveData<List<ExpressGroup>>()
    private val _financeItems = MutableLiveData<List<FinanceGroup>>()
    private val _incomeItems = MutableLiveData<List<IncomeGroup>>()
    private val _flightItems = MutableLiveData<List<FinanceGroup>>()
    private val _trainItems = MutableLiveData<List<FinanceGroup>>()
    private val _flightItems = MutableLiveData<List<FlightGroup>>()
    private val _trainItems = MutableLiveData<List<TrainGroup>>()
    
    val expressItems: LiveData<List<ExpressGroup>> = _expressItems
    val financeItems: LiveData<List<FinanceGroup>> = _financeItems
    val incomeItems: LiveData<List<IncomeGroup>> = _incomeItems
    val flightItems: LiveData<List<FinanceGroup>> = _flightItems
    val trainItems: LiveData<List<FinanceGroup>> = _trainItems
    val flightItems: LiveData<List<FlightGroup>> = _flightItems
    val trainItems: LiveData<List<TrainGroup>> = _trainItems
    private val _categories = MutableLiveData<List<CategoryConfig>>()
    val categories: LiveData<List<CategoryConfig>> = _categories
@@ -105,8 +109,38 @@
                        }
                        _incomeItems.postValue(groups)
                    }
                    "火车票" -> {
                        // 处理火车票类型
                        val groups = stations.map { station ->
                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
                                TrainPackage(
                                    id = code.id,
                                    company = code.secondLevel,
                                    trackingNumber = code.code,
                                    createTime = code.createTime
                                )
                            }
                            TrainGroup(stationName = station.stationName, packages = packages)
                        }
                        _trainItems.postValue(groups)
                    }
                    "航班" -> {
                        // 处理航班类型
                        val groups = stations.map { station ->
                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
                                FlightPackage(
                                    id = code.id,
                                    company = code.secondLevel,
                                    trackingNumber = code.code,
                                    createTime = code.createTime
                                )
                            }
                            FlightGroup(stationName = station.stationName, packages = packages)
                        }
                        _flightItems.postValue(groups)
                    }
                    else -> {
                        // 处理其他类型(还款、航班、火车票)
                        // 处理其他类型(还款)
                        val groups = stations.map { station ->
                            val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code ->
                                FinancePackage(
@@ -122,8 +156,6 @@
                        // 根据类型更新对应的 LiveData
                        when (type) {
                            "还款" -> _financeItems.postValue(groups)
                            "航班" -> _flightItems.postValue(groups)
                            "火车票" -> _trainItems.postValue(groups)
                        }
                    }
                }
app/src/main/res/layout/activity_phone_login.xml
@@ -97,7 +97,7 @@
                android:layout_height="wrap_content"
                android:background="@null"
                android:hint="邀请码"
                android:inputType="phone"
                android:inputType="textVisiblePassword"
                android:maxLength="11"
                android:textSize="16sp"
                android:padding="12dp"/>
app/src/main/res/layout/item_flight.xml
对比新文件
@@ -0,0 +1,59 @@
<?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_package_status"
        android:layout_width="12dp"
        android:layout_height="12dp"
        android:src="@drawable/circle"/>
    <TextView
        android:id="@+id/tv_package_id"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:visibility="gone"/>
    <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="12sp"
            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>
app/src/main/res/layout/item_flight_group.xml
对比新文件
@@ -0,0 +1,58 @@
<?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>
app/src/main/res/layout/item_flight_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>
app/src/main/res/layout/item_train.xml
对比新文件
@@ -0,0 +1,59 @@
<?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_package_status"
        android:layout_width="12dp"
        android:layout_height="12dp"
        android:src="@drawable/circle"/>
    <TextView
        android:id="@+id/tv_package_id"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:visibility="gone"/>
    <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="12sp"
            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>
app/src/main/res/layout/item_train_group.xml
对比新文件
@@ -0,0 +1,58 @@
<?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>
app/src/main/res/layout/item_train_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>