【发布时间】:2020-10-16 17:32:17
【问题描述】:
我在颤振中使用 table_calendar 构建了一个包含用户约会的日历。在我当前的代码中,我只能返回用户的所有约会。现在,我试图仅在同一个月内获取所有约会并将它们显示在日历下方。也就是说,当我在日历上交换月份时,我应该只看到我当前正在查看的月份内的约会列表。
目前,我正在从后端获取用户的所有约会记录。为了实现我的目标,哪种方式会更容易:
通过使用该月第一天的日期信息定义“更改月份按钮”并使用它在后端选择相应的数据
或
仍在检索所有约会记录并以某种方式在前端过滤它们?
谁能帮助我通过具体的解决方案实现我的目标?
(如下面的当前输出所示,当我在 10 月时,我仍然看到 6 月的约会)。 Current Output
前端代码:
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:frontend/util/authentication.dart';
import 'package:frontend/util/serverDetails.dart';
import 'package:http/http.dart' as http;
import 'package:frontend/components/appointment.dart';
import 'package:frontend/screens/appointmentdetail.dart';
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:frontend/main.dart';
import 'package:frontend/screens/appointmentlist.dart';
class Appointments extends StatefulWidget {
@override
_AppointmentsState createState() => _AppointmentsState();
}
class _AppointmentsState extends State<Appointments>
with TickerProviderStateMixin {
var _calendarController;
Map<DateTime, List> _events;
List<Appointment> _samemonthevents = List<Appointment>();
AnimationController _animationController;
@override
void initState() {
super.initState();
_events = Map<DateTime, List>();
_calendarController = CalendarController();
getSameMonthAppointments();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
}
@override
void dispose() {
_calendarController.dispose();
super.dispose();
}
getSameMonthAppointments() async {
String currentToken = await Authentication.getCurrentToken();
print(currentToken);
if (currentToken == null) {
print('bouncing');
Authentication.bounceUser(context);
} else {
String auth = "Bearer " + currentToken;
String url = ServerDetails.ip +
':' +
ServerDetails.port +
ServerDetails.api +
'me/appointments';
print(url);
Map<String, String> headers = {"Authorization": auth};
print(headers);
var jsonResponse = null;
var response = await http.get(url, headers: headers);
print(response.body);
if (response.statusCode == 200) {
print("200" + response.body);
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
setState(() {
for (var doc in jsonResponse) {
_samemonthevents.add(Appointment.fromJson(doc));
}
});
}
} else {
print(response.body);
}
}
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
print('CALLBACK: _onVisibleDaysChanged');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(60.0),
child: AppBar(
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
color: Colors.black,
onPressed: () {
setState(() {});
Navigator.push(context,
MaterialPageRoute(builder: (context) => MainPage()));
}),
centerTitle: true,
title: Text("Appointment", style: TextStyle(color: Colors.black)),
backgroundColor: Colors.white,
brightness: Brightness.light,
automaticallyImplyLeading: false,
// backgroundColor: Color(0x44000000),
elevation: 0.5,
actions: <Widget>[
IconButton(
color: Colors.black,
icon: Icon(Icons.list),
onPressed: () {
setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AppointmentList()));
},
)
],
),
),
body: new Builder(builder: (BuildContext context) {
return new Column(children: <Widget>[
_buildTableCalendarWithBuilders(),
const SizedBox(height: 8.0),
const SizedBox(height: 8.0),
//_buildEventList()
//_buildsameMonthEventList()
Expanded(child: _buildsameMonthEventList()),
]);
}));
}
// More advanced TableCalendar configuration (using Builders & Styles)
Widget _buildTableCalendarWithBuilders() {
return TableCalendar(
calendarController: _calendarController,
events: _events,
//holidays: _holidays,
initialCalendarFormat: CalendarFormat.month,
formatAnimation: FormatAnimation.slide,
startingDayOfWeek: StartingDayOfWeek.sunday,
availableGestures: AvailableGestures.all,
availableCalendarFormats: const {CalendarFormat.month: ''},
calendarStyle: CalendarStyle(
outsideDaysVisible: false,
weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
),
daysOfWeekStyle: DaysOfWeekStyle(
weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
),
builders: CalendarBuilders(
selectedDayBuilder: (context, date, _) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 1.0).animate(_animationController),
child: Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue[300],
borderRadius: BorderRadius.circular(36.0),
border: Border.all(width: 2, color: Colors.blue[300])),
child: Text(
'${date.day}',
style: TextStyle().copyWith(
fontSize: 20.0,
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
);
},
todayDayBuilder: (context, date, _) {
return Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(36.0),
border: Border.all(width: 2, color: Colors.white)),
child: Text(
'${date.day}',
style: TextStyle().copyWith(
fontSize: 20.0,
color: Colors.black,
fontWeight: FontWeight.bold),
),
);
},
markersBuilder: (context, date, events, holidays) {
final children = <Widget>[];
if (events.isNotEmpty) {
children.add(
Positioned(
child: _buildEventsMarker(date, events),
),
);
}
if (holidays.isNotEmpty) {
children.add(
Positioned(
right: -2,
top: -2,
child: _buildHolidaysMarker(),
),
);
}
return children;
},
),
onVisibleDaysChanged: _onVisibleDaysChanged,
);
}
Widget _buildEventsMarker(DateTime date, List events) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(36.0),
border: Border.all(width: 2, color: Colors.blue[300])),
);
}
Widget _buildHolidaysMarker() {
return Icon(
Icons.add_box,
size: 20.0,
color: Colors.blueGrey[800],
);
}
Widget _buildsameMonthEventList() {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(22.0),
child: AppBar(
centerTitle: true,
title: Text("Appointments of Current Month",
style: TextStyle(color: Colors.black, fontSize: 18)),
backgroundColor: Colors.yellow[200],
brightness: Brightness.light,
automaticallyImplyLeading: false,
// backgroundColor: Color(0x44000000),
elevation: 0.5,
),
),
body: (_samemonthevents.length == 0)
? Text("No appointment record in current month!",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 16))
: ListView(
children: _samemonthevents
.map((event) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.8),
borderRadius: BorderRadius.circular(12.0),
),
margin: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 4.0),
child: (event is Appointment)
? ListTile(
leading: Column(children: <Widget>[
//Show Weekday, Month and day of Appiontment
Text(
DateFormat('EE').format(event.date) +
' ' +
DateFormat.MMMd().format(event.date),
style: TextStyle(
color: Colors.blue.withOpacity(1.0),
fontWeight: FontWeight.bold,
)),
//Show Start Time of Appointment
Text(DateFormat.jm().format(event.date),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
height: 1.5,
)),
//Show End Time of Appointment
Text(
DateFormat.jm().format(event.date.add(
Duration(
minutes: event.duration ?? 0))),
style: TextStyle(
color: Colors.black.withOpacity(0.6)),
),
]), //Text(DateFormat.Hm().format(event.date)),//DateFormat.Hm().format(now)
title: Text(event.title),
trailing: event.status == 'UNCONFIRMED'
? Column(children: <Widget>[
//event.status=='CONFIRMED' ?
Icon(Icons.error,
color: Colors.pink,
//size:25.0,
semanticLabel:
'Unconfirmed Appointment'), //:Container(width:0,height:0),
Icon(Icons.arrow_right),
])
: Icon(Icons.arrow_right),
onTap: () {
setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
AppointmentDetail(event)));
},
)
: null))
.toList()));
}
}
后端代码:
AppointmentAPI.java
@GET
@Path("me/appointments")
@Secured(UserRole.PATIENT)
@JSONP(queryParam = "callback")
@Produces(MediaType.APPLICATION_JSON)
public Response listMyAppointments(
@Context SecurityContext sc,
@QueryParam("since") String since,
@QueryParam("until") String until,
@QueryParam("is_confirmed") Boolean is_confirmed) {
String uid = sc.getUserPrincipal().getName();
List<Appointment> results = retrieveUserAppointments(uid, since, until, is_confirmed);
return Response.ok(results).build();
}
AppointmentMapper.java
List<Appointment> getAppointmentsByUserId(
@Param("uid") String uid,
@Param("since") String since,
@Param("until") String until,
@Param("status") AppointmentStatus status);
AppointmentMapper.xml
<mapper namespace="com.sec.db.AppointmentMapper">
<select id="getAppointmentById" parameterType="String" resultType="com.sec.entity.Appointment">
SELECT * FROM Appointment WHERE id= #{id}
</select>
<select id="getAppointmentsByUserId" resultType="com.sec.entity.Appointment">
SELECT *
FROM Appointment
WHERE uid= #{uid}
<choose>
<when test="since != null and until != null">
AND date BETWEEN #{since} AND #{until}
</when>
<when test="since != null and until == null">
AND date > #{since}
</when>
<when test="since == null and until != null">
<![CDATA[
AND date < #{until}
]]>
</when>
</choose>
<choose>
<when test="status == null">
AND status != 'CANCELLED'
</when>
<otherwise>
AND status = #{status}
</otherwise>
</choose>
</select>
Json 响应示例:
### Response
Status: 200 OK
```JSON
[
{
"date": "2020-06-22T14:15:00Z",
"date_change": "2018-05-14T10:17:40Z",
"date_create": "2018-05-14T10:17:40Z",
"detail": "Inflisaport Insertion",
"duration": 15,
"id": "2",
"note": "Looking forward to see you! Take care",
"status": "CONFIRMED",
"title": "Private Hospital",
"uid": "1"
}
]
【问题讨论】:
-
需要完整的 json 响应来重现此错误。请发布您的完整 json 字符串。谢谢。
-
当然!但是没有错误,在这种情况下getSameMonthAppointments基本上只是作为getAppointments执行,它从数据库中获取所有记录并且不从_onVisibleDaysChanged函数中获取任何日期输入。在这种情况下,getSameMonthAppointments 只是为了思考而命名。
-
Json 响应示例已更新!
-
主要问题是我现在不知道如何通过'_onVisibleDaysChanged'函数获取每个月的第一个日期来表示月份。如果我能做到这一点,我可以使用以下方法在数据库中选择预期数据:SELECT * FROM Appointment WHERE uid= #{uid} AND MONTH(date) = MONTH(#{date}) AND YEAR(date) = YEAR(#{date })