import 'package:flisp_app/models/flisp.dart'; import 'package:flisp_app/models/todo.dart'; import 'package:flisp_app/service/flisp_service.dart'; import 'package:flisp_app/service/todo_service.dart'; import 'package:flisp_app/widgets/chart.dart'; import 'package:flisp_app/widgets/common.dart'; import 'package:flisp_app/widgets/flisp_widget.dart'; import 'package:flisp_app/widgets/todo_widget.dart'; import 'package:flisp_app/widgets/year_selector.dart'; import 'package:flutter/material.dart'; class StatsPage extends StatefulWidget { const StatsPage({super.key}); @override StatsPageState createState() => StatsPageState(); } class StatsPageState extends State { final double chartHeight = 400; final double statsHeight = 120; int currentYear = DateTime.now().year; final FlispService flispService = FlispService(); final TodoService todoService = TodoService(); late List allFlisps; late List allTodos; late List flispMonthlyStats; late List flispCategoryStats; late List todoMonthlyStats; late List todoMonthlyCompleteStats; late List todoPriorityStats; @override void initState() { super.initState(); refreshStats(); } void refreshStats() { allFlisps = flispService.getAllFlispsByYear(currentYear); getFlispMonthlyStats(allFlisps); getFlispCategoryStats(allFlisps); allTodos = todoService.getAllTodosByYear(currentYear); getTodoMonthlyStats(allTodos); getTodoMonthlyCompleteStats(allTodos); getTodoCategoryStats(allTodos); } void getFlispMonthlyStats(List flisps) { Map countMap = {}; for (var flisp in flisps) { String month = '${flisp.createTime.month}月'; countMap[month] = (countMap[month] ?? 0) + 1; } flispMonthlyStats = convert2ChartData(countMap); } void getFlispCategoryStats(List flisps) { Map countMap = {}; for (var flisp in flisps) { String category = flisp.tag.label; countMap[category] = (countMap[category] ?? 0) + 1; } flispCategoryStats = convert2ChartData(countMap); } void getTodoMonthlyStats(List todos) { Map countMap = {}; for (var todo in todos) { String month = '${todo.createTime.month}月'; countMap[month] = (countMap[month] ?? 0) + 1; } todoMonthlyStats = convert2ChartData(countMap); } void getTodoMonthlyCompleteStats(List todos) { Map countMap = {}; for (var todo in todos) { if (todo.isCompleted) { String month = '${todo.createTime.month}月'; countMap[month] = (countMap[month] ?? 0) + 1; } } todoMonthlyCompleteStats = convert2ChartData(countMap); } void getTodoCategoryStats(List todos) { Map countMap = {}; for (var todo in todos) { String priority = todo.priority.label; countMap[priority] = (countMap[priority] ?? 0) + 1; } todoPriorityStats = convert2ChartData(countMap); } List convert2ChartData(Map countMap) { return countMap.entries .map((e) => ChartData(name: e.key, value: e.value)) .toList(); } Widget _buildFlispStats(BuildContext context) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Icon(Icons.analytics, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 3), const Text('闪灵统计'), ], ), const SizedBox(height: 5), buildFlispStatsCard(context, allFlisps), ], ); } Widget _buildFlispMonthlyStats(BuildContext context) { return Column( children: [ buildChartTitle(context, '每月闪灵数量统计', Icons.show_chart), const SizedBox(height: 3), buildChartDivider(context), const SizedBox(height: 3), Expanded( child: lineChart( context: context, xAxisName: '月份', yAxisName: '数量', unit: '篇', data: flispMonthlyStats, ), ), ], ); } Widget _buildFlispCategoryStats(BuildContext context) { return Column( children: [ buildChartTitle(context, '闪灵分类统计', Icons.pie_chart), const SizedBox(height: 3), buildChartDivider(context), const SizedBox(height: 3), Expanded( child: pieChart( context: context, unit: '篇', data: flispCategoryStats, ), ), ], ); } Widget _buildTodoStats(BuildContext context) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Icon(Icons.analytics, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 3), const Text('待办统计'), ], ), const SizedBox(height: 5), Expanded(child: buildTodoStatsCard(context, allTodos)), ], ); } Widget _buildTodoMonthlyStats(BuildContext context) { return Column( children: [ buildChartTitle(context, '每月待办数量统计', Icons.bar_chart), const SizedBox(height: 3), buildChartDivider(context), const SizedBox(height: 3), Expanded( child: doubleBarChart( context: context, xAxisName: '月份', yAxisName: '数量', unit: '个', data1: todoMonthlyStats, data2: todoMonthlyCompleteStats, series1Name: '总数', series2Name: '完成数', ), ), ], ); } Widget _buildTodoPriorityStats(BuildContext context) { return Column( children: [ buildChartTitle(context, '待办分类统计', Icons.pie_chart), const SizedBox(height: 3), buildChartDivider(context), const SizedBox(height: 3), Expanded( child: pieChart(context: context, unit: '个', data: todoPriorityStats), ), ], ); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: [ YearSelector( initialYear: DateTime.now().year, minYear: 2000, maxYear: 2100, onYearChanged: (year) => { setState(() { currentYear = year; refreshStats(); }), }, ), SizedBox(height: statsHeight, child: _buildFlispStats(context)), SizedBox(height: 10), SizedBox(height: statsHeight, child: _buildTodoStats(context)), SizedBox(height: 10), SizedBox( height: chartHeight, child: BuildCard(child: _buildFlispMonthlyStats(context)), ), SizedBox(height: 10), SizedBox( height: chartHeight, child: BuildCard(child: _buildFlispCategoryStats(context)), ), SizedBox(height: 10), SizedBox( height: chartHeight, child: BuildCard(child: _buildTodoMonthlyStats(context)), ), SizedBox(height: 10), SizedBox( height: chartHeight, child: BuildCard(child: _buildTodoPriorityStats(context)), ), ], ), ); } }