import 'package:flutter/material.dart'; import 'package:food_hub_app/api/recipe.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/utils/date_util.dart'; import 'package:food_hub_app/utils/index.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; class RecipeCalendar extends StatefulWidget { const RecipeCalendar({super.key}); @override State createState() => _RecipeCalendarState(); } class _RecipeCalendarState extends State { DateTime _selectedDay = DateTime.now(); DateTime _focusedDay = DateTime.now(); List recordList = []; List selectRecordList = []; @override void initState() { super.initState(); refreshRecord(); } Future refreshRecord() async { final result = await queryRecordApi( getFirstDayOfMonth(_focusedDay), getLastDayOfMonth(_focusedDay), ); setState(() { recordList = result; if (recordList.isNotEmpty) { _selectedDay = DateTime.parse(recordList.last.date); } else { _selectedDay = _focusedDay; } refreshSelectRecord(); }); } void refreshSelectRecord() { setState(() { selectRecordList = recordList .where((record) => record.date == formatDateTime(_selectedDay)) .toList(); }); } TableCalendar recipeCalendar() { return TableCalendar( locale: 'zh_CN', headerStyle: const HeaderStyle( formatButtonVisible: false, titleCentered: true, ), firstDay: DateTime.utc(2010, 1, 1), lastDay: DateTime.utc(2100, 12, 31), focusedDay: _focusedDay, selectedDayPredicate: (day) => isSameDay(_selectedDay, day), onDaySelected: (selectedDay, focusedDay) { if (!isSameDay(_selectedDay, selectedDay)) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; refreshSelectRecord(); }); } }, onPageChanged: (focusedDay) { _focusedDay = focusedDay; refreshRecord(); }, // 自定义日期单元格构建器 calendarBuilders: CalendarBuilders( defaultBuilder: (context, day, focusedDay) => _buildDateWidget(day, false, false), selectedBuilder: (context, day, focusedDay) => _buildDateWidget(day, true, false), todayBuilder: (context, day, focusedDay) => _buildDateWidget(day, false, true), ), ); } Widget dailyItem() { return Card( elevation: 0, color: Colors.white, child: Padding( padding: EdgeInsets.all(5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(formatDateTime(_selectedDay, 'MM月dd日 EEEE')), if (selectRecordList.isEmpty) TDEmpty(type: TDEmptyType.plain, emptyText: '暂无数据') else ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: selectRecordList.length, itemBuilder: (context, index) { return recipeRecordItem(selectRecordList[index]); }, ), ], ), ), ); } Widget recipeRecordItem(Record record) { return Card( elevation: 0, color: Color(0xFFF5F5DC), child: Padding( padding: EdgeInsets.all(10), child: Row( children: [ TDAvatar( size: TDAvatarSize.medium, type: TDAvatarType.customText, text: record.category[0], ), SizedBox(width: 10), Expanded( // 使用Expanded让文本区域占据剩余空间 child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( record.name, style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 5), Text(record.category, style: TextStyle(color: Colors.grey)), ], ), ), circleIconButton( context: context, icon: Icons.chevron_right, onPressed: () => {} ), ], ), ), ); } Widget _buildDateWidget(DateTime day, bool isSelected, bool isToday) { // 检查当前日期是否在需要显示红点的列表中 bool shouldShowRedDot = recordList.any( (item) => item.date == formatDateTime(day), ); return Container( width: 40, height: 40, margin: EdgeInsets.all(2), decoration: BoxDecoration( color: isSelected ? Theme.of(context).primaryColor : isToday ? Colors.grey[300] : Colors.transparent, shape: BoxShape.circle, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ // 日期数字 Text( day.day.toString(), style: TextStyle(color: isSelected ? Colors.white : Colors.black), ), // 底部红点 - 只在指定日期显示 if (shouldShowRedDot) Container( margin: EdgeInsets.only(top: 2), width: 6, height: 6, decoration: BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), ), ], ), ); } @override Widget build(BuildContext context) { return Column( children: [ Card(elevation: 0, color: Colors.white, child: recipeCalendar()), Expanded(child: dailyItem()), ], ); } }