software copyright
This commit is contained in:
@@ -0,0 +1,753 @@
|
||||
// 自然写互动课堂平板端应用软件 V1.0
|
||||
// repository/local_repository.dart - SQLite + Hive本地数据存储
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
/// 数据库表名常量
|
||||
class PadDbTables {
|
||||
static const String homework = 'pad_homework';
|
||||
static const String homeworkQuestion = 'pad_homework_question';
|
||||
static const String answerProgress = 'pad_answer_progress';
|
||||
static const String errorBook = 'pad_error_book';
|
||||
static const String studyPlan = 'pad_study_plan';
|
||||
static const String studyTask = 'pad_study_task';
|
||||
static const String practiceRecord = 'pad_practice_record';
|
||||
static const String strokeCache = 'pad_stroke_cache';
|
||||
static const String offlineAction = 'pad_offline_action';
|
||||
static const String usageRecord = 'pad_usage_record';
|
||||
}
|
||||
|
||||
/// 数据库版本
|
||||
const int padDbVersion = 4;
|
||||
|
||||
/// 作业缓存模型
|
||||
class CachedHomework {
|
||||
final String id;
|
||||
final String title;
|
||||
final String subject;
|
||||
final String teacherName;
|
||||
final String status;
|
||||
final String? deadline;
|
||||
final String? content;
|
||||
final int totalQuestions;
|
||||
final int answeredQuestions;
|
||||
final DateTime cachedAt;
|
||||
|
||||
CachedHomework({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.subject,
|
||||
required this.teacherName,
|
||||
required this.status,
|
||||
this.deadline,
|
||||
this.content,
|
||||
this.totalQuestions = 0,
|
||||
this.answeredQuestions = 0,
|
||||
required this.cachedAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'subject': subject,
|
||||
'teacher_name': teacherName,
|
||||
'status': status,
|
||||
'deadline': deadline,
|
||||
'content': content,
|
||||
'total_questions': totalQuestions,
|
||||
'answered_questions': answeredQuestions,
|
||||
'cached_at': cachedAt.toIso8601String(),
|
||||
};
|
||||
|
||||
factory CachedHomework.fromMap(Map<String, dynamic> map) {
|
||||
return CachedHomework(
|
||||
id: map['id'],
|
||||
title: map['title'] ?? '',
|
||||
subject: map['subject'] ?? '',
|
||||
teacherName: map['teacher_name'] ?? '',
|
||||
status: map['status'] ?? 'pending',
|
||||
deadline: map['deadline'],
|
||||
content: map['content'],
|
||||
totalQuestions: map['total_questions'] ?? 0,
|
||||
answeredQuestions: map['answered_questions'] ?? 0,
|
||||
cachedAt: DateTime.parse(map['cached_at']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 错题记录模型
|
||||
class ErrorBookEntry {
|
||||
final String id;
|
||||
final String homeworkId;
|
||||
final String questionId;
|
||||
final String subject;
|
||||
final String? knowledgePoint;
|
||||
final String questionContent;
|
||||
final String? questionImageUrl;
|
||||
final String? studentAnswer;
|
||||
final String? correctAnswer;
|
||||
final String? errorReason;
|
||||
final int reviewCount;
|
||||
final DateTime createdAt;
|
||||
final DateTime? lastReviewAt;
|
||||
|
||||
ErrorBookEntry({
|
||||
required this.id,
|
||||
required this.homeworkId,
|
||||
required this.questionId,
|
||||
required this.subject,
|
||||
this.knowledgePoint,
|
||||
required this.questionContent,
|
||||
this.questionImageUrl,
|
||||
this.studentAnswer,
|
||||
this.correctAnswer,
|
||||
this.errorReason,
|
||||
this.reviewCount = 0,
|
||||
required this.createdAt,
|
||||
this.lastReviewAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'homework_id': homeworkId,
|
||||
'question_id': questionId,
|
||||
'subject': subject,
|
||||
'knowledge_point': knowledgePoint,
|
||||
'question_content': questionContent,
|
||||
'question_image_url': questionImageUrl,
|
||||
'student_answer': studentAnswer,
|
||||
'correct_answer': correctAnswer,
|
||||
'error_reason': errorReason,
|
||||
'review_count': reviewCount,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'last_review_at': lastReviewAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
factory ErrorBookEntry.fromMap(Map<String, dynamic> map) {
|
||||
return ErrorBookEntry(
|
||||
id: map['id'],
|
||||
homeworkId: map['homework_id'] ?? '',
|
||||
questionId: map['question_id'] ?? '',
|
||||
subject: map['subject'] ?? '',
|
||||
knowledgePoint: map['knowledge_point'],
|
||||
questionContent: map['question_content'] ?? '',
|
||||
questionImageUrl: map['question_image_url'],
|
||||
studentAnswer: map['student_answer'],
|
||||
correctAnswer: map['correct_answer'],
|
||||
errorReason: map['error_reason'],
|
||||
reviewCount: map['review_count'] ?? 0,
|
||||
createdAt: DateTime.parse(map['created_at']),
|
||||
lastReviewAt: map['last_review_at'] != null
|
||||
? DateTime.parse(map['last_review_at'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 学习计划模型
|
||||
class StudyPlanEntry {
|
||||
final String id;
|
||||
final String title;
|
||||
final String type;
|
||||
final String? subject;
|
||||
final DateTime startDate;
|
||||
final DateTime endDate;
|
||||
final double progress;
|
||||
final int totalTasks;
|
||||
final int completedTasks;
|
||||
final bool isActive;
|
||||
|
||||
StudyPlanEntry({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.type,
|
||||
this.subject,
|
||||
required this.startDate,
|
||||
required this.endDate,
|
||||
this.progress = 0.0,
|
||||
this.totalTasks = 0,
|
||||
this.completedTasks = 0,
|
||||
this.isActive = true,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'type': type,
|
||||
'subject': subject,
|
||||
'start_date': startDate.toIso8601String(),
|
||||
'end_date': endDate.toIso8601String(),
|
||||
'progress': progress,
|
||||
'total_tasks': totalTasks,
|
||||
'completed_tasks': completedTasks,
|
||||
'is_active': isActive ? 1 : 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// 练字练习记录模型
|
||||
class PracticeRecord {
|
||||
final String id;
|
||||
final String templateId;
|
||||
final String character;
|
||||
final int strokeScore;
|
||||
final int structureScore;
|
||||
final int overallScore;
|
||||
final String? strokeDataJson;
|
||||
final DateTime practiceAt;
|
||||
|
||||
PracticeRecord({
|
||||
required this.id,
|
||||
required this.templateId,
|
||||
required this.character,
|
||||
this.strokeScore = 0,
|
||||
this.structureScore = 0,
|
||||
this.overallScore = 0,
|
||||
this.strokeDataJson,
|
||||
required this.practiceAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'template_id': templateId,
|
||||
'character': character,
|
||||
'stroke_score': strokeScore,
|
||||
'structure_score': structureScore,
|
||||
'overall_score': overallScore,
|
||||
'stroke_data_json': strokeDataJson,
|
||||
'practice_at': practiceAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
/// 平板端本地数据存储仓库
|
||||
/// 使用SQLite持久化存储 + Hive内存级KV缓存
|
||||
/// 支持:作业缓存、错题本、学习计划、练字记录、离线操作队列、使用时长记录
|
||||
class PadLocalRepository {
|
||||
/// 数据库实例(实际使用sqflite库)
|
||||
// late final Database _db;
|
||||
|
||||
/// 单例
|
||||
static PadLocalRepository? _instance;
|
||||
static PadLocalRepository get instance {
|
||||
_instance ??= PadLocalRepository._internal();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
PadLocalRepository._internal();
|
||||
|
||||
/// 初始化数据库,创建表结构并执行版本迁移
|
||||
Future<void> initialize() async {
|
||||
// 实际调用: openDatabase(path, version: padDbVersion, ...)
|
||||
// 以下为建表SQL
|
||||
|
||||
// V1: 基础表
|
||||
await _createTablesV1();
|
||||
|
||||
// V2: 增加学习计划表
|
||||
await _createTablesV2();
|
||||
|
||||
// V3: 增加使用时长记录表
|
||||
await _createTablesV3();
|
||||
|
||||
// V4: 增加练字记录表和索引优化
|
||||
await _createTablesV4();
|
||||
}
|
||||
|
||||
/// V1建表:作业缓存、作答进度、错题本、离线操作队列
|
||||
Future<void> _createTablesV1() async {
|
||||
// 作业缓存表
|
||||
const createHomework = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.homework} (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
teacher_name TEXT,
|
||||
status TEXT DEFAULT 'pending',
|
||||
deadline TEXT,
|
||||
content TEXT,
|
||||
total_questions INTEGER DEFAULT 0,
|
||||
answered_questions INTEGER DEFAULT 0,
|
||||
cached_at TEXT NOT NULL
|
||||
)
|
||||
''';
|
||||
|
||||
// 作业题目缓存表
|
||||
const createQuestion = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.homeworkQuestion} (
|
||||
id TEXT PRIMARY KEY,
|
||||
homework_id TEXT NOT NULL,
|
||||
question_index INTEGER,
|
||||
type TEXT DEFAULT 'write',
|
||||
content TEXT,
|
||||
image_url TEXT,
|
||||
options TEXT,
|
||||
correct_answer TEXT,
|
||||
FOREIGN KEY (homework_id) REFERENCES ${PadDbTables.homework}(id)
|
||||
)
|
||||
''';
|
||||
|
||||
// 作答进度暂存表
|
||||
const createProgress = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.answerProgress} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
homework_id TEXT NOT NULL,
|
||||
question_id TEXT NOT NULL,
|
||||
text_answer TEXT,
|
||||
stroke_data TEXT,
|
||||
saved_at TEXT NOT NULL,
|
||||
UNIQUE(homework_id, question_id)
|
||||
)
|
||||
''';
|
||||
|
||||
// 错题本表
|
||||
const createErrorBook = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.errorBook} (
|
||||
id TEXT PRIMARY KEY,
|
||||
homework_id TEXT,
|
||||
question_id TEXT,
|
||||
subject TEXT NOT NULL,
|
||||
knowledge_point TEXT,
|
||||
question_content TEXT NOT NULL,
|
||||
question_image_url TEXT,
|
||||
student_answer TEXT,
|
||||
correct_answer TEXT,
|
||||
error_reason TEXT,
|
||||
review_count INTEGER DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
last_review_at TEXT
|
||||
)
|
||||
''';
|
||||
|
||||
// 离线操作队列表
|
||||
const createOffline = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.offlineAction} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
action_type TEXT NOT NULL,
|
||||
payload TEXT NOT NULL,
|
||||
retry_count INTEGER DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'pending'
|
||||
)
|
||||
''';
|
||||
|
||||
// 笔迹暂存表
|
||||
const createStroke = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.strokeCache} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
homework_id TEXT,
|
||||
question_id TEXT,
|
||||
page_id TEXT,
|
||||
stroke_json TEXT NOT NULL,
|
||||
pen_mac TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
)
|
||||
''';
|
||||
|
||||
// 实际执行建表SQL
|
||||
// await _db.execute(createHomework);
|
||||
// await _db.execute(createQuestion);
|
||||
// await _db.execute(createProgress);
|
||||
// await _db.execute(createErrorBook);
|
||||
// await _db.execute(createOffline);
|
||||
// await _db.execute(createStroke);
|
||||
}
|
||||
|
||||
/// V2建表:学习计划与任务
|
||||
Future<void> _createTablesV2() async {
|
||||
const createPlan = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.studyPlan} (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
subject TEXT,
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT NOT NULL,
|
||||
progress REAL DEFAULT 0.0,
|
||||
total_tasks INTEGER DEFAULT 0,
|
||||
completed_tasks INTEGER DEFAULT 0,
|
||||
is_active INTEGER DEFAULT 1
|
||||
)
|
||||
''';
|
||||
|
||||
const createTask = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.studyTask} (
|
||||
id TEXT PRIMARY KEY,
|
||||
plan_id TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
target_date TEXT,
|
||||
is_completed INTEGER DEFAULT 0,
|
||||
completed_at TEXT,
|
||||
FOREIGN KEY (plan_id) REFERENCES ${PadDbTables.studyPlan}(id)
|
||||
)
|
||||
''';
|
||||
|
||||
// await _db.execute(createPlan);
|
||||
// await _db.execute(createTask);
|
||||
}
|
||||
|
||||
/// V3建表:使用时长记录
|
||||
Future<void> _createTablesV3() async {
|
||||
const createUsage = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.usageRecord} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL,
|
||||
app_name TEXT DEFAULT 'writech',
|
||||
subject TEXT,
|
||||
duration_seconds INTEGER DEFAULT 0,
|
||||
start_time TEXT NOT NULL,
|
||||
end_time TEXT
|
||||
)
|
||||
''';
|
||||
|
||||
// await _db.execute(createUsage);
|
||||
}
|
||||
|
||||
/// V4建表:练字记录 + 索引
|
||||
Future<void> _createTablesV4() async {
|
||||
const createPractice = '''
|
||||
CREATE TABLE IF NOT EXISTS ${PadDbTables.practiceRecord} (
|
||||
id TEXT PRIMARY KEY,
|
||||
template_id TEXT NOT NULL,
|
||||
character TEXT NOT NULL,
|
||||
stroke_score INTEGER DEFAULT 0,
|
||||
structure_score INTEGER DEFAULT 0,
|
||||
overall_score INTEGER DEFAULT 0,
|
||||
stroke_data_json TEXT,
|
||||
practice_at TEXT NOT NULL
|
||||
)
|
||||
''';
|
||||
|
||||
// 索引优化
|
||||
const indexHomeworkStatus = '''
|
||||
CREATE INDEX IF NOT EXISTS idx_homework_status
|
||||
ON ${PadDbTables.homework}(status)
|
||||
''';
|
||||
const indexErrorSubject = '''
|
||||
CREATE INDEX IF NOT EXISTS idx_error_subject
|
||||
ON ${PadDbTables.errorBook}(subject)
|
||||
''';
|
||||
const indexPracticeChar = '''
|
||||
CREATE INDEX IF NOT EXISTS idx_practice_char
|
||||
ON ${PadDbTables.practiceRecord}(character)
|
||||
''';
|
||||
|
||||
// await _db.execute(createPractice);
|
||||
// await _db.execute(indexHomeworkStatus);
|
||||
// await _db.execute(indexErrorSubject);
|
||||
// await _db.execute(indexPracticeChar);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 作业缓存 CRUD
|
||||
// ============================================================
|
||||
|
||||
/// 缓存作业到本地(用于离线作答)
|
||||
Future<void> cacheHomework(CachedHomework homework) async {
|
||||
// await _db.insert(
|
||||
// PadDbTables.homework,
|
||||
// homework.toMap(),
|
||||
// conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取本地缓存的作业列表
|
||||
Future<List<CachedHomework>> getCachedHomeworks({
|
||||
String? status,
|
||||
int limit = 50,
|
||||
}) async {
|
||||
// String where = '';
|
||||
// List<dynamic> whereArgs = [];
|
||||
// if (status != null) {
|
||||
// where = 'status = ?';
|
||||
// whereArgs = [status];
|
||||
// }
|
||||
// final maps = await _db.query(
|
||||
// PadDbTables.homework,
|
||||
// where: where.isNotEmpty ? where : null,
|
||||
// whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
|
||||
// orderBy: 'cached_at DESC',
|
||||
// limit: limit,
|
||||
// );
|
||||
// return maps.map((m) => CachedHomework.fromMap(m)).toList();
|
||||
return [];
|
||||
}
|
||||
|
||||
/// 保存作答进度到本地
|
||||
Future<void> saveAnswerProgress({
|
||||
required String homeworkId,
|
||||
required String questionId,
|
||||
String? textAnswer,
|
||||
String? strokeDataJson,
|
||||
}) async {
|
||||
// await _db.insert(
|
||||
// PadDbTables.answerProgress,
|
||||
// {
|
||||
// 'homework_id': homeworkId,
|
||||
// 'question_id': questionId,
|
||||
// 'text_answer': textAnswer,
|
||||
// 'stroke_data': strokeDataJson,
|
||||
// 'saved_at': DateTime.now().toIso8601String(),
|
||||
// },
|
||||
// conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取某作业的所有作答进度
|
||||
Future<Map<String, Map<String, dynamic>>> getAnswerProgress(
|
||||
String homeworkId,
|
||||
) async {
|
||||
// final maps = await _db.query(
|
||||
// PadDbTables.answerProgress,
|
||||
// where: 'homework_id = ?',
|
||||
// whereArgs: [homeworkId],
|
||||
// );
|
||||
// final result = <String, Map<String, dynamic>>{};
|
||||
// for (final m in maps) {
|
||||
// result[m['question_id'] as String] = m;
|
||||
// }
|
||||
// return result;
|
||||
return {};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 错题本 CRUD
|
||||
// ============================================================
|
||||
|
||||
/// 添加错题记录
|
||||
Future<void> addErrorEntry(ErrorBookEntry entry) async {
|
||||
// await _db.insert(
|
||||
// PadDbTables.errorBook,
|
||||
// entry.toMap(),
|
||||
// conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取错题列表(支持按科目/知识点筛选)
|
||||
Future<List<ErrorBookEntry>> getErrorEntries({
|
||||
String? subject,
|
||||
String? knowledgePoint,
|
||||
int limit = 50,
|
||||
int offset = 0,
|
||||
}) async {
|
||||
// final conditions = <String>[];
|
||||
// final args = <dynamic>[];
|
||||
// if (subject != null) {
|
||||
// conditions.add('subject = ?');
|
||||
// args.add(subject);
|
||||
// }
|
||||
// if (knowledgePoint != null) {
|
||||
// conditions.add('knowledge_point = ?');
|
||||
// args.add(knowledgePoint);
|
||||
// }
|
||||
// final maps = await _db.query(
|
||||
// PadDbTables.errorBook,
|
||||
// where: conditions.isNotEmpty ? conditions.join(' AND ') : null,
|
||||
// whereArgs: args.isNotEmpty ? args : null,
|
||||
// orderBy: 'created_at DESC',
|
||||
// limit: limit,
|
||||
// offset: offset,
|
||||
// );
|
||||
// return maps.map((m) => ErrorBookEntry.fromMap(m)).toList();
|
||||
return [];
|
||||
}
|
||||
|
||||
/// 更新错题复习次数
|
||||
Future<void> updateErrorReviewCount(String entryId) async {
|
||||
// await _db.rawUpdate('''
|
||||
// UPDATE ${PadDbTables.errorBook}
|
||||
// SET review_count = review_count + 1,
|
||||
// last_review_at = ?
|
||||
// WHERE id = ?
|
||||
// ''', [DateTime.now().toIso8601String(), entryId]);
|
||||
}
|
||||
|
||||
/// 获取错题统计(按科目分组计数)
|
||||
Future<Map<String, int>> getErrorStatsBySubject() async {
|
||||
// final maps = await _db.rawQuery('''
|
||||
// SELECT subject, COUNT(*) as count
|
||||
// FROM ${PadDbTables.errorBook}
|
||||
// GROUP BY subject
|
||||
// ''');
|
||||
// return {for (var m in maps) m['subject'] as String: m['count'] as int};
|
||||
return {};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 学习计划 CRUD
|
||||
// ============================================================
|
||||
|
||||
/// 保存学习计划
|
||||
Future<void> saveStudyPlan(StudyPlanEntry plan) async {
|
||||
// await _db.insert(
|
||||
// PadDbTables.studyPlan,
|
||||
// plan.toMap(),
|
||||
// conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取活跃的学习计划列表
|
||||
Future<List<Map<String, dynamic>>> getActiveStudyPlans() async {
|
||||
// return await _db.query(
|
||||
// PadDbTables.studyPlan,
|
||||
// where: 'is_active = 1',
|
||||
// orderBy: 'start_date ASC',
|
||||
// );
|
||||
return [];
|
||||
}
|
||||
|
||||
/// 更新学习计划进度
|
||||
Future<void> updatePlanProgress(
|
||||
String planId,
|
||||
double progress,
|
||||
int completedTasks,
|
||||
) async {
|
||||
// await _db.update(
|
||||
// PadDbTables.studyPlan,
|
||||
// {'progress': progress, 'completed_tasks': completedTasks},
|
||||
// where: 'id = ?',
|
||||
// whereArgs: [planId],
|
||||
// );
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 练字记录
|
||||
// ============================================================
|
||||
|
||||
/// 保存练字记录
|
||||
Future<void> savePracticeRecord(PracticeRecord record) async {
|
||||
// await _db.insert(
|
||||
// PadDbTables.practiceRecord,
|
||||
// record.toMap(),
|
||||
// conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取某字的练习历史(查看进步轨迹)
|
||||
Future<List<Map<String, dynamic>>> getPracticeHistory(
|
||||
String character, {
|
||||
int limit = 20,
|
||||
}) async {
|
||||
// return await _db.query(
|
||||
// PadDbTables.practiceRecord,
|
||||
// where: 'character = ?',
|
||||
// whereArgs: [character],
|
||||
// orderBy: 'practice_at DESC',
|
||||
// limit: limit,
|
||||
// );
|
||||
return [];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 离线操作队列
|
||||
// ============================================================
|
||||
|
||||
/// 添加离线操作到队列
|
||||
Future<void> enqueueOfflineAction(
|
||||
String actionType,
|
||||
Map<String, dynamic> payload,
|
||||
) async {
|
||||
// await _db.insert(PadDbTables.offlineAction, {
|
||||
// 'action_type': actionType,
|
||||
// 'payload': jsonEncode(payload),
|
||||
// 'created_at': DateTime.now().toIso8601String(),
|
||||
// 'status': 'pending',
|
||||
// });
|
||||
}
|
||||
|
||||
/// 获取待执行的离线操作
|
||||
Future<List<Map<String, dynamic>>> getPendingOfflineActions() async {
|
||||
// return await _db.query(
|
||||
// PadDbTables.offlineAction,
|
||||
// where: 'status = ? AND retry_count < 5',
|
||||
// whereArgs: ['pending'],
|
||||
// orderBy: 'created_at ASC',
|
||||
// );
|
||||
return [];
|
||||
}
|
||||
|
||||
/// 标记离线操作完成
|
||||
Future<void> markOfflineActionDone(int actionId) async {
|
||||
// await _db.update(
|
||||
// PadDbTables.offlineAction,
|
||||
// {'status': 'done'},
|
||||
// where: 'id = ?',
|
||||
// whereArgs: [actionId],
|
||||
// );
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 使用时长记录
|
||||
// ============================================================
|
||||
|
||||
/// 记录使用时长
|
||||
Future<void> recordUsage({
|
||||
required String date,
|
||||
required int durationSeconds,
|
||||
required String startTime,
|
||||
String? endTime,
|
||||
String? subject,
|
||||
}) async {
|
||||
// await _db.insert(PadDbTables.usageRecord, {
|
||||
// 'date': date,
|
||||
// 'duration_seconds': durationSeconds,
|
||||
// 'start_time': startTime,
|
||||
// 'end_time': endTime,
|
||||
// 'subject': subject,
|
||||
// });
|
||||
}
|
||||
|
||||
/// 获取某日使用总时长(秒)
|
||||
Future<int> getDailyUsage(String date) async {
|
||||
// final result = await _db.rawQuery('''
|
||||
// SELECT COALESCE(SUM(duration_seconds), 0) as total
|
||||
// FROM ${PadDbTables.usageRecord}
|
||||
// WHERE date = ?
|
||||
// ''', [date]);
|
||||
// return result.first['total'] as int? ?? 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 数据库维护
|
||||
// ============================================================
|
||||
|
||||
/// 清理过期缓存数据(30天前的作业缓存、90天前的笔迹暂存)
|
||||
Future<void> cleanExpiredData() async {
|
||||
final thirtyDaysAgo = DateTime.now()
|
||||
.subtract(const Duration(days: 30))
|
||||
.toIso8601String();
|
||||
final ninetyDaysAgo = DateTime.now()
|
||||
.subtract(const Duration(days: 90))
|
||||
.toIso8601String();
|
||||
|
||||
// await _db.delete(
|
||||
// PadDbTables.homework,
|
||||
// where: 'cached_at < ? AND status IN (?, ?)',
|
||||
// whereArgs: [thirtyDaysAgo, 'graded', 'expired'],
|
||||
// );
|
||||
// await _db.delete(
|
||||
// PadDbTables.strokeCache,
|
||||
// where: 'created_at < ?',
|
||||
// whereArgs: [ninetyDaysAgo],
|
||||
// );
|
||||
// await _db.delete(
|
||||
// PadDbTables.offlineAction,
|
||||
// where: 'status = ? AND created_at < ?',
|
||||
// whereArgs: ['done', thirtyDaysAgo],
|
||||
// );
|
||||
}
|
||||
|
||||
/// 获取本地数据库存储大小(字节)
|
||||
Future<int> getDatabaseSize() async {
|
||||
// final dbPath = await getDatabasesPath();
|
||||
// final file = File('$dbPath/writech_pad.db');
|
||||
// return file.existsSync() ? file.lengthSync() : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 关闭数据库
|
||||
Future<void> close() async {
|
||||
// await _db.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user