// 发现页数据模型 — 手写不可变类(避免 build_runner 依赖) /// 发现页聚合响应 — 一次 API 返回全部板块数据 class DiscoverData { final InspirationItem? dailyInspiration; final List hotTopics; final List featuredTemplates; final List expertDiaries; const DiscoverData({ this.dailyInspiration, this.hotTopics = const [], this.featuredTemplates = const [], this.expertDiaries = const [], }); factory DiscoverData.fromJson(Map json) => DiscoverData( dailyInspiration: json['daily_inspiration'] != null ? InspirationItem.fromJson( json['daily_inspiration'] as Map) : null, hotTopics: (json['hot_topics'] as List? ?? []) .map((e) => TagCount.fromJson(e as Map)) .toList(), featuredTemplates: (json['featured_templates'] as List? ?? []) .map( (e) => DiscoverTemplateItem.fromJson(e as Map)) .toList(), expertDiaries: (json['expert_diaries'] as List? ?? []) .map((e) => ExpertDiaryItem.fromJson(e as Map)) .toList(), ); /// 心情 → emoji 映射 static String moodToEmoji(String mood) => switch (mood) { 'happy' => '😊', 'calm' => '😌', 'sad' => '😢', 'angry' => '😤', 'thinking' => '🤔', _ => '📝', }; } /// 每日推荐条目 class InspirationItem { final String journalId; final String title; final String authorName; final String mood; final DateTime date; const InspirationItem({ required this.journalId, required this.title, required this.authorName, required this.mood, required this.date, }); factory InspirationItem.fromJson(Map json) => InspirationItem( journalId: json['journal_id'] as String, title: json['title'] as String, authorName: json['author_name'] as String, mood: json['mood'] as String, date: DateTime.parse(json['date'] as String), ); } /// 热门话题 class TagCount { final String tag; final int count; const TagCount({required this.tag, required this.count}); factory TagCount.fromJson(Map json) => TagCount( tag: json['tag'] as String, count: json['count'] as int, ); } /// 精选模板条目(轻量版,不含 layout_data) class DiscoverTemplateItem { final String id; final String name; final String? previewUrl; final String? category; final bool isFree; const DiscoverTemplateItem({ required this.id, required this.name, this.previewUrl, this.category, this.isFree = true, }); factory DiscoverTemplateItem.fromJson(Map json) => DiscoverTemplateItem( id: json['id'] as String, name: json['name'] as String, previewUrl: json['preview_url'] as String?, category: json['category'] as String?, isFree: json['is_free'] as bool? ?? true, ); /// 分类 → emoji 映射 String get emoji => switch (category) { '日常' => '📖', '旅行' => '✈️', '校园' => '🎓', '节日' => '🎄', '创意' => '✨', '心情' => '🌿', _ => '📝', }; /// 使用人数展示文本 String get usageText => isFree ? '免费模板' : '精品模板'; } /// 达人日记条目 class ExpertDiaryItem { final String journalId; final String title; final String authorId; final String authorName; final String authorEmoji; final String contentPreview; final int likeCount; final DateTime createdAt; const ExpertDiaryItem({ required this.journalId, required this.title, required this.authorId, required this.authorName, required this.authorEmoji, required this.contentPreview, required this.likeCount, required this.createdAt, }); factory ExpertDiaryItem.fromJson(Map json) => ExpertDiaryItem( journalId: json['journal_id'] as String, title: json['title'] as String, authorId: json['author_id'] as String, authorName: json['author_name'] as String, authorEmoji: json['author_emoji'] as String, contentPreview: json['content_preview'] as String? ?? '', likeCount: json['like_count'] as int? ?? 0, createdAt: DateTime.parse(json['created_at'] as String), ); /// 点赞数展示文本 String get likeText => '$likeCount 赞'; }