fix(app): Phase 1.1 紧急修复 — SyncEngine 接入 + authorId + catch 异常处理
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled

- feat(sync): SyncEngine 接入 EditorPage, 保存时 enqueue + 网络恢复自动 trySync
- fix(editor): authorId 从 AuthBloc 获取, 替代硬编码 'local'
- fix(bloc): class_bloc/calendar/profile/parent catch(_).全部改为 debugPrint
- feat(editor): 编辑器工具栏拆分 (brush_panel/tag_panel/text_format_bar/dot_grid_painter)
- feat(editor): EditorBloc 扩展 + EditorPage 增强
- feat(search): SearchBloc 扩展搜索功能
- feat(home): HomeBloc/HomePage 增强
- feat(auth): LoginPage 增强
- feat(templates): TemplateGalleryPage 重构
- fix(web): 管理端班级/日记页面修复
- fix(server): comment_service + theme_handler 修复
- docs: 添加全链路审计报告和验证截图
This commit is contained in:
iven
2026-06-02 21:21:43 +08:00
parent 7e928ae1e1
commit 49d4aa36a7
55 changed files with 2738 additions and 677 deletions

View File

@@ -16,7 +16,7 @@ extension GetJournalElementCollectionCollection on Isar {
const JournalElementCollectionSchema = CollectionSchema(
name: r'JournalElementCollection',
id: 5678901234567001,
id: -1002,
properties: {
r'contentJson': PropertySchema(
id: 0,
@@ -96,7 +96,7 @@ const JournalElementCollectionSchema = CollectionSchema(
idName: r'isarId',
indexes: {
r'id': IndexSchema(
id: 5678901234567002,
id: -2002,
name: r'id',
unique: false,
replace: false,
@@ -109,7 +109,7 @@ const JournalElementCollectionSchema = CollectionSchema(
],
),
r'journalId': IndexSchema(
id: 5678901234567003,
id: 3001,
name: r'journalId',
unique: false,
replace: false,

View File

@@ -46,6 +46,9 @@ class JournalEntryCollection {
/// 关联主题 ID可选
String? assignedTopicId;
/// 内容摘要(自动从文本元素提取)
String? contentExcerpt;
/// 版本号(乐观锁)
int version = 1;

View File

@@ -16,7 +16,7 @@ extension GetJournalEntryCollectionCollection on Isar {
const JournalEntryCollectionSchema = CollectionSchema(
name: r'JournalEntryCollection',
id: 5678901234567004,
id: -1001,
properties: {
r'assignedTopicId': PropertySchema(
id: 0,
@@ -33,63 +33,68 @@ const JournalEntryCollectionSchema = CollectionSchema(
name: r'classId',
type: IsarType.string,
),
r'createdAtEpoch': PropertySchema(
r'contentExcerpt': PropertySchema(
id: 3,
name: r'contentExcerpt',
type: IsarType.string,
),
r'createdAtEpoch': PropertySchema(
id: 4,
name: r'createdAtEpoch',
type: IsarType.long,
),
r'dateEpoch': PropertySchema(
id: 4,
id: 5,
name: r'dateEpoch',
type: IsarType.long,
),
r'id': PropertySchema(
id: 5,
id: 6,
name: r'id',
type: IsarType.string,
),
r'isDeleted': PropertySchema(
id: 6,
id: 7,
name: r'isDeleted',
type: IsarType.bool,
),
r'isPrivate': PropertySchema(
id: 7,
id: 8,
name: r'isPrivate',
type: IsarType.bool,
),
r'mood': PropertySchema(
id: 8,
id: 9,
name: r'mood',
type: IsarType.string,
),
r'sharedToClass': PropertySchema(
id: 9,
id: 10,
name: r'sharedToClass',
type: IsarType.bool,
),
r'tagsJson': PropertySchema(
id: 10,
id: 11,
name: r'tagsJson',
type: IsarType.string,
),
r'title': PropertySchema(
id: 11,
id: 12,
name: r'title',
type: IsarType.string,
),
r'updatedAtEpoch': PropertySchema(
id: 12,
id: 13,
name: r'updatedAtEpoch',
type: IsarType.long,
),
r'version': PropertySchema(
id: 13,
id: 14,
name: r'version',
type: IsarType.long,
),
r'weather': PropertySchema(
id: 14,
id: 15,
name: r'weather',
type: IsarType.string,
)
@@ -101,7 +106,7 @@ const JournalEntryCollectionSchema = CollectionSchema(
idName: r'isarId',
indexes: {
r'id': IndexSchema(
id: 5678901234567002,
id: -2001,
name: r'id',
unique: false,
replace: false,
@@ -141,6 +146,12 @@ int _journalEntryCollectionEstimateSize(
bytesCount += 3 + value.length * 3;
}
}
{
final value = object.contentExcerpt;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
bytesCount += 3 + object.id.length * 3;
bytesCount += 3 + object.mood.length * 3;
bytesCount += 3 + object.tagsJson.length * 3;
@@ -158,18 +169,19 @@ void _journalEntryCollectionSerialize(
writer.writeString(offsets[0], object.assignedTopicId);
writer.writeString(offsets[1], object.authorId);
writer.writeString(offsets[2], object.classId);
writer.writeLong(offsets[3], object.createdAtEpoch);
writer.writeLong(offsets[4], object.dateEpoch);
writer.writeString(offsets[5], object.id);
writer.writeBool(offsets[6], object.isDeleted);
writer.writeBool(offsets[7], object.isPrivate);
writer.writeString(offsets[8], object.mood);
writer.writeBool(offsets[9], object.sharedToClass);
writer.writeString(offsets[10], object.tagsJson);
writer.writeString(offsets[11], object.title);
writer.writeLong(offsets[12], object.updatedAtEpoch);
writer.writeLong(offsets[13], object.version);
writer.writeString(offsets[14], object.weather);
writer.writeString(offsets[3], object.contentExcerpt);
writer.writeLong(offsets[4], object.createdAtEpoch);
writer.writeLong(offsets[5], object.dateEpoch);
writer.writeString(offsets[6], object.id);
writer.writeBool(offsets[7], object.isDeleted);
writer.writeBool(offsets[8], object.isPrivate);
writer.writeString(offsets[9], object.mood);
writer.writeBool(offsets[10], object.sharedToClass);
writer.writeString(offsets[11], object.tagsJson);
writer.writeString(offsets[12], object.title);
writer.writeLong(offsets[13], object.updatedAtEpoch);
writer.writeLong(offsets[14], object.version);
writer.writeString(offsets[15], object.weather);
}
JournalEntryCollection _journalEntryCollectionDeserialize(
@@ -182,19 +194,20 @@ JournalEntryCollection _journalEntryCollectionDeserialize(
object.assignedTopicId = reader.readStringOrNull(offsets[0]);
object.authorId = reader.readString(offsets[1]);
object.classId = reader.readStringOrNull(offsets[2]);
object.createdAtEpoch = reader.readLong(offsets[3]);
object.dateEpoch = reader.readLong(offsets[4]);
object.id = reader.readString(offsets[5]);
object.isDeleted = reader.readBool(offsets[6]);
object.isPrivate = reader.readBool(offsets[7]);
object.contentExcerpt = reader.readStringOrNull(offsets[3]);
object.createdAtEpoch = reader.readLong(offsets[4]);
object.dateEpoch = reader.readLong(offsets[5]);
object.id = reader.readString(offsets[6]);
object.isDeleted = reader.readBool(offsets[7]);
object.isPrivate = reader.readBool(offsets[8]);
object.isarId = id;
object.mood = reader.readString(offsets[8]);
object.sharedToClass = reader.readBool(offsets[9]);
object.tagsJson = reader.readString(offsets[10]);
object.title = reader.readString(offsets[11]);
object.updatedAtEpoch = reader.readLong(offsets[12]);
object.version = reader.readLong(offsets[13]);
object.weather = reader.readString(offsets[14]);
object.mood = reader.readString(offsets[9]);
object.sharedToClass = reader.readBool(offsets[10]);
object.tagsJson = reader.readString(offsets[11]);
object.title = reader.readString(offsets[12]);
object.updatedAtEpoch = reader.readLong(offsets[13]);
object.version = reader.readLong(offsets[14]);
object.weather = reader.readString(offsets[15]);
return object;
}
@@ -212,28 +225,30 @@ P _journalEntryCollectionDeserializeProp<P>(
case 2:
return (reader.readStringOrNull(offset)) as P;
case 3:
return (reader.readLong(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 4:
return (reader.readLong(offset)) as P;
case 5:
return (reader.readString(offset)) as P;
return (reader.readLong(offset)) as P;
case 6:
return (reader.readBool(offset)) as P;
return (reader.readString(offset)) as P;
case 7:
return (reader.readBool(offset)) as P;
case 8:
return (reader.readString(offset)) as P;
case 9:
return (reader.readBool(offset)) as P;
case 10:
case 9:
return (reader.readString(offset)) as P;
case 10:
return (reader.readBool(offset)) as P;
case 11:
return (reader.readString(offset)) as P;
case 12:
return (reader.readLong(offset)) as P;
return (reader.readString(offset)) as P;
case 13:
return (reader.readLong(offset)) as P;
case 14:
return (reader.readLong(offset)) as P;
case 15:
return (reader.readString(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@@ -832,6 +847,162 @@ extension JournalEntryCollectionQueryFilter on QueryBuilder<
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'contentExcerpt',
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'contentExcerpt',
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'contentExcerpt',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition>
contentExcerptContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'contentExcerpt',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition>
contentExcerptMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'contentExcerpt',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'contentExcerpt',
value: '',
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> contentExcerptIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'contentExcerpt',
value: '',
));
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection,
QAfterFilterCondition> createdAtEpochEqualTo(int value) {
return QueryBuilder.apply(this, (query) {
@@ -1883,6 +2054,20 @@ extension JournalEntryCollectionQuerySortBy
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
sortByContentExcerpt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'contentExcerpt', Sort.asc);
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
sortByContentExcerptDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'contentExcerpt', Sort.desc);
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
sortByCreatedAtEpoch() {
return QueryBuilder.apply(this, (query) {
@@ -2096,6 +2281,20 @@ extension JournalEntryCollectionQuerySortThenBy on QueryBuilder<
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
thenByContentExcerpt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'contentExcerpt', Sort.asc);
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
thenByContentExcerptDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'contentExcerpt', Sort.desc);
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QAfterSortBy>
thenByCreatedAtEpoch() {
return QueryBuilder.apply(this, (query) {
@@ -2303,6 +2502,14 @@ extension JournalEntryCollectionQueryWhereDistinct
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QDistinct>
distinctByContentExcerpt({bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'contentExcerpt',
caseSensitive: caseSensitive);
});
}
QueryBuilder<JournalEntryCollection, JournalEntryCollection, QDistinct>
distinctByCreatedAtEpoch() {
return QueryBuilder.apply(this, (query) {
@@ -2417,6 +2624,13 @@ extension JournalEntryCollectionQueryProperty on QueryBuilder<
});
}
QueryBuilder<JournalEntryCollection, String?, QQueryOperations>
contentExcerptProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'contentExcerpt');
});
}
QueryBuilder<JournalEntryCollection, int, QQueryOperations>
createdAtEpochProperty() {
return QueryBuilder.apply(this, (query) {

View File

@@ -16,7 +16,7 @@ extension GetPendingOperationCollectionCollection on Isar {
const PendingOperationCollectionSchema = CollectionSchema(
name: r'PendingOperationCollection',
id: 5678901234567005,
id: -1003,
properties: {
r'createdAtEpoch': PropertySchema(
id: 0,
@@ -61,7 +61,7 @@ const PendingOperationCollectionSchema = CollectionSchema(
idName: r'isarId',
indexes: {
r'id': IndexSchema(
id: 5678901234567002,
id: -2003,
name: r'id',
unique: false,
replace: false,