You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
7.7 KiB

// sqlite_provider.dart
import 'package:get/get.dart';
import 'package:problem_check_system/data/models/sync_status.dart';
import 'package:problem_check_system/data/models/problem_model.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
/// `SQLiteProvider` 是一个 GetxService,负责管理本地 SQLite 数据库。
/// 作为一个单例服务,它在整个应用生命周期中只会被创建一次。
class SQLiteProvider extends GetxService {
static const String _dbName = 'problems.db';
static const String _tableName = 'problems';
static const int _dbVersion = 1;
late Database _database;
@override
void onInit() {
super.onInit();
_initDatabase();
}
/// 异步初始化数据库连接
Future<void> _initDatabase() async {
try {
final databasePath = await getDatabasesPath();
final path = join(databasePath, _dbName);
_database = await openDatabase(
path,
version: _dbVersion,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
Get.log('数据库初始化成功');
} catch (e) {
Get.log('数据库初始化失败:$e', isError: true);
rethrow;
}
}
/// 数据库创建时的回调函数
Future<void> _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $_tableName(
id TEXT PRIMARY KEY,
description TEXT NOT NULL,
location TEXT NOT NULL,
imageUrls TEXT NOT NULL,
creationTime INTEGER NOT NULL,
syncStatus INTEGER NOT NULL,
operation INTEGER NOT NULL,
isDeleted INTEGER NOT NULL,
censorTaskId TEXT,
bindData TEXT,
isChecked INTEGER NOT NULL
)
''');
Get.log('数据库表创建成功');
}
/// 数据库版本升级处理
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
Get.log('正在将数据库从版本 $oldVersion 升级到 $newVersion...');
// 版本升级迁移逻辑
for (int version = oldVersion + 1; version <= newVersion; version++) {
await _runMigration(db, version);
}
Get.log('数据库升级完成');
}
/// 执行特定版本的数据库迁移
Future<void> _runMigration(Database db, int version) async {
switch (version) {
case 2:
// 版本2迁移逻辑
// await db.execute('ALTER TABLE $_tableName ADD COLUMN newColumn TEXT;');
break;
// 添加更多版本迁移逻辑
default:
Get.log('没有找到版本 $version 的迁移脚本');
}
}
/// 插入问题记录,并设置同步状态为未同步
Future<int> insertProblem(Problem problem) async {
try {
// 确保插入的问题同步状态为未同步
final problemToInsert = problem.copyWith(
syncStatus: SyncStatus.notSynced,
);
final result = await _database.insert(
_tableName,
problemToInsert.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
Get.log('问题记录插入成功,ID: ${problem.id}');
return result;
} catch (e) {
Get.log('插入问题失败(ID: ${problem.id}):$e', isError: true);
return 0;
}
}
/// 逻辑删除问题记录,并设置同步状态为未同步
Future<int> deleteProblem(String id) async {
try {
final result = await _database.update(
_tableName,
{
'isDeleted': 1,
'syncStatus': SyncStatus.notSynced.index, // 设置为未同步
},
where: 'id = ?',
whereArgs: [id],
);
if (result > 0) {
Get.log('问题逻辑删除成功,ID: $id');
}
return result;
} catch (e) {
Get.log('逻辑删除问题失败(ID: $id):$e', isError: true);
return 0;
}
}
/// 更新问题记录,并设置同步状态为未同步
Future<int> updateProblem(Problem problem) async {
try {
final result = await _database.update(
_tableName,
problem.toMap(),
where: 'id = ?',
whereArgs: [problem.id],
);
if (result > 0) {
Get.log('问题更新成功,ID: ${problem.id}');
}
return result;
} catch (e) {
Get.log('更新问题失败(ID: ${problem.id}):$e', isError: true);
return 0;
}
}
/// 获取需要同步的问题记录(所有同步状态为未同步的记录)
Future<List<Problem>> getProblemsForSync() async {
try {
final results = await _database.query(
_tableName,
where: 'syncStatus = ?',
whereArgs: [SyncStatus.notSynced.index],
orderBy: 'creationTime ASC',
);
Get.log('找到 ${results.length} 条需要同步的记录');
return results.map((json) => Problem.fromMap(json)).toList();
} catch (e) {
Get.log('获取待同步问题失败:$e', isError: true);
return [];
}
}
/// 标记问题为已同步(在同步成功后调用)
Future<int> markAsSynced(String id) async {
try {
final result = await _database.update(
_tableName,
{'syncStatus': SyncStatus.synced.index},
where: 'id = ? AND syncStatus = ?',
whereArgs: [id, SyncStatus.notSynced.index],
);
if (result > 0) {
Get.log('问题标记为已同步,ID: $id');
}
return result;
} catch (e) {
Get.log('标记同步状态失败(ID: $id):$e', isError: true);
return 0;
}
}
/// 根据ID获取问题记录
Future<Problem?> getProblemById(String id) async {
try {
final results = await _database.query(
_tableName,
where: 'id = ? AND isDeleted = 0',
whereArgs: [id],
limit: 1,
);
return results.isNotEmpty ? Problem.fromMap(results.first) : null;
} catch (e) {
Get.log('获取问题失败(ID: $id):$e', isError: true);
return null;
}
}
/// 获取问题列表(支持多种筛选条件)
Future<List<Problem>> getProblems({
DateTime? startDate,
DateTime? endDate,
String? syncStatus,
String? bindStatus,
bool includeDeleted = false,
}) async {
try {
final whereClauses = <String>[];
final whereArgs = <dynamic>[];
// 删除状态筛选
if (!includeDeleted) {
whereClauses.add('isDeleted = 0');
}
// 时间范围筛选
if (startDate != null) {
whereClauses.add('creationTime >= ?');
whereArgs.add(startDate.millisecondsSinceEpoch);
}
if (endDate != null) {
whereClauses.add('creationTime <= ?');
whereArgs.add(endDate.millisecondsSinceEpoch);
}
// 同步状态筛选
if (syncStatus != null && syncStatus != '全部') {
final statusValue = syncStatus == '已上传'
? SyncStatus.synced.index
: SyncStatus.notSynced.index;
whereClauses.add('syncStatus = ?');
whereArgs.add(statusValue);
}
// 绑定状态筛选
if (bindStatus != null && bindStatus != '全部') {
if (bindStatus == '已绑定') {
whereClauses.add('bindData IS NOT NULL AND bindData != ""');
} else {
whereClauses.add('(bindData IS NULL OR bindData = "")');
}
}
final results = await _database.query(
_tableName,
where: whereClauses.isNotEmpty ? whereClauses.join(' AND ') : null,
whereArgs: whereArgs.isEmpty ? null : whereArgs,
orderBy: 'creationTime DESC',
);
return results.map((json) => Problem.fromMap(json)).toList();
} catch (e) {
Get.log('获取问题列表失败:$e', isError: true);
return [];
}
}
@override
void onClose() {
_database.close();
Get.log('数据库连接已关闭');
super.onClose();
}
}