fix(app): 修复 P2~P4 共 10 项前端问题
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled

P2 必须修复:
- 教师布置主题 classId 从硬编码改为班级下拉选择器
- 班级日记墙使用服务端 classId 过滤替代前端过滤
- Profile 统计栏接入 JournalRepository 真实数据
- WeeklyPage 从全硬编码改为 JournalRepository 数据驱动

P3 建议改进:
- 提取 mood_utils.dart 公共函数,消除 4 处重复定义
- 贴纸库搜索框连接 StickerBloc 按名称过滤

P4 细节打磨:
- 家长页多孩子时显示 DropdownButton 选择器
- 搜索结果日记卡片点击跳转 /editor?id=
- MonthlyPage 照片数量从 JournalElement 统计
- calendar_page/mood_page/search_page 统一使用 moodToEmoji/moodToLabel
This commit is contained in:
iven
2026-06-02 20:21:51 +08:00
parent 75db6a7eb7
commit 7e928ae1e1
17 changed files with 2537 additions and 799 deletions

View File

@@ -535,7 +535,7 @@ class _ChildCard extends StatelessWidget {
}
/// 功能操作网格 — 4 个功能按钮
class _ActionGrid extends StatelessWidget {
class _ActionGrid extends StatefulWidget {
const _ActionGrid({
required this.children,
required this.onViewJournals,
@@ -550,20 +550,88 @@ class _ActionGrid extends StatelessWidget {
final void Function(String childId) onDelete;
final void Function(String childId) onMoodStats;
/// 取第一个绑定的孩子 IDPhase 1 简化逻辑)
String get _firstChildId =>
children.isNotEmpty ? children.first.childId : '';
@override
State<_ActionGrid> createState() => _ActionGridState();
}
class _ActionGridState extends State<_ActionGrid> {
late String _selectedChildId;
@override
void initState() {
super.initState();
_selectedChildId = widget.children.isNotEmpty ? widget.children.first.childId : '';
}
@override
void didUpdateWidget(covariant _ActionGrid oldWidget) {
super.didUpdateWidget(oldWidget);
// 当孩子列表变化时更新选中 ID
if (oldWidget.children != widget.children) {
if (!widget.children.any((c) => c.childId == _selectedChildId)) {
_selectedChildId = widget.children.isNotEmpty ? widget.children.first.childId : '';
}
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 孩子选择器(多孩子时显示)
if (widget.children.length > 1) ...[
Text(
'选择孩子',
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: colorScheme.surface,
borderRadius: AppRadius.mdBorder,
border: Border.all(color: colorScheme.outlineVariant),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: _selectedChildId.isEmpty ? null : _selectedChildId,
isExpanded: true,
icon: const Icon(Icons.expand_more, size: 20),
items: widget.children.map((child) {
final shortId = child.childId.length > 8
? child.childId.substring(0, 8)
: child.childId;
return DropdownMenuItem(
value: child.childId,
child: Row(
children: [
const Text('👧', style: TextStyle(fontSize: 18)),
const SizedBox(width: 8),
Text('孩子 $shortId'),
],
),
);
}).toList(),
onChanged: (v) {
if (v != null) setState(() => _selectedChildId = v);
},
),
),
),
const SizedBox(height: 16),
],
Text(
'功能',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
_ActionCard(
@@ -572,7 +640,7 @@ class _ActionGrid extends StatelessWidget {
iconBgColor: AppColors.accent.withValues(alpha: 0.12),
title: '日记查看',
subtitle: '只读查看孩子的日记和评语',
onTap: () => onViewJournals(_firstChildId),
onTap: () => widget.onViewJournals(_selectedChildId),
),
const SizedBox(height: 12),
_ActionCard(
@@ -581,7 +649,7 @@ class _ActionGrid extends StatelessWidget {
iconBgColor: AppColors.secondary.withValues(alpha: 0.12),
title: '心情统计',
subtitle: '查看孩子的写作频率和心情趋势',
onTap: () => onMoodStats(_firstChildId),
onTap: () => widget.onMoodStats(_selectedChildId),
),
const SizedBox(height: 12),
_ActionCard(
@@ -590,7 +658,7 @@ class _ActionGrid extends StatelessWidget {
iconBgColor: AppColors.tertiary.withValues(alpha: 0.12),
title: '数据导出',
subtitle: '导出孩子的所有日记数据',
onTap: () => onExport(_firstChildId),
onTap: () => widget.onExport(_selectedChildId),
),
const SizedBox(height: 12),
_ActionCard(
@@ -599,7 +667,7 @@ class _ActionGrid extends StatelessWidget {
iconBgColor: AppColors.error.withValues(alpha: 0.12),
title: '数据删除',
subtitle: '永久删除孩子的日记数据',
onTap: () => onDelete(_firstChildId),
onTap: () => widget.onDelete(_selectedChildId),
),
],
);