fix: seed production defaults and harden onboarding

This commit is contained in:
2026-08-22 23:18:27 +08:00
parent acf6356ba6
commit c6f98b5445
5 changed files with 182 additions and 62 deletions
@@ -39,15 +39,17 @@ class GuestMergeService {
: (existingLedger['id'] as num).toInt();
final categoryMap = <int, int>{};
final available = <Map<String, dynamic>>[];
for (final type in ['expense', 'income']) {
for (final type in ['expense', 'income']) {
final response = await _dio.get(
'/api/categories',
queryParameters: {'type': type},
);
available.addAll(
(response.data as List).map((item) => item as Map<String, dynamic>),
);
}
);
}
await _ensureFallbackCategory(available, 'expense');
await _ensureFallbackCategory(available, 'income');
for (final value in snapshot['categories'] as List<dynamic>? ?? const []) {
final category = value as Map<String, dynamic>;
@@ -90,9 +92,10 @@ class GuestMergeService {
item['name'] == transaction['categoryName'],
);
if (exact.isNotEmpty) return (exact.first['id'] as num).toInt();
final fallback = available.firstWhere(
(item) => item['type'] == categoryType && item['name'] == '其他',
);
final fallback = available.firstWhere(
(item) => item['type'] == categoryType && item['name'] == '其他',
orElse: () => throw StateError('$categoryType 分类缺少“其他”,无法导入本机账单'),
);
return (fallback['id'] as num).toInt();
}
@@ -145,13 +148,47 @@ class GuestMergeService {
await CurrentLedgerStore.instance.ensureLoaded(force: true);
await CurrentLedgerStore.instance.select(ledgerId);
return GuestMergeResult(
ledgerId: ledgerId,
transactionCount: transactionCount,
);
}
static int? _findMappedDefault(
return GuestMergeResult(
ledgerId: ledgerId,
transactionCount: transactionCount,
);
}
static Future<void> _ensureFallbackCategory(
List<Map<String, dynamic>> available,
String type,
) async {
bool hasFallback() => available.any(
(item) => item['type'] == type && item['name'] == '其他',
);
if (hasFallback()) return;
try {
final response = await _dio.post(
'/api/categories',
data: {
'name': '其他',
'iconKey': 'tag',
'colorKey': type == 'income' ? 'lime' : 'graphite',
'type': type,
},
);
available.add(response.data as Map<String, dynamic>);
} catch (_) {
// Another request may have created it between the list and create calls.
final response = await _dio.get(
'/api/categories',
queryParameters: {'type': type},
);
available.removeWhere((item) => item['type'] == type);
available.addAll(
(response.data as List).map((item) => item as Map<String, dynamic>),
);
if (!hasFallback()) rethrow;
}
}
static int? _findMappedDefault(
List<Map<String, dynamic>> available,
Map<String, dynamic> snapshot,
int oldCategoryId,