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

@@ -7,6 +7,7 @@ import 'package:nuanji_app/core/theme/app_colors.dart';
import 'package:nuanji_app/core/theme/app_radius.dart';
import 'package:nuanji_app/data/repositories/class_repository.dart';
import 'package:nuanji_app/data/repositories/journal_repository.dart';
import 'package:nuanji_app/data/models/school_class.dart';
import '../../class_/bloc/class_bloc.dart';
/// 老师管理页面 — 教师专属功能入口
@@ -162,57 +163,91 @@ class _TeacherView extends StatelessWidget {
final titleController = TextEditingController();
final descController = TextEditingController();
// 从 ClassBloc 获取已加载的班级列表
final classState = context.read<ClassBloc>().state;
final classes = classState is ClassListLoaded ? classState.classes : <SchoolClass>[];
// 无班级时提示先创建
if (classes.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请先创建班级后再布置主题')),
);
return;
}
String selectedClassId = classes.first.id;
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
title: const Text('布置主题'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: titleController,
decoration: const InputDecoration(
labelText: '主题标题',
hintText: '例如: 我的周末',
border: OutlineInputBorder(),
builder: (dialogContext) => StatefulBuilder(
builder: (context, setDialogState) => AlertDialog(
title: const Text('布置主题'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 班级选择下拉框
DropdownButtonFormField<String>(
value: selectedClassId,
decoration: const InputDecoration(
labelText: '选择班级',
border: OutlineInputBorder(),
),
items: classes
.map((c) => DropdownMenuItem(
value: c.id,
child: Text(c.name),
))
.toList(),
onChanged: (v) {
if (v != null) setDialogState(() => selectedClassId = v);
},
),
const SizedBox(height: 12),
TextField(
controller: titleController,
decoration: const InputDecoration(
labelText: '主题标题',
hintText: '例如: 我的周末',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 12),
TextField(
controller: descController,
decoration: const InputDecoration(
labelText: '描述(可选)',
hintText: '主题要求和说明',
border: OutlineInputBorder(),
),
maxLines: 3,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: const Text('取消'),
),
const SizedBox(height: 12),
TextField(
controller: descController,
decoration: const InputDecoration(
labelText: '描述(可选)',
hintText: '主题要求和说明',
border: OutlineInputBorder(),
),
maxLines: 3,
FilledButton(
onPressed: () {
if (titleController.text.trim().isNotEmpty) {
context.read<ClassBloc>().add(TopicAssign(
classId: selectedClassId,
title: titleController.text.trim(),
description: descController.text.trim().isEmpty
? null
: descController.text.trim(),
));
Navigator.pop(dialogContext);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('主题布置成功!')),
);
}
},
child: const Text('布置'),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: const Text('取消'),
),
FilledButton(
onPressed: () {
if (titleController.text.trim().isNotEmpty) {
context.read<ClassBloc>().add(TopicAssign(
classId: 'class-1',
title: titleController.text.trim(),
description: descController.text.trim().isEmpty
? null
: descController.text.trim(),
));
Navigator.pop(dialogContext);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('主题布置成功!')),
);
}
},
child: const Text('布置'),
),
],
),
);
}