first commit

This commit is contained in:
ytc1012
2025-11-13 15:45:28 +08:00
commit 6b321890c0
54 changed files with 8412 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
import 'package:flutter/foundation.dart' show kIsWeb;
import '../models/daily_stats.dart';
import '../models/app_usage.dart';
import '../database/app_usage_dao.dart';
import '../database/daily_stats_dao.dart';
import 'mock_data_service.dart';
class StatisticsService {
final AppUsageDao _appUsageDao = AppUsageDao();
final DailyStatsDao _dailyStatsDao = DailyStatsDao();
// 获取今日统计(如果不存在则计算)
Future<DailyStats> getTodayStats() async {
// Web 平台返回测试数据
if (kIsWeb) {
return MockDataService.generateTodayStats();
}
final today = DateTime.now();
// 先查数据库
var stats = await _dailyStatsDao.getTodayStats();
if (stats != null) {
return stats;
}
// 如果不存在,计算并保存
stats = await _calculateDailyStats(today);
if (stats != null) {
await _dailyStatsDao.upsertDailyStats(stats);
} else {
// 如果没有数据,返回空统计
stats = DailyStats(
date: today,
totalTime: 0,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
}
return stats;
}
// 计算指定日期的统计
Future<DailyStats?> _calculateDailyStats(DateTime date) async {
final startOfDay = DateTime(date.year, date.month, date.day);
final endOfDay = startOfDay.add(const Duration(days: 1));
// 获取该日期的所有应用使用记录
final appUsages = await _appUsageDao.getAppUsages(
startTime: startOfDay,
endTime: endOfDay,
);
if (appUsages.isEmpty) return null;
// 按分类聚合
final categoryTime = <String, int>{};
int totalTime = 0;
int appSwitchCount = 0;
for (final usage in appUsages) {
categoryTime[usage.category] = (categoryTime[usage.category] ?? 0) + usage.duration;
totalTime += usage.duration;
appSwitchCount += usage.deviceUnlockCount;
}
// 计算效率评分
final efficiencyScore = _calculateEfficiencyScore(categoryTime, totalTime);
// 计算专注度评分
final focusScore = _calculateFocusScore(appSwitchCount, totalTime);
return DailyStats(
date: startOfDay,
totalTime: totalTime,
workTime: categoryTime['work'] ?? 0,
studyTime: categoryTime['study'] ?? 0,
entertainmentTime: categoryTime['entertainment'] ?? 0,
socialTime: categoryTime['social'] ?? 0,
toolTime: categoryTime['tool'] ?? 0,
efficiencyScore: efficiencyScore,
focusScore: focusScore,
appSwitchCount: appSwitchCount,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
}
// 计算效率评分
int _calculateEfficiencyScore(Map<String, int> categoryTime, int totalTime) {
if (totalTime == 0) return 0;
// 工作时间占比40%
final workRatio = (categoryTime['work'] ?? 0) / totalTime;
final workScore = workRatio * 40;
// 学习时间占比30%
final studyRatio = (categoryTime['study'] ?? 0) / totalTime;
final studyScore = studyRatio * 30;
// 娱乐时间占比越低越好30%
final entertainmentRatio = (categoryTime['entertainment'] ?? 0) / totalTime;
final entertainmentScore = (1 - entertainmentRatio) * 30;
return (workScore + studyScore + entertainmentScore).round();
}
// 计算专注度评分
int _calculateFocusScore(int appSwitchCount, int totalTime) {
if (totalTime == 0) return 0;
// 平均每小时切换次数
final switchesPerHour = (appSwitchCount / (totalTime / 3600));
// 理想情况:每小时切换 < 10 次 = 100分
// 每小时切换 > 50 次 = 0分
final score = 100 - (switchesPerHour * 2).clamp(0, 100);
return score.round();
}
// 获取本周统计
Future<List<DailyStats>> getWeekStats() async {
// Web 平台返回测试数据
if (kIsWeb) {
return MockDataService.generateWeekStats();
}
final stats = await _dailyStatsDao.getWeekStats();
// 如果数据不完整,计算缺失的日期
final now = DateTime.now();
final startOfWeek = now.subtract(Duration(days: now.weekday - 1));
final result = <DailyStats>[];
for (int i = 0; i < 7; i++) {
final date = startOfWeek.add(Duration(days: i));
final existing = stats.firstWhere(
(s) => s.date.year == date.year &&
s.date.month == date.month &&
s.date.day == date.day,
orElse: () => DailyStats(
date: date,
totalTime: 0,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
);
result.add(existing);
}
return result;
}
// 获取本月统计
Future<List<DailyStats>> getMonthStats() async {
return await _dailyStatsDao.getMonthStats();
}
// 刷新今日统计(重新计算)
Future<DailyStats> refreshTodayStats() async {
final today = DateTime.now();
final stats = await _calculateDailyStats(today);
if (stats != null) {
await _dailyStatsDao.upsertDailyStats(stats);
return stats;
} else {
final emptyStats = DailyStats(
date: today,
totalTime: 0,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
await _dailyStatsDao.upsertDailyStats(emptyStats);
return emptyStats;
}
}
// 获取 Top 应用
Future<List<AppUsage>> getTopApps({
required DateTime startTime,
required DateTime endTime,
int limit = 10,
}) async {
// Web 平台返回测试数据
if (kIsWeb) {
return MockDataService.generateTopApps().take(limit).toList();
}
return await _appUsageDao.getTopApps(
startTime: startTime,
endTime: endTime,
limit: limit,
);
}
}