问题描述
共享账本 Editor 打开记账页的标签选择器时,「最近使用」区块和「全部标签」区块内容完全一致,「最近使用」失去意义。
个人账本 / Owner 视角正常。
根因
lib/utils/shared_ledger_picker_filter.dart::filterTagsForLedger 在 Editor 分支里无视传入的列表,直接返回该账本的全量 mirror 标签:
Future<List<Tag>> filterTagsForLedger(List<Tag> all, LedgerPickerContext? ctx) async {
if (ctx == null || !ctx.isEditorInShared || ctx.ledgerSyncId == null) {
return all;
}
final shared = await (select(sharedLedgerTags)
..where((t) => t.ledgerSyncId.equals(ctx.ledgerSyncId!))).get();
return shared.map(_sharedTagAsMain).toList(); // ← 入参 all 被整个丢掉
}
而 lib/providers/tag_providers.dart 的 recentTagsForCurrentLedgerProvider 先查出真正的最近 10 条、再交给它过滤:
final recent = await repo.getRecentlyUsedTags(limit: 10);
if (repo is! LocalRepository) return recent;
final ledgerId = ref.watch(currentLedgerIdProvider);
final ctx = await repo.db.loadLedgerPickerContext(ledgerId);
return repo.db.filterTagsForLedger(recent, ctx); // Editor 下被整体替换成全量
于是 Editor 下「最近使用」= 全部 mirror 标签。
影响范围很小
只有这一处调用方传的是子集。其余调用方传的都是全量列表,此时「丢弃入参、返回 mirror 集合」正是预期语义,不受影响:
| 调用点 |
传入 |
是否受影响 |
tag_providers.dart:48(全部标签) |
全量 |
否 |
tag_providers.dart:104(最近使用) |
子集 recent |
是 |
account_selector.dart:90 |
全量 |
否 |
transfer_form.dart:328 |
全量 |
否 |
category_selector.dart:104 / category_selector_dialog.dart:147 |
全量 |
否 |
所以 filterAccountsForLedger / filterCategoriesForLedger 虽然是同款写法,但没有子集调用方,暂时没有等价问题。
还有两个相邻问题,建议一并评估
1. Editor 的「最近使用」本质上取不到数据
getRecentlyUsedTags(lib/data/repositories/local/local_tag_repository.dart:723)查的是主表关联:
FROM tags t
INNER JOIN transaction_tags tt ON t.id = tt.tag_id
INNER JOIN transactions tx ON tt.transaction_id = tx.id
但共享账本 Editor 的标签关联存在 transaction_tag_overrides(按 tag_sync_id),不在 transaction_tags。所以即使修掉上面那个替换问题,Editor 的 recent 也会是空的 —— 真正的最近使用需要从 transaction_tag_overrides join transactions,再经 shared_ledger_tags 映射成 synthetic ID。
2. getRecentlyUsedTags 没有账本维度
上面那段 SQL 没有 ledger_id 过滤,是跨全部账本的全局「最近使用」。多账本用户在 A 账本记账时,「最近使用」里会混进 B 账本用过的标签。这个可能是有意的(标签本身是 user-scoped),但跟「按当前账本过滤」的 provider 命名有出入,值得确认是否符合预期。
建议修法
recentTagsForCurrentLedgerProvider 在 Editor 分支下不要复用 filterTagsForLedger,改为:
- 从
transaction_tag_overrides join 当前账本的 transactions,按 MAX(happened_at) 取最近 N 个 tag_sync_id
- 用
shared_ledger_tags 把这些 syncId 映射成 synthetic Tag(与 filterTagsForLedger 用同一个 _sharedTagAsMain / syntheticIdForSyncId 口径,保证 ID 与「全部标签」区块一致,否则选中态会错位)
- 拿不到(mirror 未到齐等)就返回空列表,让「最近使用」区块自然隐藏 —— 现有代码已经有
recentTags.isEmpty → SizedBox.shrink() 的分支
个人账本 / Owner 分支保持现状不动。
备注
发现于 #436 的真机验证过程。该 PR 未改动 shared_ledger_picker_filter.dart,recentTagsForCurrentLedgerProvider 也原封未动,因此不是 #436 引入的,按最小改动原则单独跟进。
问题描述
共享账本 Editor 打开记账页的标签选择器时,「最近使用」区块和「全部标签」区块内容完全一致,「最近使用」失去意义。
个人账本 / Owner 视角正常。
根因
lib/utils/shared_ledger_picker_filter.dart::filterTagsForLedger在 Editor 分支里无视传入的列表,直接返回该账本的全量 mirror 标签:而
lib/providers/tag_providers.dart的recentTagsForCurrentLedgerProvider先查出真正的最近 10 条、再交给它过滤:于是 Editor 下「最近使用」= 全部 mirror 标签。
影响范围很小
只有这一处调用方传的是子集。其余调用方传的都是全量列表,此时「丢弃入参、返回 mirror 集合」正是预期语义,不受影响:
tag_providers.dart:48(全部标签)tag_providers.dart:104(最近使用)recentaccount_selector.dart:90transfer_form.dart:328category_selector.dart:104/category_selector_dialog.dart:147所以
filterAccountsForLedger/filterCategoriesForLedger虽然是同款写法,但没有子集调用方,暂时没有等价问题。还有两个相邻问题,建议一并评估
1. Editor 的「最近使用」本质上取不到数据
getRecentlyUsedTags(lib/data/repositories/local/local_tag_repository.dart:723)查的是主表关联:但共享账本 Editor 的标签关联存在
transaction_tag_overrides(按tag_sync_id),不在transaction_tags。所以即使修掉上面那个替换问题,Editor 的 recent 也会是空的 —— 真正的最近使用需要从transaction_tag_overridesjointransactions,再经shared_ledger_tags映射成 synthetic ID。2.
getRecentlyUsedTags没有账本维度上面那段 SQL 没有
ledger_id过滤,是跨全部账本的全局「最近使用」。多账本用户在 A 账本记账时,「最近使用」里会混进 B 账本用过的标签。这个可能是有意的(标签本身是 user-scoped),但跟「按当前账本过滤」的 provider 命名有出入,值得确认是否符合预期。建议修法
recentTagsForCurrentLedgerProvider在 Editor 分支下不要复用filterTagsForLedger,改为:transaction_tag_overridesjoin 当前账本的transactions,按MAX(happened_at)取最近 N 个tag_sync_idshared_ledger_tags把这些 syncId 映射成 synthetic Tag(与filterTagsForLedger用同一个_sharedTagAsMain/syntheticIdForSyncId口径,保证 ID 与「全部标签」区块一致,否则选中态会错位)recentTags.isEmpty → SizedBox.shrink()的分支个人账本 / Owner 分支保持现状不动。
备注
发现于 #436 的真机验证过程。该 PR 未改动
shared_ledger_picker_filter.dart,recentTagsForCurrentLedgerProvider也原封未动,因此不是 #436 引入的,按最小改动原则单独跟进。