|  |  | 
 |  |  | import java.util.* | 
 |  |  | import java.text.SimpleDateFormat | 
 |  |  | import android.graphics.Color | 
 |  |  | import android.widget.Button | 
 |  |  | import android.view.Gravity | 
 |  |  | import android.widget.GridLayout | 
 |  |  | import android.widget.LinearLayout | 
 |  |  | import android.widget.Toast | 
 |  |  | import androidx.core.content.ContextCompat | 
 |  |  | import androidx.cardview.widget.CardView | 
 |  |  | import androidx.lifecycle.lifecycleScope | 
 |  |  | import com.bumptech.glide.Glide | 
 |  |  | import com.example.firstapp.database.response.UserInfo | 
 |  |  | import com.example.firstapp.database.service.RetrofitClient | 
 |  |  | import com.example.firstapp.model.DailyStat | 
 |  |  | import com.example.firstapp.utils.PreferencesManager | 
 |  |  | import com.github.mikephil.charting.components.YAxis | 
 |  |  | import kotlinx.coroutines.launch | 
 |  |  |  | 
 |  |  | class DashboardFragment : Fragment() { | 
 |  |  | 
 |  |  |     private var currentDateType = DateType.DAY | 
 |  |  |     private lateinit var barChart: BarChart | 
 |  |  |     private lateinit var pieChart: PieChart | 
 |  |  |     private lateinit var chartCourierDistriBution:CardView | 
 |  |  |     private lateinit var heatmapView: View | 
 |  |  |     private var currentUserInfo: UserInfo? = null // 确保使用你的实际数据类 | 
 |  |  |  | 
 |  |  |     private var startDateCur:String = "" | 
 |  |  |     private var endDateCur:String = "" | 
 |  |  |     private lateinit var bar_title:TextView | 
 |  |  |     private lateinit var pie_title:TextView | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     enum class DateType { | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun setupTabLayout() { | 
 |  |  |         val weekStatsView = binding.layoutWeekStats.root | 
 |  |  |         bar_title = weekStatsView.findViewById(R.id.bar_title) | 
 |  |  |         pie_title = weekStatsView.findViewById(R.id.pie_title) | 
 |  |  |  | 
 |  |  |         binding.tabDateRange.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { | 
 |  |  |             override fun onTabSelected(tab: TabLayout.Tab?) { | 
 |  |  |                 currentDate = Calendar.getInstance() | 
 |  |  |  | 
 |  |  |                 currentDateType = when(tab?.position) { | 
 |  |  |                     0 -> DateType.DAY | 
 |  |  |                     1 -> DateType.WEEK | 
 |  |  | 
 |  |  |                     3 -> DateType.YEAR | 
 |  |  |                     else -> DateType.DAY | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 when (currentDateType) { | 
 |  |  |                     DateType.DAY -> { | 
 |  |  |                         binding.cardPackageStatsTitleText.text = "本日收到包裹总数" | 
 |  |  |                         binding.layoutYearStatsTitleText.text = "包裹取件码记录" | 
 |  |  |  | 
 |  |  |                         binding.cardPackageStatsTitleText.visibility = View.VISIBLE | 
 |  |  |                         binding.layoutYearStatsTitleText.visibility =  View.VISIBLE | 
 |  |  |                     } | 
 |  |  |                     DateType.WEEK -> { | 
 |  |  |                         binding.cardPackageStatsTitleText.text = "本周收到包裹总数" | 
 |  |  |                         bar_title.text = "本周收到包裹数分布 ->" | 
 |  |  |                         pie_title.text = "本周包裹物流公司分布 ->" | 
 |  |  |                         binding.cardPackageStatsTitleText.visibility = View.VISIBLE | 
 |  |  |                         binding.layoutYearStatsTitleText.visibility =  View.GONE | 
 |  |  |  | 
 |  |  |                     } | 
 |  |  |                     DateType.MONTH -> { | 
 |  |  |                         binding.cardPackageStatsTitleText.text = "本月收到包裹总数" | 
 |  |  |                         bar_title.text = "本月收到包裹数分布 ->" | 
 |  |  |                         pie_title.text = "本月包裹物流公司分布 ->" | 
 |  |  |                         binding.cardPackageStatsTitleText.visibility = View.VISIBLE | 
 |  |  |                         binding.layoutYearStatsTitleText.visibility =  View.GONE | 
 |  |  |                     } | 
 |  |  |                     DateType.YEAR -> { | 
 |  |  |                         bar_title.text = "本年收到包裹数分布 ->" | 
 |  |  |                         pie_title.text = "本年包裹物流公司分布 ->" | 
 |  |  |                         binding.cardPackageStatsTitleText.visibility = View.GONE | 
 |  |  |                         binding.layoutYearStatsTitleText.visibility =  View.GONE | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |                 updateDateDisplay() | 
 |  |  |                 updateCharts() | 
 |  |  |                 loadPackages() | 
 |  |  | 
 |  |  |  | 
 |  |  |     private fun updateDateDisplay() { | 
 |  |  |         val dateFormat = when (currentDateType) { | 
 |  |  |             DateType.DAY -> { | 
 |  |  |                 // 获取当天的起始和结束时间 | 
 |  |  |                 val calendar = currentDate.clone() as Calendar | 
 |  |  |                 // 设置为当天的 00:00:00 | 
 |  |  |                 calendar.set(Calendar.HOUR_OF_DAY, 0) | 
 |  |  |                 calendar.set(Calendar.MINUTE, 0) | 
 |  |  |                 calendar.set(Calendar.SECOND, 0) | 
 |  |  |                 calendar.set(Calendar.MILLISECOND, 0) | 
 |  |  |                 startDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 // 设置为当天的 23:59:59 | 
 |  |  |                 calendar.set(Calendar.HOUR_OF_DAY, 23) | 
 |  |  |                 calendar.set(Calendar.MINUTE, 59) | 
 |  |  |                 calendar.set(Calendar.SECOND, 59) | 
 |  |  |                 calendar.set(Calendar.MILLISECOND, 999) | 
 |  |  |                 endDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 // 返回当天的日期格式 | 
 |  |  |                 SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault()).format(currentDate.time) | 
 |  |  |             } | 
 |  |  |             DateType.WEEK -> { | 
 |  |  |                 // 获取本周的起始和结束日期 | 
 |  |  |                 val calendar = currentDate.clone() as Calendar | 
 |  |  |                 calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) | 
 |  |  |                 val startDate = SimpleDateFormat("MM月dd日", Locale.getDefault()).format(calendar.time) | 
 |  |  |                 startDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 calendar.add(Calendar.DAY_OF_WEEK, 6) | 
 |  |  |                 val endDate = SimpleDateFormat("MM月dd日", Locale.getDefault()).format(calendar.time) | 
 |  |  |                 endDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 "$startDate-$endDate" | 
 |  |  |             } | 
 |  |  |             DateType.MONTH -> { | 
 |  |  |                 // 获取本月的起始和结束日期 | 
 |  |  |                 val calendar = currentDate.clone() as Calendar | 
 |  |  |                 calendar.set(Calendar.DAY_OF_MONTH, 1) | 
 |  |  |                 startDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 calendar.add(Calendar.MONTH, 1) | 
 |  |  |                 calendar.set(Calendar.DAY_OF_MONTH, 0) | 
 |  |  |                 endDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 "yyyy年MM月" | 
 |  |  |             } | 
 |  |  |             DateType.YEAR -> { | 
 |  |  |                 // 获取当前年的起始和结束日期 | 
 |  |  |                 val calendar = currentDate.clone() as Calendar | 
 |  |  |  | 
 |  |  |                 // 设置为当前年份的 1 月 1 日 | 
 |  |  |                 calendar.set(Calendar.MONTH, Calendar.JANUARY) | 
 |  |  |                 calendar.set(Calendar.DAY_OF_MONTH, 1) | 
 |  |  |                 startDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 // 设置为当前年份的 12 月 31 日 | 
 |  |  |                 calendar.set(Calendar.MONTH, Calendar.DECEMBER) | 
 |  |  |                 calendar.set(Calendar.DAY_OF_MONTH, 31) | 
 |  |  |                 endDateCur = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |  | 
 |  |  |                 "yyyy年" | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         // 更新界面显示 | 
 |  |  |         if (currentDateType == DateType.WEEK) { | 
 |  |  |             binding.textCurrentDate.text = dateFormat | 
 |  |  |         } else { | 
 |  |  |             binding.textCurrentDate.text = SimpleDateFormat(dateFormat, Locale.getDefault()) | 
 |  |  |                 .format(currentDate.time) | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun updateDateDisplay_bak() { | 
 |  |  |         val dateFormat = when (currentDateType) { | 
 |  |  |             DateType.DAY -> "yyyy年MM月dd日" | 
 |  |  |             DateType.WEEK -> { | 
 |  |  |                 // 获取本周的起始和结束日期 | 
 |  |  |                 val calendar = currentDate.clone() as Calendar | 
 |  |  |                 calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) | 
 |  |  |                 val startDate = SimpleDateFormat("MM月dd日", Locale.getDefault()).format(calendar.time) | 
 |  |  |                  | 
 |  |  |                 startDateCur=SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |                 calendar.add(Calendar.DAY_OF_WEEK, 6) | 
 |  |  |                 val endDate = SimpleDateFormat("MM月dd日", Locale.getDefault()).format(calendar.time) | 
 |  |  |                  | 
 |  |  |                 endDateCur=SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(calendar.time) | 
 |  |  |  | 
 |  |  |  | 
 |  |  |                 "$startDate-$endDate" | 
 |  |  |             } | 
 |  |  |             DateType.MONTH -> "yyyy年MM月" | 
 |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |     private fun setupView(view: View) { | 
 |  |  |  | 
 |  |  |         val weekStatsView = binding.layoutWeekStats.root | 
 |  |  |         barChart = weekStatsView.findViewById(R.id.chart_daily_packages) | 
 |  |  |         chartCourierDistriBution=weekStatsView.findViewById(R.id.chart_courier_card_view) | 
 |  |  |         pieChart = weekStatsView.findViewById(R.id.chart_courier_distribution) | 
 |  |  |         heatmapView = weekStatsView.findViewById(R.id.heatmap_yearly) | 
 |  |  |  | 
 |  |  |         barChart.setViewPortOffsets(100f, 100f, 100f, 200f) | 
 |  |  |  | 
 |  |  | //        barChart.invalidate() | 
 |  |  |          | 
 |  |  |         // 初始化时隐藏统计视图 | 
 |  |  |         weekStatsView.visibility = View.GONE | 
 |  |  | 
 |  |  |         setupPieChart() | 
 |  |  |         setupHeatmap() | 
 |  |  |         updateCharts() | 
 |  |  |  | 
 |  |  |     } | 
 |  |  |     private fun setupBarChart() { | 
 |  |  |         barChart.apply { | 
 |  |  | 
 |  |  |     private fun updateBarChartData() { | 
 |  |  |         val statsFlow = when (currentDateType) { | 
 |  |  |             DateType.WEEK -> { | 
 |  |  |                 viewModel.getWeeklyStats(currentDate.timeInMillis, 6) | 
 |  |  | //                viewModel.getWeeklyStats(currentDate.timeInMillis, 6) | 
 |  |  |                 viewModel.getWeeklyStatsChart(startDateCur,endDateCur) | 
 |  |  |             } | 
 |  |  |             DateType.MONTH -> { | 
 |  |  |                 viewModel.getYearMonthlyStats(currentDate.timeInMillis) | 
 |  |  | 
 |  |  |                 PieEntry(stat.count.toFloat(), "${stat.courierName}(${stat.count})") | 
 |  |  |             } | 
 |  |  |  | 
 |  |  |             val dataSet = PieDataSet(entries, "快递公司分布") | 
 |  |  |             dataSet.colors = listOf( | 
 |  |  |                 resources.getColor(R.color.purple_500), | 
 |  |  |                 resources.getColor(R.color.teal_200), | 
 |  |  |                 resources.getColor(R.color.purple_200), | 
 |  |  |                 resources.getColor(R.color.teal_700) | 
 |  |  |             ) | 
 |  |  |             dataSet.valueTextSize = 14f // 增大数值文字大小 | 
 |  |  |             if (entries.isNotEmpty()) { | 
 |  |  |                 val dataSet = PieDataSet(entries, "快递公司分布") | 
 |  |  |                 dataSet.colors = listOf( | 
 |  |  |                     resources.getColor(R.color.light_blue_600_1), | 
 |  |  |                     resources.getColor(R.color.sunflower), | 
 |  |  |                     resources.getColor(R.color.light_blue), | 
 |  |  |                     resources.getColor(R.color.vermillion), | 
 |  |  |                     resources.getColor(R.color.fish_belly_white), | 
 |  |  |                     resources.getColor(R.color.light_green), | 
 |  |  |                     resources.getColor(R.color.crimson), | 
 |  |  |                     resources.getColor(R.color.sky_blue), | 
 |  |  |                     resources.getColor(R.color.gold), | 
 |  |  |                     resources.getColor(R.color.light_purple), | 
 |  |  |                     resources.getColor(R.color.yellow), | 
 |  |  |                     resources.getColor(R.color.canary_yellow), | 
 |  |  |                     resources.getColor(R.color.red_purple), | 
 |  |  |                     resources.getColor(R.color.light_cyan), | 
 |  |  |                     resources.getColor(R.color.orange), | 
 |  |  |                     resources.getColor(R.color.magenta), | 
 |  |  |                     resources.getColor(R.color.light_purple_2), | 
 |  |  |                     resources.getColor(R.color.bright_yellow), | 
 |  |  |                     resources.getColor(R.color.emerald_green), | 
 |  |  |                     resources.getColor(R.color.turmeric), | 
 |  |  |                     resources.getColor(R.color.red_gold), | 
 |  |  |                     resources.getColor(R.color.off_white), | 
 |  |  |                     resources.getColor(R.color.tangerine), | 
 |  |  |                     resources.getColor(R.color.aqua_blue), | 
 |  |  |                     resources.getColor(R.color.frost), | 
 |  |  |                     resources.getColor(R.color.wisteria), | 
 |  |  |                     resources.getColor(R.color.cyan) | 
 |  |  |                 ) | 
 |  |  |                 dataSet.valueTextSize = 14f // 增大数值文字大小 | 
 |  |  |  | 
 |  |  |             val pieData = PieData(dataSet) | 
 |  |  |             pieData.setValueFormatter(object : ValueFormatter() { | 
 |  |  |                 override fun getFormattedValue(value: Float): String { | 
 |  |  |                     return value.toInt().toString() | 
 |  |  |                 } | 
 |  |  |             }) | 
 |  |  |                 val pieData = PieData(dataSet) | 
 |  |  |                 pieData.setValueFormatter(object : ValueFormatter() { | 
 |  |  |                     override fun getFormattedValue(value: Float): String { | 
 |  |  |                         return value.toInt().toString() | 
 |  |  |                     } | 
 |  |  |                 }) | 
 |  |  |  | 
 |  |  |             pieChart.data = pieData | 
 |  |  |             pieChart.invalidate() | 
 |  |  |                 pieChart.data = pieData | 
 |  |  |                 pieChart.invalidate() | 
 |  |  |  | 
 |  |  |                 pieChart.visibility = View.VISIBLE  // 例如:隐藏 PieChart | 
 |  |  |  | 
 |  |  |                 pie_title.visibility = View.VISIBLE | 
 |  |  |  | 
 |  |  |                 chartCourierDistriBution.visibility =View.VISIBLE | 
 |  |  |  | 
 |  |  |             } else { | 
 |  |  |                 // 如果 entries 为空,可以选择隐藏图表或设置一个默认显示 | 
 |  |  |                 pieChart.visibility = View.GONE  // 例如:隐藏 PieChart | 
 |  |  |  | 
 |  |  |                 pie_title.visibility = View.GONE | 
 |  |  |  | 
 |  |  |                 chartCourierDistriBution.visibility =View.GONE | 
 |  |  |  | 
 |  |  |             } | 
 |  |  |  | 
 |  |  |  | 
 |  |  | //            val dataSet = PieDataSet(entries, "快递公司分布") | 
 |  |  | //            dataSet.colors = listOf( | 
 |  |  | //                resources.getColor(R.color.purple_500), | 
 |  |  | //                resources.getColor(R.color.teal_200), | 
 |  |  | //                resources.getColor(R.color.purple_200), | 
 |  |  | //                resources.getColor(R.color.teal_700) | 
 |  |  | //            ) | 
 |  |  | //            dataSet.valueTextSize = 14f // 增大数值文字大小 | 
 |  |  | // | 
 |  |  | //            val pieData = PieData(dataSet) | 
 |  |  | //            pieData.setValueFormatter(object : ValueFormatter() { | 
 |  |  | //                override fun getFormattedValue(value: Float): String { | 
 |  |  | //                    return value.toInt().toString() | 
 |  |  | //                } | 
 |  |  | //            }) | 
 |  |  | // | 
 |  |  | //            pieChart.data = pieData | 
 |  |  | //            pieChart.invalidate() | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |     private fun getDayLabels(): Array<String> { | 
 |  |  |         return arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日") | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun loadPackages() { | 
 |  |  |     private fun loadPackages(){ | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  | //            根据日、周、月、年 获取统计数字 | 
 |  |  |         when (currentDateType) { | 
 |  |  |             DateType.DAY -> { | 
 |  |  |  | 
 |  |  |                 viewModel.getCurrentDayStatsByType(startDateCur,endDateCur,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 获取取件记录 | 
 |  |  |                 viewModel.getPackagesReaded(currentDate.timeInMillis, | 
 |  |  |                     currentDateType.name) | 
 |  |  |                     .observe(viewLifecycleOwner) { unpackages-> | 
 |  |  |                         // 只读取未取件的包裹 | 
 |  |  |                         packageAdapter.updatePackages(unpackages) | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |             } | 
 |  |  |             DateType.WEEK -> { | 
 |  |  |  | 
 |  |  |                 viewModel.getCurrentDayStatsByType(startDateCur,endDateCur,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             DateType.MONTH -> { | 
 |  |  |  | 
 |  |  |                 viewModel.getCurrentDayStatsByType(startDateCur,endDateCur,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             DateType.YEAR -> { | 
 |  |  |  | 
 |  |  |                 viewModel.getCurrentDayStatsByType(startDateCur,endDateCur,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.layoutYearStats.textTotalPackages.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun loadPackages_bak2(){ | 
 |  |  |  | 
 |  |  |         val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) | 
 |  |  |  | 
 |  |  | //            根据日、周、月、年 获取统计数字 | 
 |  |  |         when (currentDateType) { | 
 |  |  |             DateType.DAY -> { | 
 |  |  |                 val today = Calendar.getInstance() | 
 |  |  |                 val tmpCurDateStart = formatter.format(currentDate.time) | 
 |  |  |                 val tmpCurDateEnd = formatter.format(currentDate.time) | 
 |  |  |                 viewModel.getCurrentDayStatsByType(tmpCurDateStart,tmpCurDateEnd,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 获取本周统计 | 
 |  |  |                 viewModel.getPackagesReaded(currentDate.timeInMillis, | 
 |  |  |                     currentDateType.name) | 
 |  |  |                     .observe(viewLifecycleOwner) { unpackages-> | 
 |  |  |                         // 只读取未取件的包裹 | 
 |  |  |                         packageAdapter.updatePackages(unpackages) | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |             } | 
 |  |  |             DateType.WEEK -> { | 
 |  |  |                 val today = Calendar.getInstance() | 
 |  |  |  | 
 |  |  |                 // 获取本周的周一(第一天) | 
 |  |  |                 today.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) | 
 |  |  |                 val firstDayOfWeek = formatter.format(today.time) | 
 |  |  |                 // 获取本周的周日(最后一天) | 
 |  |  |                 today.add(Calendar.DATE, 6)  // 加6天 | 
 |  |  |                 val lastDayOfWeek = formatter.format(today.time) | 
 |  |  |                 viewModel.getCurrentDayStatsByType(firstDayOfWeek,lastDayOfWeek,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             DateType.MONTH -> { | 
 |  |  |                 val today = Calendar.getInstance() | 
 |  |  |                 today.set(Calendar.DAY_OF_MONTH, 1)  // 设置为本月第一天 | 
 |  |  |                 val firstDayOfMonth = formatter.format(today.time) | 
 |  |  |  | 
 |  |  |                 today.add(Calendar.MONTH, 1)  // 移动到下个月 | 
 |  |  |                 today.set(Calendar.DAY_OF_MONTH, 0)  // 设置为下个月的最后一天 | 
 |  |  |                 val lastDayOfMonth = formatter.format(today.time) | 
 |  |  |                 viewModel.getCurrentDayStatsByType(firstDayOfMonth,lastDayOfMonth,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                     binding.textPackageCount.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             DateType.YEAR -> { | 
 |  |  |                 val today = Calendar.getInstance() | 
 |  |  |                 today.set(Calendar.MONTH, Calendar.JANUARY)  // 设置为第一月 | 
 |  |  |                 today.set(Calendar.DAY_OF_MONTH, 1)  // 设置为第一天 | 
 |  |  |                 val firstDayOfYear = formatter.format(today.time) | 
 |  |  |  | 
 |  |  |                 today.add(Calendar.YEAR, 1)  // 移动到下一年 | 
 |  |  |                 today.set(Calendar.MONTH, Calendar.DECEMBER)  // 设置为最后一月 | 
 |  |  |                 today.set(Calendar.DAY_OF_MONTH, 31)  // 设置为最后一天 | 
 |  |  |                 val lastDayOfYear = formatter.format(today.time) | 
 |  |  |                 viewModel.getCurrentDayStatsByType(firstDayOfYear,lastDayOfYear,"快递") .observe(viewLifecycleOwner) { stats -> | 
 |  |  | //                    binding.textPackageCount.text = "${stats}个" | 
 |  |  |                     binding.layoutYearStats.textTotalPackages.text = "${stats}个" | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |     private fun loadPackages_bak() { | 
 |  |  |         viewModel.getPackages( | 
 |  |  |             currentDate.timeInMillis, | 
 |  |  |             currentDateType.name | 
 |  |  | 
 |  |  |             when (currentDateType) { | 
 |  |  |                 DateType.DAY -> { | 
 |  |  |                     binding.textPackageCount.text = "${packages.size}个" | 
 |  |  |  | 
 |  |  |                     // 获取本周统计 | 
 |  |  |                     viewModel.getPackagesReaded(currentDate.timeInMillis, | 
 |  |  |                         currentDateType.name) | 
 |  |  |                         .observe(viewLifecycleOwner) { unpackages-> | 
 |  |  |                             // 只读取未取件的包裹 | 
 |  |  |                             packageAdapter.updatePackages(unpackages) | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                 } | 
 |  |  |                 DateType.WEEK -> { | 
 |  |  |                     // 获取本周统计 | 
 |  |  |                     viewModel.getCurrentWeekStats(currentDate.timeInMillis) | 
 |  |  |                         .observe(viewLifecycleOwner) { stats -> | 
 |  |  |                             val weekTotal = stats.sumOf { it.count } | 
 |  |  |                             binding.textPackageCount.text = "${weekTotal}个" | 
 |  |  |                         } | 
 |  |  |                     viewModel.getCurrentWeekStats2(startDateCur,endDateCur).observe(viewLifecycleOwner) { stats -> | 
 |  |  |                         binding.textPackageCount.text = "${stats}个" | 
 |  |  |                     } | 
 |  |  | //                    viewModel.getCurrentWeekStats(currentDate.timeInMillis) | 
 |  |  | //                        .observe(viewLifecycleOwner) { stats -> | 
 |  |  | //                            val weekTotal = stats.sumOf { it.count } | 
 |  |  | //                            binding.textPackageCount.text = "${weekTotal}个" | 
 |  |  | //                        } | 
 |  |  |                 } | 
 |  |  |                 DateType.MONTH -> { | 
 |  |  |                     // 获取本月统计 | 
 |  |  | 
 |  |  |                         } | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |             packageAdapter.updatePackages(packages) | 
 |  |  |             packageAdapter.updatePackages(packages) | 
 |  |  |  | 
 |  |  | //            packageAdapter.updatePackages(packages) | 
 |  |  | //            binding.textPackageCount.text = "${packages.size}个" | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun updateHeatmapData() { | 
 |  |  |         viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats -> | 
 |  |  |             if (stats.isEmpty()) return@observe | 
 |  |  |  | 
 |  |  |             // 创建52周x7天的数据矩阵 | 
 |  |  |             val heatmapMatrix = Array(7) { IntArray(52) } | 
 |  |  |  | 
 |  |  |             // 填充数据 | 
 |  |  |             stats.forEach { stat -> | 
 |  |  |                 val week = stat.weekOfYear - 1 // 0-51 | 
 |  |  |                 val dayOfWeek = stat.dayOfWeek - 1 // 0-6 | 
 |  |  |                 if (week in 0..51 && dayOfWeek in 0..6) { | 
 |  |  |                     heatmapMatrix[dayOfWeek][week] = stat.count | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |  | 
 |  |  |             // 更新UI | 
 |  |  |             binding.layoutWeekStats.heatmapYearly.apply { | 
 |  |  |                 removeAllViews() | 
 |  |  |  | 
 |  |  |                 val gridLayout = GridLayout(context).apply { | 
 |  |  |                     rowCount = 8 // 1行月份 + 7行星期 | 
 |  |  |                     columnCount = 53 // 1列星期 + 52列周数 | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 添加月份标签 | 
 |  |  |                 val months = arrayOf("1月", "2月", "3月", "4月", "5月", "6月", | 
 |  |  |                     "7月", "8月", "9月", "10月", "11月", "12月") | 
 |  |  |                 months.forEachIndexed { index, month -> | 
 |  |  |                     val label = TextView(context).apply { | 
 |  |  |                         text = month | 
 |  |  |                         textSize = 10f | 
 |  |  |                         setPadding(0, 0, 8, 4) | 
 |  |  |                         val weekPosition = (index * 4.3).toInt() // 估算月份起始位置 | 
 |  |  |                         layoutParams = GridLayout.LayoutParams().apply { | 
 |  |  |                             columnSpec = GridLayout.spec(weekPosition + 1) | 
 |  |  |                             rowSpec = GridLayout.spec(0) | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                     gridLayout.addView(label) | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 添加星期标签 | 
 |  |  |                 val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日") | 
 |  |  |                 dayLabels.forEachIndexed { index, label -> | 
 |  |  |                     val textView = TextView(context).apply { | 
 |  |  |                         text = label | 
 |  |  |                         textSize = 10f | 
 |  |  |                         setPadding(4, 0, 8, 0) | 
 |  |  |                         layoutParams = GridLayout.LayoutParams().apply { | 
 |  |  |                             columnSpec = GridLayout.spec(0) | 
 |  |  |                             rowSpec = GridLayout.spec(index + 1) | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                     gridLayout.addView(textView) | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 添加热力图单元格 | 
 |  |  |                 for (day in 0..6) { | 
 |  |  |                     for (week in 0..51) { | 
 |  |  |                         val count = heatmapMatrix[day][week] | 
 |  |  |                         val cell = View(context).apply { | 
 |  |  |                             layoutParams = GridLayout.LayoutParams().apply { | 
 |  |  |                                 width = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size) | 
 |  |  |                                 height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size) | 
 |  |  |                                 columnSpec = GridLayout.spec(week + 1) | 
 |  |  |                                 rowSpec = GridLayout.spec(day + 1) | 
 |  |  |                                 setMargins(1, 1, 1, 1) | 
 |  |  |                             } | 
 |  |  |                             setBackgroundColor(getHeatmapColor(count)) | 
 |  |  |                         } | 
 |  |  |                         gridLayout.addView(cell) | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 创建图例(Legend) | 
 |  |  |                 val legendLayout = LinearLayout(context).apply { | 
 |  |  |                     orientation = LinearLayout.HORIZONTAL | 
 |  |  |                     gravity = Gravity.END or Gravity.CENTER_VERTICAL // 靠右对齐 | 
 |  |  |                     setPadding(8, 16, 8, 0) | 
 |  |  |                     layoutParams = LinearLayout.LayoutParams( | 
 |  |  |                         ViewGroup.LayoutParams.MATCH_PARENT, | 
 |  |  |                         ViewGroup.LayoutParams.WRAP_CONTENT | 
 |  |  |                     ) | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 左侧“少”标签 | 
 |  |  |                 val labelLow = TextView(context).apply { | 
 |  |  |                     text = "少" | 
 |  |  |                     textSize = 10f | 
 |  |  |                     setPadding(0, 0, 8, 0) | 
 |  |  |                 } | 
 |  |  |                 legendLayout.addView(labelLow) | 
 |  |  |  | 
 |  |  |                 // 渐变色块 + 数值 | 
 |  |  |                 val legendLevels = listOf(0, 5, 10, 15, 20) | 
 |  |  |                 legendLevels.forEach { level -> | 
 |  |  |                     val colorBox = View(context).apply { | 
 |  |  |                         setBackgroundColor(getHeatmapColor(level)) | 
 |  |  |                         val size = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size) | 
 |  |  |                         layoutParams = LinearLayout.LayoutParams(size, size).apply { | 
 |  |  |                             marginEnd = 4 | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |                     val label = TextView(context).apply { | 
 |  |  | //                        text = "$level" | 
 |  |  |                         textSize = 10f | 
 |  |  |                         setPadding(0, 0, 8, 0) | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |                     legendLayout.addView(colorBox) | 
 |  |  |                     legendLayout.addView(label) | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 右侧“多”标签 | 
 |  |  |                 val labelHigh = TextView(context).apply { | 
 |  |  |                     text = "多" | 
 |  |  |                     textSize = 10f | 
 |  |  |                     setPadding(8, 0, 0, 0) | 
 |  |  |                 } | 
 |  |  |                 legendLayout.addView(labelHigh) | 
 |  |  |  | 
 |  |  |                 // 垂直组合 gridLayout + legendLayout | 
 |  |  |                 val container = LinearLayout(context).apply { | 
 |  |  |                     orientation = LinearLayout.VERTICAL | 
 |  |  |                     addView(gridLayout) | 
 |  |  |                     addView(legendLayout) | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 addView(container) | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun getHeatmapColor(count: Int): Int { | 
 |  |  |         return when { | 
 |  |  |             count == 0 -> Color.parseColor("#EBECF1") // 最淡 | 
 |  |  |             count < 5 -> Color.parseColor("#ACE7B1") | 
 |  |  |             count < 10 -> Color.parseColor("#68C16F") | 
 |  |  |             count < 15 -> Color.parseColor("#529F57") | 
 |  |  |             else -> Color.parseColor("#356D40") // 最深 | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     private fun updateHeatmapData_bak() { | 
 |  |  |         viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats -> | 
 |  |  |             if (stats.isEmpty()) return@observe | 
 |  |  |  | 
 |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private fun getHeatmapColor(count: Int): Int { | 
 |  |  |     private fun getHeatmapColor_bak(count: Int): Int { | 
 |  |  |         return when { | 
 |  |  |             count == 0 -> Color.parseColor("#EBEDF0") | 
 |  |  |             count == 1 -> Color.parseColor("#9BE9A8") | 
 |  |  | 
 |  |  |             if (stats.isEmpty()) return@observe | 
 |  |  |              | 
 |  |  |             // 更新年度包裹总数 | 
 |  |  |             binding.layoutYearStats.textTotalPackages.text = "${stats.sumOf { it.count }}个" | 
 |  |  | //            binding.layoutYearStats.textTotalPackages.text = "${stats.sumOf { it.count }}个" | 
 |  |  |              | 
 |  |  |             // 更新平均每天包裹数 | 
 |  |  |             val avgDaily = stats.sumOf { it.count }.toFloat() / 365 |