feat:设备日志模块

feat:定时任务
feat:设置页面用路由重构
This commit is contained in:
dzc committed 2026-07-30 13:16:14 +08:00
1 parent 1033f403b1
commit 2efa7a3c19
60 files changed
+6560 -643

No files matched your search

+379 -1
View File
@@ -98,13 +98,19 @@ class _$AppDatabase extends AppDatabase {
SettingDao? _getSettingDaoInstance;
ScheduledTaskDao? _getScheduledTaskDaoInstance;
ScheduledTaskLogDao? _getScheduledTaskLogDaoInstance;
FileUploadRecordDao? _getFileUploadRecordDaoInstance;
Future<sqflite.Database> open(
String path,
List<Migration> migrations, [
Callback? callback,
]) async {
final databaseOptions = sqflite.OpenDatabaseOptions(
version: 7,
version: 8,
onConfigure: (database) async {
await database.execute('PRAGMA foreign_keys = ON');
await callback?.onConfigure?.call(database);
@@ -145,6 +151,20 @@ class _$AppDatabase extends AppDatabase {
'CREATE TABLE IF NOT EXISTS `face` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `userId` TEXT NOT NULL, `sampleId` TEXT NOT NULL, `userName` TEXT NOT NULL, `deptId` TEXT, `deptName` TEXT, `imagePath` TEXT NOT NULL, `path` TEXT, `faceModel` TEXT, `createTime` TEXT, `updateTime` TEXT)');
await database.execute(
'CREATE TABLE IF NOT EXISTS `setting` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `userJson` TEXT NOT NULL, `sysJson` TEXT NOT NULL, `canteenExtraPriceConfigJson` TEXT)');
await database.execute(
'CREATE TABLE IF NOT EXISTS `scheduled_task` (`taskCode` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `cronExpression` TEXT NOT NULL, `idleOnly` INTEGER NOT NULL, `lastRunAt` TEXT, `lastSuccessAt` TEXT, `lastStatus` TEXT NOT NULL, `lastMessage` TEXT NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, PRIMARY KEY (`taskCode`))');
await database.execute(
'CREATE TABLE IF NOT EXISTS `scheduled_task_log` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `taskCode` TEXT NOT NULL, `taskName` TEXT NOT NULL, `triggerType` TEXT NOT NULL, `sourceType` TEXT NOT NULL, `sourceName` TEXT NOT NULL, `status` TEXT NOT NULL, `message` TEXT NOT NULL, `errorType` TEXT, `errorMessage` TEXT, `errorStack` TEXT, `startedAt` TEXT NOT NULL, `finishedAt` TEXT, `durationMs` INTEGER NOT NULL, `scannedCount` INTEGER, `skippedCount` INTEGER, `successCount` INTEGER, `failureCount` INTEGER)');
await database.execute(
'CREATE TABLE IF NOT EXISTS `file_upload_record` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hardId` TEXT NOT NULL, `bizType` TEXT NOT NULL, `relativePath` TEXT NOT NULL, `originalName` TEXT NOT NULL, `sourceSize` INTEGER NOT NULL, `sourceModifiedTime` TEXT NOT NULL, `sanitizedHash` TEXT NOT NULL, `sanitizedSize` INTEGER NOT NULL, `status` TEXT NOT NULL, `serverFileId` TEXT, `attemptCount` INTEGER NOT NULL, `lastAttemptAt` TEXT, `uploadedAt` TEXT, `lastError` TEXT, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL)');
await database.execute(
'CREATE INDEX `index_scheduled_task_log_taskCode_startedAt` ON `scheduled_task_log` (`taskCode`, `startedAt`)');
await database.execute(
'CREATE INDEX `index_scheduled_task_log_sourceType_status_startedAt` ON `scheduled_task_log` (`sourceType`, `status`, `startedAt`)');
await database.execute(
'CREATE UNIQUE INDEX `index_file_upload_record_hardId_bizType_relativePath` ON `file_upload_record` (`hardId`, `bizType`, `relativePath`)');
await database.execute(
'CREATE INDEX `index_file_upload_record_bizType_status_updateTime` ON `file_upload_record` (`bizType`, `status`, `updateTime`)');
await callback?.onCreate?.call(database, version);
},
@@ -223,6 +243,24 @@ class _$AppDatabase extends AppDatabase {
SettingDao get getSettingDao {
return _getSettingDaoInstance ??= _$SettingDao(database, changeListener);
}
@override
ScheduledTaskDao get getScheduledTaskDao {
return _getScheduledTaskDaoInstance ??=
_$ScheduledTaskDao(database, changeListener);
}
@override
ScheduledTaskLogDao get getScheduledTaskLogDao {
return _getScheduledTaskLogDaoInstance ??=
_$ScheduledTaskLogDao(database, changeListener);
}
@override
FileUploadRecordDao get getFileUploadRecordDao {
return _getFileUploadRecordDaoInstance ??=
_$FileUploadRecordDao(database, changeListener);
}
}
class _$BroadcastDao extends BroadcastDao {
@@ -1981,6 +2019,346 @@ class _$SettingDao extends SettingDao {
}
}
class _$ScheduledTaskDao extends ScheduledTaskDao {
_$ScheduledTaskDao(
this.database,
this.changeListener,
) : _queryAdapter = QueryAdapter(database),
_scheduledTaskEntityInsertionAdapter = InsertionAdapter(
database,
'scheduled_task',
(ScheduledTaskEntity item) => <String, Object?>{
'taskCode': item.taskCode,
'enabled': _boolConverter.encode(item.enabled),
'cronExpression': item.cronExpression,
'idleOnly': _boolConverter.encode(item.idleOnly),
'lastRunAt': _dateTimeEmptyConverter.encode(item.lastRunAt),
'lastSuccessAt':
_dateTimeEmptyConverter.encode(item.lastSuccessAt),
'lastStatus': item.lastStatus,
'lastMessage': item.lastMessage,
'createTime': _dateTimeConverter.encode(item.createTime),
'updateTime': _dateTimeConverter.encode(item.updateTime)
}),
_scheduledTaskEntityUpdateAdapter = UpdateAdapter(
database,
'scheduled_task',
['taskCode'],
(ScheduledTaskEntity item) => <String, Object?>{
'taskCode': item.taskCode,
'enabled': _boolConverter.encode(item.enabled),
'cronExpression': item.cronExpression,
'idleOnly': _boolConverter.encode(item.idleOnly),
'lastRunAt': _dateTimeEmptyConverter.encode(item.lastRunAt),
'lastSuccessAt':
_dateTimeEmptyConverter.encode(item.lastSuccessAt),
'lastStatus': item.lastStatus,
'lastMessage': item.lastMessage,
'createTime': _dateTimeConverter.encode(item.createTime),
'updateTime': _dateTimeConverter.encode(item.updateTime)
});
final sqflite.DatabaseExecutor database;
final StreamController<String> changeListener;
final QueryAdapter _queryAdapter;
final InsertionAdapter<ScheduledTaskEntity>
_scheduledTaskEntityInsertionAdapter;
final UpdateAdapter<ScheduledTaskEntity> _scheduledTaskEntityUpdateAdapter;
@override
Future<List<ScheduledTaskEntity>> getAll() async {
return _queryAdapter.queryList(
'SELECT * FROM scheduled_task ORDER BY taskCode',
mapper: (Map<String, Object?> row) => ScheduledTaskEntity(
taskCode: row['taskCode'] as String,
enabled: _boolConverter.decode(row['enabled'] as int),
cronExpression: row['cronExpression'] as String,
idleOnly: _boolConverter.decode(row['idleOnly'] as int),
lastRunAt:
_dateTimeEmptyConverter.decode(row['lastRunAt'] as String),
lastSuccessAt:
_dateTimeEmptyConverter.decode(row['lastSuccessAt'] as String),
lastStatus: row['lastStatus'] as String,
lastMessage: row['lastMessage'] as String,
createTime: _dateTimeConverter.decode(row['createTime'] as String),
updateTime:
_dateTimeConverter.decode(row['updateTime'] as String)));
}
@override
Future<ScheduledTaskEntity?> getByCode(String taskCode) async {
return _queryAdapter.query(
'SELECT * FROM scheduled_task WHERE taskCode = ?1 LIMIT 1',
mapper: (Map<String, Object?> row) => ScheduledTaskEntity(
taskCode: row['taskCode'] as String,
enabled: _boolConverter.decode(row['enabled'] as int),
cronExpression: row['cronExpression'] as String,
idleOnly: _boolConverter.decode(row['idleOnly'] as int),
lastRunAt:
_dateTimeEmptyConverter.decode(row['lastRunAt'] as String),
lastSuccessAt:
_dateTimeEmptyConverter.decode(row['lastSuccessAt'] as String),
lastStatus: row['lastStatus'] as String,
lastMessage: row['lastMessage'] as String,
createTime: _dateTimeConverter.decode(row['createTime'] as String),
updateTime: _dateTimeConverter.decode(row['updateTime'] as String)),
arguments: [taskCode]);
}
@override
Future<void> save(ScheduledTaskEntity entity) async {
await _scheduledTaskEntityInsertionAdapter.insert(
entity, OnConflictStrategy.replace);
}
@override
Future<void> batchSave(List<ScheduledTaskEntity> entities) async {
await _scheduledTaskEntityInsertionAdapter.insertList(
entities, OnConflictStrategy.replace);
}
@override
Future<void> edit(ScheduledTaskEntity entity) async {
await _scheduledTaskEntityUpdateAdapter.update(
entity, OnConflictStrategy.abort);
}
}
class _$ScheduledTaskLogDao extends ScheduledTaskLogDao {
_$ScheduledTaskLogDao(
this.database,
this.changeListener,
) : _queryAdapter = QueryAdapter(database),
_scheduledTaskLogEntityInsertionAdapter = InsertionAdapter(
database,
'scheduled_task_log',
(ScheduledTaskLogEntity item) => <String, Object?>{
'id': item.id,
'taskCode': item.taskCode,
'taskName': item.taskName,
'triggerType': item.triggerType,
'sourceType': item.sourceType,
'sourceName': item.sourceName,
'status': item.status,
'message': item.message,
'errorType': item.errorType,
'errorMessage': item.errorMessage,
'errorStack': item.errorStack,
'startedAt': _dateTimeConverter.encode(item.startedAt),
'finishedAt': _dateTimeEmptyConverter.encode(item.finishedAt),
'durationMs': item.durationMs,
'scannedCount': item.scannedCount,
'skippedCount': item.skippedCount,
'successCount': item.successCount,
'failureCount': item.failureCount
}),
_scheduledTaskLogEntityUpdateAdapter = UpdateAdapter(
database,
'scheduled_task_log',
['id'],
(ScheduledTaskLogEntity item) => <String, Object?>{
'id': item.id,
'taskCode': item.taskCode,
'taskName': item.taskName,
'triggerType': item.triggerType,
'sourceType': item.sourceType,
'sourceName': item.sourceName,
'status': item.status,
'message': item.message,
'errorType': item.errorType,
'errorMessage': item.errorMessage,
'errorStack': item.errorStack,
'startedAt': _dateTimeConverter.encode(item.startedAt),
'finishedAt': _dateTimeEmptyConverter.encode(item.finishedAt),
'durationMs': item.durationMs,
'scannedCount': item.scannedCount,
'skippedCount': item.skippedCount,
'successCount': item.successCount,
'failureCount': item.failureCount
});
final sqflite.DatabaseExecutor database;
final StreamController<String> changeListener;
final QueryAdapter _queryAdapter;
final InsertionAdapter<ScheduledTaskLogEntity>
_scheduledTaskLogEntityInsertionAdapter;
final UpdateAdapter<ScheduledTaskLogEntity>
_scheduledTaskLogEntityUpdateAdapter;
@override
Future<List<ScheduledTaskLogEntity>> getByTask(
String taskCode,
String sourceType,
int limit,
) async {
return _queryAdapter.queryList(
'SELECT * FROM scheduled_task_log WHERE taskCode = ?1 AND (?2 = \'\' OR sourceType = ?2) ORDER BY id DESC LIMIT ?3',
mapper: (Map<String, Object?> row) => ScheduledTaskLogEntity(id: row['id'] as int?, taskCode: row['taskCode'] as String, taskName: row['taskName'] as String, triggerType: row['triggerType'] as String, sourceType: row['sourceType'] as String, sourceName: row['sourceName'] as String, status: row['status'] as String, message: row['message'] as String, errorType: row['errorType'] as String?, errorMessage: row['errorMessage'] as String?, errorStack: row['errorStack'] as String?, startedAt: _dateTimeConverter.decode(row['startedAt'] as String), finishedAt: _dateTimeEmptyConverter.decode(row['finishedAt'] as String), durationMs: row['durationMs'] as int, scannedCount: row['scannedCount'] as int?, skippedCount: row['skippedCount'] as int?, successCount: row['successCount'] as int?, failureCount: row['failureCount'] as int?),
arguments: [taskCode, sourceType, limit]);
}
@override
Future<List<ScheduledTaskLogEntity>> getPageByTask(
String taskCode,
String sourceType,
int pageSize,
int offset,
) async {
return _queryAdapter.queryList(
'SELECT * FROM scheduled_task_log WHERE taskCode = ?1 AND (?2 = \'\' OR sourceType = ?2) ORDER BY id DESC LIMIT ?3 OFFSET ?4',
mapper: (Map<String, Object?> row) => ScheduledTaskLogEntity(id: row['id'] as int?, taskCode: row['taskCode'] as String, taskName: row['taskName'] as String, triggerType: row['triggerType'] as String, sourceType: row['sourceType'] as String, sourceName: row['sourceName'] as String, status: row['status'] as String, message: row['message'] as String, errorType: row['errorType'] as String?, errorMessage: row['errorMessage'] as String?, errorStack: row['errorStack'] as String?, startedAt: _dateTimeConverter.decode(row['startedAt'] as String), finishedAt: _dateTimeEmptyConverter.decode(row['finishedAt'] as String), durationMs: row['durationMs'] as int, scannedCount: row['scannedCount'] as int?, skippedCount: row['skippedCount'] as int?, successCount: row['successCount'] as int?, failureCount: row['failureCount'] as int?),
arguments: [taskCode, sourceType, pageSize, offset]);
}
@override
Future<int?> countByTask(
String taskCode,
String sourceType,
) async {
return _queryAdapter.query(
'SELECT COUNT(0) FROM scheduled_task_log WHERE taskCode = ?1 AND (?2 = \'\' OR sourceType = ?2)',
mapper: (Map<String, Object?> row) => row.values.first as int,
arguments: [taskCode, sourceType]);
}
@override
Future<ScheduledTaskLogEntity?> getLatest(String taskCode) async {
return _queryAdapter.query(
'SELECT * FROM scheduled_task_log WHERE taskCode = ?1 ORDER BY id DESC LIMIT 1',
mapper: (Map<String, Object?> row) => ScheduledTaskLogEntity(id: row['id'] as int?, taskCode: row['taskCode'] as String, taskName: row['taskName'] as String, triggerType: row['triggerType'] as String, sourceType: row['sourceType'] as String, sourceName: row['sourceName'] as String, status: row['status'] as String, message: row['message'] as String, errorType: row['errorType'] as String?, errorMessage: row['errorMessage'] as String?, errorStack: row['errorStack'] as String?, startedAt: _dateTimeConverter.decode(row['startedAt'] as String), finishedAt: _dateTimeEmptyConverter.decode(row['finishedAt'] as String), durationMs: row['durationMs'] as int, scannedCount: row['scannedCount'] as int?, skippedCount: row['skippedCount'] as int?, successCount: row['successCount'] as int?, failureCount: row['failureCount'] as int?),
arguments: [taskCode]);
}
@override
Future<void> trimHistory() async {
await _queryAdapter.queryNoReturn(
'DELETE FROM scheduled_task_log WHERE id NOT IN ( SELECT id FROM scheduled_task_log ORDER BY id DESC LIMIT 2000 )');
}
@override
Future<int> save(ScheduledTaskLogEntity entity) {
return _scheduledTaskLogEntityInsertionAdapter.insertAndReturnId(
entity, OnConflictStrategy.abort);
}
@override
Future<void> edit(ScheduledTaskLogEntity entity) async {
await _scheduledTaskLogEntityUpdateAdapter.update(
entity, OnConflictStrategy.abort);
}
}
class _$FileUploadRecordDao extends FileUploadRecordDao {
_$FileUploadRecordDao(
this.database,
this.changeListener,
) : _queryAdapter = QueryAdapter(database),
_fileUploadRecordEntityInsertionAdapter = InsertionAdapter(
database,
'file_upload_record',
(FileUploadRecordEntity item) => <String, Object?>{
'id': item.id,
'hardId': item.hardId,
'bizType': item.bizType,
'relativePath': item.relativePath,
'originalName': item.originalName,
'sourceSize': item.sourceSize,
'sourceModifiedTime':
_dateTimeConverter.encode(item.sourceModifiedTime),
'sanitizedHash': item.sanitizedHash,
'sanitizedSize': item.sanitizedSize,
'status': item.status,
'serverFileId': item.serverFileId,
'attemptCount': item.attemptCount,
'lastAttemptAt':
_dateTimeEmptyConverter.encode(item.lastAttemptAt),
'uploadedAt': _dateTimeEmptyConverter.encode(item.uploadedAt),
'lastError': item.lastError,
'createTime': _dateTimeConverter.encode(item.createTime),
'updateTime': _dateTimeConverter.encode(item.updateTime)
}),
_fileUploadRecordEntityUpdateAdapter = UpdateAdapter(
database,
'file_upload_record',
['id'],
(FileUploadRecordEntity item) => <String, Object?>{
'id': item.id,
'hardId': item.hardId,
'bizType': item.bizType,
'relativePath': item.relativePath,
'originalName': item.originalName,
'sourceSize': item.sourceSize,
'sourceModifiedTime':
_dateTimeConverter.encode(item.sourceModifiedTime),
'sanitizedHash': item.sanitizedHash,
'sanitizedSize': item.sanitizedSize,
'status': item.status,
'serverFileId': item.serverFileId,
'attemptCount': item.attemptCount,
'lastAttemptAt':
_dateTimeEmptyConverter.encode(item.lastAttemptAt),
'uploadedAt': _dateTimeEmptyConverter.encode(item.uploadedAt),
'lastError': item.lastError,
'createTime': _dateTimeConverter.encode(item.createTime),
'updateTime': _dateTimeConverter.encode(item.updateTime)
});
final sqflite.DatabaseExecutor database;
final StreamController<String> changeListener;
final QueryAdapter _queryAdapter;
final InsertionAdapter<FileUploadRecordEntity>
_fileUploadRecordEntityInsertionAdapter;
final UpdateAdapter<FileUploadRecordEntity>
_fileUploadRecordEntityUpdateAdapter;
@override
Future<List<FileUploadRecordEntity>> getAll(
String hardId,
String bizType,
) async {
return _queryAdapter.queryList(
'SELECT * FROM file_upload_record WHERE hardId = ?1 AND bizType = ?2 ORDER BY updateTime DESC',
mapper: (Map<String, Object?> row) => FileUploadRecordEntity(id: row['id'] as int?, hardId: row['hardId'] as String, bizType: row['bizType'] as String, relativePath: row['relativePath'] as String, originalName: row['originalName'] as String, sourceSize: row['sourceSize'] as int, sourceModifiedTime: _dateTimeConverter.decode(row['sourceModifiedTime'] as String), sanitizedHash: row['sanitizedHash'] as String, sanitizedSize: row['sanitizedSize'] as int, status: row['status'] as String, serverFileId: row['serverFileId'] as String?, attemptCount: row['attemptCount'] as int, lastAttemptAt: _dateTimeEmptyConverter.decode(row['lastAttemptAt'] as String), uploadedAt: _dateTimeEmptyConverter.decode(row['uploadedAt'] as String), lastError: row['lastError'] as String?, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String)),
arguments: [hardId, bizType]);
}
@override
Future<FileUploadRecordEntity?> getByPath(
String hardId,
String bizType,
String relativePath,
) async {
return _queryAdapter.query(
'SELECT * FROM file_upload_record WHERE hardId = ?1 AND bizType = ?2 AND relativePath = ?3 LIMIT 1',
mapper: (Map<String, Object?> row) => FileUploadRecordEntity(id: row['id'] as int?, hardId: row['hardId'] as String, bizType: row['bizType'] as String, relativePath: row['relativePath'] as String, originalName: row['originalName'] as String, sourceSize: row['sourceSize'] as int, sourceModifiedTime: _dateTimeConverter.decode(row['sourceModifiedTime'] as String), sanitizedHash: row['sanitizedHash'] as String, sanitizedSize: row['sanitizedSize'] as int, status: row['status'] as String, serverFileId: row['serverFileId'] as String?, attemptCount: row['attemptCount'] as int, lastAttemptAt: _dateTimeEmptyConverter.decode(row['lastAttemptAt'] as String), uploadedAt: _dateTimeEmptyConverter.decode(row['uploadedAt'] as String), lastError: row['lastError'] as String?, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String)),
arguments: [hardId, bizType, relativePath]);
}
@override
Future<int> save(FileUploadRecordEntity entity) {
return _fileUploadRecordEntityInsertionAdapter.insertAndReturnId(
entity, OnConflictStrategy.replace);
}
@override
Future<void> edit(FileUploadRecordEntity entity) async {
await _fileUploadRecordEntityUpdateAdapter.update(
entity, OnConflictStrategy.abort);
}
}
// ignore_for_file: unused_element
final _dateTimeConverter = DateTimeConverter();
final _dateTimeEmptyConverter = DateTimeEmptyConverter();