cloudroam
2025-03-12 32b40371a31b3984e01f5a072e8e9c7a1e6acc2b
app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
@@ -23,6 +23,7 @@
import android.graphics.Color
import android.widget.GridLayout
import com.example.firstapp.model.DailyStat
import com.github.mikephil.charting.components.YAxis
class DashboardFragment : Fragment() {
@@ -162,23 +163,20 @@
                position = XAxis.XAxisPosition.BOTTOM
                setDrawGridLines(false)
                granularity = 1f
                labelRotationAngle = -45f
                textSize = 10f
                labelRotationAngle = 0f
                textSize = 10f  //标签字体
                setExtraLeftOffset(5f)  // 减少左侧留白
                setExtraBottomOffset(15f)
            }
            // Y轴设置
            axisLeft.apply {
                setDrawGridLines(true)
                axisMinimum = 0f
                granularity = 0.5f  // 将刻度间隔设为0.5
                granularity = 1f
                valueFormatter = object : ValueFormatter() {
                    override fun getFormattedValue(value: Float): String {
                        // 只有整数时才显示标签
                        return if (value % 1 == 0f) {
                            value.toInt().toString()
                        } else {
                            ""
                        }
                        return if (value > 0) value.toInt().toString() else ""
                    }
                }
            }
@@ -188,8 +186,13 @@
            setTouchEnabled(true)
            isDragEnabled = true
            setScaleEnabled(true)
            // 设置边距
            setExtraOffsets(10f, 10f, 10f, 20f)
        }
        updateBarChartData()
    }
    private fun updateBarChartData() {
@@ -207,7 +210,11 @@
            if (stats.isEmpty()) return@observe
            
            val entries = stats.mapIndexed { index, stat ->
                BarEntry(index.toFloat(), stat.count.toFloat())
                val entry = BarEntry(index.toFloat(), stat.count.toFloat())
                if (stat.count == 0) {
                    entry.data = "hide_label"
                }
                entry
            }
            val dataSet = BarDataSet(entries, "包裹数量")
@@ -216,7 +223,7 @@
                valueTextSize = 12f
                valueFormatter = object : ValueFormatter() {
                    override fun getFormattedValue(value: Float): String {
                        return value.toInt().toString()
                        return if (value > 0) value.toInt().toString() else ""
                    }
                }
            }
@@ -233,13 +240,27 @@
                            return when(currentDateType) {
                                DateType.WEEK -> {
                                    val weekStat = stats[position]
                                    val calendar = Calendar.getInstance()
                                    calendar.timeInMillis = weekStat.weekStart!!
                                    SimpleDateFormat("MM/dd", Locale.getDefault()).format(calendar.time)
                                    try {
                                        // 解析日期字符串
                                        val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                                        val date = sdf.parse(weekStat.date)
                                        val calendar = Calendar.getInstance()
                                        calendar.time = date
                                        // 获取年份和周数
                                        val weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR)
                                        val year = calendar.get(Calendar.YEAR)
                                        // 显示格式:第X周
//                                        "第${weekOfYear}周"
                                        "${weekOfYear}"
                                    } catch (e: Exception) {
                                        weekStat.date
                                    }
                                }
//                                DateType.MONTH -> "${stats[position].date}月"
                                DateType.MONTH -> {
                                    // 显示月份标签(1-12月)
                                    "${position + 1}月"
                                    stats[position].date.replaceFirst("^0+".toRegex(), "")
                                }
                                else -> ""
                            }
@@ -247,15 +268,16 @@
                        return ""
                    }
                }
                position = XAxis.XAxisPosition.BOTTOM
                setDrawGridLines(false)
                labelCount = stats.size
                granularity = 1f
                labelRotationAngle = -45f
                textSize = 10f
                setAvoidFirstLastClipping(true)
                labelRotationAngle = 0f
                // 增加标签间距
