|
|
@ -1,6 +1,7 @@ |
|
|
|
// sqlite_provider.dart |
|
|
|
// sqlite_provider.dart |
|
|
|
|
|
|
|
|
|
|
|
import 'package:get/get.dart'; |
|
|
|
import 'package:get/get.dart'; |
|
|
|
import 'package:problem_check_system/data/models/enum_model.dart'; |
|
|
|
import 'package:problem_check_system/data/models/sync_status.dart'; |
|
|
|
import 'package:problem_check_system/data/models/problem_model.dart'; |
|
|
|
import 'package:problem_check_system/data/models/problem_model.dart'; |
|
|
|
import 'package:sqflite/sqflite.dart'; |
|
|
|
import 'package:sqflite/sqflite.dart'; |
|
|
|
import 'package:path/path.dart'; |
|
|
|
import 'package:path/path.dart'; |
|
|
@ -24,13 +25,19 @@ class SQLiteProvider extends GetxService { |
|
|
|
|
|
|
|
|
|
|
|
/// 异步初始化数据库连接。如果数据库不存在,则会创建它。 |
|
|
|
/// 异步初始化数据库连接。如果数据库不存在,则会创建它。 |
|
|
|
Future<void> _initDatabase() async { |
|
|
|
Future<void> _initDatabase() async { |
|
|
|
final databasePath = await getDatabasesPath(); |
|
|
|
try { |
|
|
|
final path = join(databasePath, _dbName); |
|
|
|
final databasePath = await getDatabasesPath(); |
|
|
|
|
|
|
|
final path = join(databasePath, _dbName); |
|
|
|
_database = await openDatabase(path, version: 1, onCreate: _onCreate); |
|
|
|
|
|
|
|
|
|
|
|
_database = await openDatabase(path, version: 1, onCreate: _onCreate); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 在这里添加日志记录,例如 Get.log('数据库初始化失败:$e'); |
|
|
|
|
|
|
|
rethrow; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 数据库创建时的回调函数,用于定义表结构。 |
|
|
|
/// 数据库创建时的回调函数,用于定义表结构。 |
|
|
|
|
|
|
|
/// **注意**:这里新增了 `operation` 和 `isChecked` 两个字段。 |
|
|
|
Future<void> _onCreate(Database db, int version) async { |
|
|
|
Future<void> _onCreate(Database db, int version) async { |
|
|
|
await db.execute(''' |
|
|
|
await db.execute(''' |
|
|
|
CREATE TABLE $_tableName( |
|
|
|
CREATE TABLE $_tableName( |
|
|
@ -40,102 +47,146 @@ class SQLiteProvider extends GetxService { |
|
|
|
imageUrls TEXT NOT NULL, |
|
|
|
imageUrls TEXT NOT NULL, |
|
|
|
creationTime INTEGER NOT NULL, |
|
|
|
creationTime INTEGER NOT NULL, |
|
|
|
syncStatus INTEGER NOT NULL, |
|
|
|
syncStatus INTEGER NOT NULL, |
|
|
|
|
|
|
|
operation INTEGER NOT NULL, -- 新增:问题操作类型 |
|
|
|
censorTaskId TEXT, |
|
|
|
censorTaskId TEXT, |
|
|
|
bindData TEXT |
|
|
|
bindData TEXT, |
|
|
|
|
|
|
|
isChecked INTEGER NOT NULL -- 新增:问题是否已检查(SQLite 用 INTEGER 表示布尔值) |
|
|
|
) |
|
|
|
) |
|
|
|
'''); |
|
|
|
'''); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// --- |
|
|
|
// --- |
|
|
|
|
|
|
|
|
|
|
|
/// **数据操作 (CRUD) 方法** |
|
|
|
/// **数据操作 (CRUD) 方法** |
|
|
|
|
|
|
|
|
|
|
|
/// 向数据库中插入一个新问题。 |
|
|
|
/// 向数据库中插入一个新问题。 |
|
|
|
/// 如果 `problem` 没有 `id`,会自动生成一个唯一的 UUID。 |
|
|
|
/// 如果 `problem` 没有 `id`,会自动生成一个唯一的 UUID。 |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// 返回:`Future<int>`,表示插入的行ID。如果失败,会返回 0。 |
|
|
|
Future<int> insertProblem(Problem problem) async { |
|
|
|
Future<int> insertProblem(Problem problem) async { |
|
|
|
final problemToInsert = problem.copyWith( |
|
|
|
try { |
|
|
|
id: problem.id ?? const Uuid().v4(), |
|
|
|
final problemToInsert = problem.copyWith( |
|
|
|
); |
|
|
|
id: problem.id ?? const Uuid().v4(), |
|
|
|
return await _database.insert( |
|
|
|
); |
|
|
|
_tableName, |
|
|
|
return await _database.insert( |
|
|
|
problemToInsert.toMap(), |
|
|
|
_tableName, |
|
|
|
conflictAlgorithm: ConflictAlgorithm.replace, |
|
|
|
problemToInsert.toMap(), |
|
|
|
); |
|
|
|
conflictAlgorithm: ConflictAlgorithm.replace, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 可以添加日志记录 |
|
|
|
|
|
|
|
return 0; // 返回 0 表示插入失败 |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 根据 ID 从数据库中删除一个问题。 |
|
|
|
/// 根据 ID 从数据库中删除一个问题。 |
|
|
|
/// 返回被删除的行数。 |
|
|
|
/// |
|
|
|
|
|
|
|
/// 参数:`id` - 要删除的问题ID。 |
|
|
|
|
|
|
|
/// 返回:`Future<int>`,表示被删除的行数。 |
|
|
|
Future<int> deleteProblem(String id) async { |
|
|
|
Future<int> deleteProblem(String id) async { |
|
|
|
return await _database.delete(_tableName, where: 'id = ?', whereArgs: [id]); |
|
|
|
try { |
|
|
|
|
|
|
|
return await _database.delete( |
|
|
|
|
|
|
|
_tableName, |
|
|
|
|
|
|
|
where: 'id = ?', |
|
|
|
|
|
|
|
whereArgs: [id], |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 可以添加日志记录 |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 更新数据库中已存在的问题。 |
|
|
|
/// 更新数据库中已存在的问题。 |
|
|
|
/// 返回被更新的行数。 |
|
|
|
/// |
|
|
|
|
|
|
|
/// 参数:`problem` - 包含更新数据的 `Problem` 对象。 |
|
|
|
|
|
|
|
/// 返回:`Future<int>`,表示被更新的行数。 |
|
|
|
Future<int> updateProblem(Problem problem) async { |
|
|
|
Future<int> updateProblem(Problem problem) async { |
|
|
|
return await _database.update( |
|
|
|
try { |
|
|
|
_tableName, |
|
|
|
return await _database.update( |
|
|
|
problem.toMap(), |
|
|
|
_tableName, |
|
|
|
where: 'id = ?', |
|
|
|
problem.toMap(), |
|
|
|
whereArgs: [problem.id], |
|
|
|
where: 'id = ?', |
|
|
|
); |
|
|
|
whereArgs: [problem.id], |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 可以添加日志记录 |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 根据 ID 获取单个问题。 |
|
|
|
/// 根据 ID 获取单个问题。 |
|
|
|
/// 如果找到则返回 `Problem` 对象,否则返回 `null`。 |
|
|
|
/// |
|
|
|
|
|
|
|
/// 参数:`id` - 要获取的问题ID。 |
|
|
|
|
|
|
|
/// 返回:`Future<Problem?>`,如果找到则返回 `Problem` 对象,否则返回 `null`。 |
|
|
|
Future<Problem?> getProblemById(String id) async { |
|
|
|
Future<Problem?> getProblemById(String id) async { |
|
|
|
final List<Map<String, dynamic>> maps = await _database.query( |
|
|
|
try { |
|
|
|
_tableName, |
|
|
|
final List<Map<String, dynamic>> maps = await _database.query( |
|
|
|
where: 'id = ?', |
|
|
|
_tableName, |
|
|
|
whereArgs: [id], |
|
|
|
where: 'id = ?', |
|
|
|
limit: 1, |
|
|
|
whereArgs: [id], |
|
|
|
); |
|
|
|
limit: 1, |
|
|
|
|
|
|
|
); |
|
|
|
if (maps.isNotEmpty) { |
|
|
|
if (maps.isNotEmpty) { |
|
|
|
return Problem.fromMap(maps.first); |
|
|
|
return Problem.fromMap(maps.first); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 可以添加日志记录 |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 获取所有问题,支持按筛选条件查询。 |
|
|
|
/// 获取所有问题,支持按筛选条件查询。 |
|
|
|
/// 可选参数用于筛选创建时间范围和同步状态。 |
|
|
|
/// |
|
|
|
|
|
|
|
/// 可选参数: |
|
|
|
|
|
|
|
/// - `startDate`: 创建时间范围的开始时间。 |
|
|
|
|
|
|
|
/// - `endDate`: 创建时间范围的结束时间。 |
|
|
|
|
|
|
|
/// - `syncStatus`: 同步状态。 |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// 返回:`Future<List<Problem>>`,返回符合条件的问题列表。如果查询失败,返回空列表。 |
|
|
|
Future<List<Problem>> getProblems({ |
|
|
|
Future<List<Problem>> getProblems({ |
|
|
|
DateTime? startDate, |
|
|
|
DateTime? startDate, |
|
|
|
DateTime? endDate, |
|
|
|
DateTime? endDate, |
|
|
|
SyncStatus? syncStatus, |
|
|
|
SyncStatus? syncStatus, |
|
|
|
}) async { |
|
|
|
}) async { |
|
|
|
final List<String> whereClauses = []; |
|
|
|
try { |
|
|
|
final List<dynamic> whereArgs = []; |
|
|
|
final List<String> whereClauses = []; |
|
|
|
|
|
|
|
final List<dynamic> whereArgs = []; |
|
|
|
if (startDate != null) { |
|
|
|
|
|
|
|
whereClauses.add('creationTime >= ?'); |
|
|
|
if (startDate != null) { |
|
|
|
whereArgs.add(startDate.millisecondsSinceEpoch); |
|
|
|
whereClauses.add('creationTime >= ?'); |
|
|
|
|
|
|
|
whereArgs.add(startDate.millisecondsSinceEpoch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
|
|
whereClauses.add('creationTime <= ?'); |
|
|
|
|
|
|
|
whereArgs.add(endDate.millisecondsSinceEpoch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (syncStatus != null) { |
|
|
|
|
|
|
|
whereClauses.add('syncStatus = ?'); |
|
|
|
|
|
|
|
whereArgs.add(syncStatus.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final String? whereString = whereClauses.isNotEmpty |
|
|
|
|
|
|
|
? whereClauses.join(' AND ') |
|
|
|
|
|
|
|
: null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final List<Map<String, dynamic>> maps = await _database.query( |
|
|
|
|
|
|
|
_tableName, |
|
|
|
|
|
|
|
where: whereString, |
|
|
|
|
|
|
|
whereArgs: whereArgs.isEmpty ? null : whereArgs, |
|
|
|
|
|
|
|
orderBy: 'creationTime DESC', |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return maps.map((json) => Problem.fromMap(json)).toList(); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
// 可以添加日志记录 |
|
|
|
|
|
|
|
return []; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
|
|
whereClauses.add('creationTime <= ?'); |
|
|
|
|
|
|
|
whereArgs.add(endDate.millisecondsSinceEpoch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (syncStatus != null) { |
|
|
|
|
|
|
|
whereClauses.add('syncStatus = ?'); |
|
|
|
|
|
|
|
whereArgs.add(syncStatus.index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final String? whereString = whereClauses.isNotEmpty |
|
|
|
|
|
|
|
? whereClauses.join(' AND ') |
|
|
|
|
|
|
|
: null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final List<Map<String, dynamic>> maps = await _database.query( |
|
|
|
|
|
|
|
_tableName, |
|
|
|
|
|
|
|
where: whereString, |
|
|
|
|
|
|
|
whereArgs: whereArgs.isEmpty ? null : whereArgs, |
|
|
|
|
|
|
|
orderBy: 'creationTime DESC', |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return maps.map((json) => Problem.fromMap(json)).toList(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// --- |
|
|
|
// --- |
|
|
|
|
|
|
|
|
|
|
|
/// `GetxService` 生命周期方法,在服务被销毁前调用, |
|
|
|
/// `GetxService` 生命周期方法,在服务被销毁前调用, |
|
|
|
/// 用于关闭数据库连接,防止资源泄漏。 |
|
|
|
/// 用于关闭数据库连接,防止资源泄漏。 |
|
|
|