Files
xianyan/lib/features/study_plan/study_plan_service.dart
Developer f91be94e9c refactor: 完成项目架构重构,统一模块导入路径
- 清理大量废弃的 barrel 导出文件,移除冗余的中间导出层
- 修复所有相对路径导入错误,统一调整为扁平化模块引用
- 更新多平台 pubspec 版本号与依赖库版本
- 补充后端功能问题管理后台与脚本工具
- 调整部分页面的快捷方式文案适配新功能
- 更新部分翻译覆盖率与API文档
2026-06-12 08:53:57 +08:00

145 lines
4.3 KiB
Dart

/// ============================================================
/// 闲言APP — 学习计划服务
/// 创建时间: 2026-05-02
/// 更新时间: 2026-06-12
/// 作用: 学习计划 CRUD + 进度计算 + 连续天数
/// 上次更新: 从 services/ 子目录移至 study_plan 模块根目录
/// ============================================================
import 'package:drift/drift.dart' show Value;
import '../../../core/storage/database/app_database.dart';
import '../../../core/utils/logger.dart';
import 'study_plan_models.dart';
class StudyPlanService {
StudyPlanService._();
static final _db = AppDatabase.instance;
static Future<int> createPlan({
required String title,
required PlanCategory category,
required int dailyGoal,
String description = '',
}) async {
try {
final now = DateTime.now();
final id = await _db.insertLearningPlan(
LearningPlansCompanion.insert(
title: title,
description: Value(description),
category: Value(category.name),
dailyGoal: Value(dailyGoal),
startDate: now,
createdAt: now,
updatedAt: now,
),
);
Log.i('学习计划: 创建成功 id=$id title=$title');
return id;
} catch (e) {
Log.e('学习计划: 创建失败', e);
return -1;
}
}
static Future<List<LearningPlan>> getActivePlans() async {
try {
return _db.getActiveLearningPlans();
} catch (e) {
Log.e('学习计划: 获取活跃计划失败', e);
return [];
}
}
static Future<List<LearningPlan>> getAllPlans() async {
try {
return _db.getAllLearningPlans();
} catch (e) {
Log.e('学习计划: 获取全部计划失败', e);
return [];
}
}
static Future<void> completeDailyGoal(int planId, {String? contentId, String? title, String? contentType, int durationSeconds = 0}) async {
try {
await _db.insertLearningRecord(
LearningRecordsCompanion.insert(
planId: planId,
contentId: Value(contentId ?? ''),
contentType: Value(contentType ?? 'poetry'),
title: Value(title ?? ''),
durationSeconds: Value(durationSeconds),
completedAt: DateTime.now(),
),
);
final plan = await _db.getLearningPlan(planId);
if (plan != null) {
final todayRecords = await _db.getTodayLearningRecords(planId: planId);
final newStreak = _calculateNewStreak(plan, todayRecords.length);
final newTotal = plan.totalCompleted + 1;
await _db.updateLearningPlan(
LearningPlansCompanion(
id: Value(planId),
streakDays: Value(newStreak),
totalCompleted: Value(newTotal),
updatedAt: Value(DateTime.now()),
),
);
}
Log.i('学习计划: 完成任务 planId=$planId');
} catch (e) {
Log.e('学习计划: 完成任务失败', e);
}
}
static Future<void> togglePlanActive(int planId, bool isActive) async {
try {
await _db.updateLearningPlan(
LearningPlansCompanion(
id: Value(planId),
isActive: Value(isActive),
updatedAt: Value(DateTime.now()),
),
);
Log.i('学习计划: 切换状态 planId=$planId isActive=$isActive');
} catch (e) {
Log.e('学习计划: 切换状态失败', e);
}
}
static Future<void> deletePlan(int planId) async {
try {
await _db.deleteLearningRecordsByPlan(planId);
await _db.deleteLearningPlan(planId);
Log.i('学习计划: 删除成功 planId=$planId');
} catch (e) {
Log.e('学习计划: 删除失败', e);
}
}
static Future<int> getTodayCompletedCount(int planId) async {
final records = await _db.getTodayLearningRecords(planId: planId);
return records.length;
}
static Future<double> getTodayProgress(int planId, int dailyGoal) async {
final count = await getTodayCompletedCount(planId);
return (count / dailyGoal).clamp(0.0, 1.0);
}
static Future<List<LearningRecord>> getPlanRecords(int planId, {int limit = 50}) async {
return _db.getLearningRecords(planId, limit: limit);
}
static int _calculateNewStreak(LearningPlan plan, int todayCount) {
if (todayCount >= plan.dailyGoal) {
return plan.streakDays + 1;
}
return plan.streakDays;
}
}