后端 (erp-diary): - B4: CommentService 班级成员验证 + 删除评语 + SSE 通知推送 - B4: NotificationService 评语/主题/成就三类通知事件 - B5: StickerService 贴纸包列表 + 贴纸查询 + 模板管理 - B5: AchievementService 成就列表 + 解锁 + SSE 通知 - B6: MoodStatsService 心情统计 + 连续天数 - B6: ContentSafetyService 敏感词过滤框架 - SSE handler 增加 diary.notification.* 事件处理 - 新增 14 个 API 端点 + diary.comment.delete 权限 前端 (Flutter): - F5: CalendarBloc + 月视图日历 + 日记列表 - F6: MoodBloc + fl_chart 心情饼图 + 统计卡片 + 连续天数 - F7: 贴纸库分类浏览 + 模板画廊 - 首页改为日记流 + 心情快速选择 - 成就页改为徽章收集展示 验证: cargo check ✓ cargo test 17/17 ✓ flutter analyze 0 error
186 lines
5.6 KiB
Dart
186 lines
5.6 KiB
Dart
// 首页 — 日记流 + 心情概览
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:nuanji_app/core/theme/app_colors.dart';
|
|
import 'package:nuanji_app/data/models/journal_entry.dart';
|
|
|
|
/// 首页 — 展示最近日记流和心情概览
|
|
class HomePage extends StatelessWidget {
|
|
const HomePage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final colorScheme = theme.colorScheme;
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(
|
|
'暖记',
|
|
style: theme.textTheme.headlineSmall?.copyWith(
|
|
fontFamily: 'Caveat',
|
|
color: colorScheme.primary,
|
|
),
|
|
),
|
|
actions: [
|
|
IconButton(
|
|
onPressed: () => context.go('/stickers'),
|
|
icon: const Icon(Icons.emoji_emotions_outlined),
|
|
tooltip: '贴纸库',
|
|
),
|
|
IconButton(
|
|
onPressed: () => context.go('/templates'),
|
|
icon: const Icon(Icons.dashboard_customize_outlined),
|
|
tooltip: '模板',
|
|
),
|
|
],
|
|
),
|
|
body: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 心情快速选择卡片
|
|
_QuickMoodCard(colorScheme: colorScheme),
|
|
const SizedBox(height: 20),
|
|
|
|
// 最近日记标题
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
'最近日记',
|
|
style: theme.textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
TextButton(
|
|
onPressed: () => context.go('/calendar'),
|
|
child: const Text('查看全部'),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// 日记流占位 — 待数据层集成后替换
|
|
const _EmptyJournalState(),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 心情快速选择卡片
|
|
class _QuickMoodCard extends StatelessWidget {
|
|
const _QuickMoodCard({required this.colorScheme});
|
|
|
|
final ColorScheme colorScheme;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final moods = [
|
|
('😊', '开心', Mood.happy),
|
|
('😌', '平静', Mood.calm),
|
|
('😢', '难过', Mood.sad),
|
|
('😠', '生气', Mood.angry),
|
|
('🤔', '思考', Mood.thinking),
|
|
];
|
|
|
|
return Card(
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(22),
|
|
),
|
|
color: colorScheme.primaryContainer.withValues(alpha: 0.3),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'今天心情如何?',
|
|
style: theme.textTheme.titleSmall?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: moods.map((mood) {
|
|
return GestureDetector(
|
|
onTap: () => context.go('/editor'),
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
width: 44,
|
|
height: 44,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: (AppColors.moodColors[mood.$3.value] ??
|
|
colorScheme.primary)
|
|
.withValues(alpha: 0.15),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Text(mood.$1, style: const TextStyle(fontSize: 22)),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
mood.$2,
|
|
style: theme.textTheme.labelSmall?.copyWith(
|
|
color: colorScheme.onSurface.withValues(alpha: 0.6),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 空日记状态
|
|
class _EmptyJournalState extends StatelessWidget {
|
|
const _EmptyJournalState();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final colorScheme = theme.colorScheme;
|
|
|
|
return Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 48),
|
|
child: Column(
|
|
children: [
|
|
Icon(
|
|
Icons.edit_note_rounded,
|
|
size: 64,
|
|
color: colorScheme.onSurface.withValues(alpha: 0.2),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
'开始你的第一篇手账日记吧!',
|
|
style: theme.textTheme.bodyLarge?.copyWith(
|
|
color: colorScheme.onSurface.withValues(alpha: 0.5),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
FilledButton.icon(
|
|
onPressed: () => context.go('/editor'),
|
|
icon: const Icon(Icons.add_rounded),
|
|
label: const Text('写日记'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|