//                setExtraBottomOffset(20f)
                textSize = 11f  // 稍微调小字体
            }
            
            // 高亮当前月份
            // 高亮显示
            if (currentDateType == DateType.MONTH) {
                val currentMonth = currentDate.get(Calendar.MONTH)
                dataSet.setColors(List(stats.size) { index ->
@@ -263,42 +285,50 @@
                    else resources.getColor(R.color.purple_200)
                })
            } else if (currentDateType == DateType.WEEK) {
                // 保持周视图的高亮逻辑
                val highlightIndex = 3f
                val highlightIndex = 3 // 当前周在第4个位置
                dataSet.setColors(List(stats.size) { index ->
                    if (index == 3) resources.getColor(R.color.purple_500)
                    if (index == highlightIndex) resources.getColor(R.color.purple_500)
                    else resources.getColor(R.color.purple_200)
                })
            }
            
            // 刷新图表
            barChart.notifyDataSetChanged()
            barChart.invalidate()
        }
    }
    private fun setupPieChart() {
        pieChart.apply {
            // 隐藏图表描述(右下角默认文字)
            description.isEnabled = false
            // 显示实际值而非百分比
            setUsePercentValues(false)
            // 隐藏饼图区块上的标签(如数值或名称)
            setDrawEntryLabels(false)
            // 调整饼图边距
            setExtraOffsets(20f, 10f, 60f, 10f)
            // 设置饼图与容器的边距,参数顺序:左、上、右、下
            // 右侧留出 80f 空间,可能为图例腾出位置
            setExtraOffsets(20f, 20f, 20f, 20f)
            // 配置图例
            legend.apply {
                isEnabled = true
                verticalAlignment = Legend.LegendVerticalAlignment.CENTER
                horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT
                orientation = Legend.LegendOrientation.VERTICAL
                setDrawInside(false)
                xEntrySpace = 10f
                yEntrySpace = 5f
                yOffset = 0f
                textSize = 14f
                isEnabled = true // 启用图例
                verticalAlignment = Legend.LegendVerticalAlignment.CENTER // 垂直居中
                horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT // 水平靠右对齐
                orientation = Legend.LegendOrientation.VERTICAL // 图例项垂直排列
                setDrawInside(false)  // 图例绘制在图表外部(而非覆盖在图上)
                xEntrySpace = 10f  // 图例项水平间距
                yEntrySpace = 5f  // 图例项垂直间距
                yOffset = 0f      // 图例整体 Y 轴无偏移
                textSize = 12f   // 图例文字大小
            }
            // 设置中心空白
            holeRadius = 45f
            transparentCircleRadius = 50f
            // 调整中心空白区域大小
            holeRadius = 20f  // 中间空心圆的半径(占饼图比例)
            transparentCircleRadius = 25f  // 透明圆圈的半径(可能用于边框效果)
        }
        updatePieChartData()
@@ -341,8 +371,38 @@
            currentDate.timeInMillis,
            currentDateType.name
        ).observe(viewLifecycleOwner) { packages ->
            when (currentDateType) {
                DateType.DAY -> {
                    binding.textPackageCount.text = "${packages.size}个"
                }
                DateType.WEEK -> {
                    // 获取本周统计
                    viewModel.getCurrentWeekStats(currentDate.timeInMillis)
                        .observe(viewLifecycleOwner) { stats ->
                            val weekTotal = stats.sumOf { it.count }
                            binding.textPackageCount.text = "${weekTotal}个"
                        }
                }
                DateType.MONTH -> {
                    // 获取本月统计
                    viewModel.getMonthlyStats(currentDate.timeInMillis)
                        .observe(viewLifecycleOwner) { stats ->
                            val monthTotal = stats.sumOf { it.count }
                            binding.textPackageCount.text = "${monthTotal}个"
                        }
                }
                DateType.YEAR -> {
                    // 获取本年统计
                    viewModel.getCurrentYearStats(currentDate.timeInMillis)
                        .observe(viewLifecycleOwner) { stats ->
                            val yearTotal = stats.sumOf { it.count }
                            binding.textPackageCount.text = "${yearTotal}个"
                        }
                }
            }
            packageAdapter.updatePackages(packages)
            binding.textPackageCount.text = "${packages.size}个"
            packageAdapter.updatePackages(packages)
//            binding.textPackageCount.text = "${packages.size}个"
        }
    }
    private fun setupHeatmap() {
@@ -367,24 +427,44 @@
            // 更新UI
            binding.layoutWeekStats.heatmapYearly.apply {
                // 清除现有的子视图
                removeAllViews()
                
                // 创建网格布局
                val gridLayout = GridLayout(context).apply {
                    rowCount = 7
                    columnCount = 52
                    rowCount = 8 // 增加一行用于显示月份
                    columnCount = 53 // 增加一列用于显示星期标签
                }
                // 添加日期标签
                val dayLabels = arrayOf("周日", "周一", "周二", "周三", "周四", "周五", "周六")
                for (i in 0..6) {
                // 添加月份标签
                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 = dayLabels[i]
                        text = month
                        textSize = 10f
                        setPadding(0, 0, 8, 0)
                        setPadding(0, 0, 8, 4)
                        // 计算每个月份标签的位置
                        val weekPosition = (index * 4.3).toInt()
                        val params = GridLayout.LayoutParams()
                        params.columnSpec = GridLayout.spec(weekPosition + 1)
                        params.rowSpec = GridLayout.spec(0)
                        layoutParams = params
                    }
                    gridLayout.addView(label)
                }
                // 添加星期标签
                val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
                dayLabels.forEachIndexed { index, label ->
                    val textView = TextView(context).apply {
                        text = label
                        textSize = 10f
                        setPadding(4, 0, 8, 0)
                        val params = GridLayout.LayoutParams()
                        params.columnSpec = GridLayout.spec(0)
                        params.rowSpec = GridLayout.spec(index + 1)
                        layoutParams = params
                    }
                    gridLayout.addView(textView)
                }
                // 添加热力图单元格
@@ -392,12 +472,15 @@
                    for (week in 0..51) {
                        val count = heatmapMatrix[day][week]
                        val cell = View(context).apply {
                            layoutParams = ViewGroup.LayoutParams(
                                resources.getDimensionPixelSize(R.dimen.heatmap_cell_size),
                                resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
                            )
                            val params = 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)
                            }
                            layoutParams = params
                            setBackgroundColor(getHeatmapColor(count))
                            setPadding(1, 1, 1, 1)
                        }
                        gridLayout.addView(cell)
                    }
