fix(app): 日记可见性修复 — 私密日记仅本地 + Web 端 ID 修复 + 分享按钮
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled

问题修复:
1. Web端保存的日记看不到:createJournal 返回值未捕获,server ID 丢失导致
   后续元素保存用错 ID。现在使用 saved.id 贯穿全部操作。
2. 管理端看不到新建日记:后端 list_journals 添加 is_private 过滤,admin/teacher
   查看他人日记时排除私密日记。
3. RemoteJournalRepository 添加 onJournalChanged 变更通知流,HomeBloc 可自动刷新。
4. SyncEngine(native + web)enqueue 添加 is_private 防御性检查,私密日记不入队。
5. 编辑器 _persistState 条件入队:仅非私密日记同步到后端。
6. 分享流程改造:首次从私密变为公开时入队 create 操作上传。
7. 日记卡片添加可见性标签(仅自己可见/班级可见/公开),私密日记可点击分享。
8. 首页 _sharePrivateJournal 弹出 ShareBottomSheet 主动分享。
This commit is contained in:
iven
2026-06-04 12:03:24 +08:00
parent c441aa4e34
commit bb388ed8ff
7 changed files with 276 additions and 33 deletions

View File

@@ -121,28 +121,35 @@ class _EditorPageState extends State<EditorPage> {
title: '${now.month}${now.day}日的日记',
date: now,
);
await repo.createJournal(entry);
setId(entry.id);
// 保存笔画
// 保存到仓库Web=远程API原生=Isar本地
// 远程仓库返回服务端生成的 ID必须使用返回值
final saved = await repo.createJournal(entry);
final journalId = saved.id;
setId(journalId);
// 保存笔画 — 使用 saved.id与仓库一致
if (state.strokes.isNotEmpty) {
await _saveStrokesAsElement(repo, entry.id, state.strokes);
await _saveStrokesAsElement(repo, journalId, state.strokes);
}
// 保存其他元素
for (final element in state.elements) {
await repo.addElement(element.copyWith(journalId: entry.id));
await repo.addElement(element.copyWith(journalId: journalId));
}
// 入队 SyncEngine 等待同步到后端
syncEngine.enqueue(PendingOperation(
id: entry.id,
type: SyncOperationType.create,
endpoint: '/diary/journals',
data: entry.toJson(),
version: entry.version,
createdAt: now,
));
// 仅非私密日记入队 SyncEngine 等待同步到后端
// 私密日记is_private=true仅保存在本地不上传
if (!saved.isPrivate) {
syncEngine.enqueue(PendingOperation(
id: journalId,
type: SyncOperationType.create,
endpoint: '/diary/journals',
data: saved.toJson(),
version: saved.version,
createdAt: now,
));
}
} else {
// --- 更新已有日记 ---
final existing = await repo.getJournal(savedJournalId);
@@ -156,15 +163,17 @@ class _EditorPageState extends State<EditorPage> {
);
await repo.updateJournal(updated);
// 入队 SyncEngine 等待同步到后端
syncEngine.enqueue(PendingOperation(
id: existing.id,
type: SyncOperationType.update,
endpoint: '/diary/journals/${existing.id}',
data: existing.toJson(),
version: existing.version,
createdAt: now,
));
// 仅非私密日记入队 SyncEngine
if (!updated.isPrivate) {
syncEngine.enqueue(PendingOperation(
id: updated.id,
type: SyncOperationType.update,
endpoint: '/diary/journals/${updated.id}',
data: updated.toJson(),
version: updated.version,
createdAt: now,
));
}
}
// 更新笔画
@@ -215,6 +224,11 @@ class _EditorPageState extends State<EditorPage> {
}
/// 显示分享面板并在用户选择后导航
///
/// 分享行为:
/// - 分享到班级/所有人 → is_private=false + shared_to_class=对应值
/// - 仅自己可见 → is_private=true不上传到后端
/// - 首次将私密日记变为公开时,入队 SyncEngine create 操作上传
static Future<void> _showShareSheetAndNavigate(
BuildContext context,
JournalRepository repo,
@@ -246,14 +260,41 @@ class _EditorPageState extends State<EditorPage> {
classId: userClassId,
className: userClassName,
onDecision: (shareToClass) async {
// 更新日记的 sharedToClass 状态
if (savedJournalId != null) {
try {
final entry = await repo.getJournal(savedJournalId);
if (entry != null) {
await repo.updateJournal(
entry.copyWith(sharedToClass: shareToClass),
final wasPrivate = entry.isPrivate;
// 分享到班级/所有人 → 取消私密标记
final updated = entry.copyWith(
isPrivate: false,
sharedToClass: shareToClass,
);
await repo.updateJournal(updated);
// 首次从私密变为公开 → 入队 SyncEngine 上传到后端
if (wasPrivate && !updated.isPrivate) {
final syncEngine = context.read<SyncEngine>();
syncEngine.enqueue(PendingOperation(
id: updated.id,
type: SyncOperationType.create,
endpoint: '/diary/journals',
data: updated.toJson(),
version: updated.version,
createdAt: DateTime.now(),
));
} else if (!updated.isPrivate) {
// 已公开日记的分享状态更新
final syncEngine = context.read<SyncEngine>();
syncEngine.enqueue(PendingOperation(
id: updated.id,
type: SyncOperationType.update,
endpoint: '/diary/journals/${updated.id}',
data: updated.toJson(),
version: updated.version,
createdAt: DateTime.now(),
));
}
}
} catch (e) {
debugPrint('更新分享状态失败: $e');