| | |
| | | import java.util.* |
| | | import java.text.SimpleDateFormat |
| | | import android.graphics.Color |
| | | import android.widget.Button |
| | | import android.widget.GridLayout |
| | | 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 showOverlay() { |
| | | binding.viewOverlay.visibility = View.VISIBLE |
| | | binding.viewOverlay.visibility = View.VISIBLE |
| | | binding.overlayContent.visibility = View.VISIBLE |
| | | |
| | | } |
| | | |
| | | private fun hiddleOverlay() { |
| | | binding.viewOverlay.visibility = View.GONE |
| | | binding.viewOverlay.visibility = View.GONE |
| | | binding.overlayContent.visibility = View.GONE |
| | | |
| | | |
| | | } |
| | |
| | | } |
| | | |
| | | 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}个" |
| | | } |
| | | } |
| | |
| | | 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 |