@@ -409,12 +492,11 @@
    }
    private fun getHeatmapColor(count: Int): Int {
        // 根据数量返回不同深浅的颜色
        return when {
            count == 0 -> Color.parseColor("#EBEDF0")
            count <= 2 -> Color.parseColor("#9BE9A8")
            count <= 4 -> Color.parseColor("#40C463")
            count <= 6 -> Color.parseColor("#30A14E")
            count == 1 -> Color.parseColor("#9BE9A8")
            count == 2 -> Color.parseColor("#40C463")
            count <= 4 -> Color.parseColor("#30A14E")
            else -> Color.parseColor("#216E39")
        }
    }
@@ -426,6 +508,7 @@
                binding.recyclerPackages.visibility = View.VISIBLE
                binding.layoutWeekStats.root.visibility = View.GONE
                binding.layoutYearStats.root.visibility = View.GONE
                binding.cardPackageStats.visibility = View.VISIBLE
            }
            DateType.WEEK, DateType.MONTH -> {
                // 周和月视图显示柱状图和饼图,隐藏包裹列表
@@ -433,7 +516,9 @@
                binding.layoutWeekStats.root.visibility = View.VISIBLE
                binding.layoutYearStats.root.visibility = View.GONE
                binding.layoutWeekStats.chartDailyPackages.visibility = View.VISIBLE
                (binding.layoutWeekStats.chartDailyPackages.parent as? View)?.visibility = View.VISIBLE
                binding.layoutWeekStats.heatmapYearly.visibility = View.GONE
                binding.cardPackageStats.visibility = View.VISIBLE
                updateBarChartData()
                updatePieChartData()
            }
@@ -442,10 +527,12 @@
                binding.recyclerPackages.visibility = View.GONE
                binding.layoutWeekStats.root.visibility = View.VISIBLE
                binding.layoutYearStats.root.visibility = View.VISIBLE
                binding.layoutWeekStats.chartDailyPackages.visibility = View.GONE
                (binding.layoutWeekStats.chartDailyPackages.parent as? View)?.visibility = View.GONE
                binding.layoutWeekStats.heatmapYearly.visibility = View.VISIBLE
                binding.cardPackageStats.visibility = View.GONE
                updateHeatmapData()
                updatePieChartData()
                updateYearlyStats()
            }
        }
    }