1. 日历数据绑定
在本小节中,我们将创建:
-
Meeting
JPA 实体。 -
带有 data provider 的
FullCalendar
组件。
会议事项
FullCalendar
组件中的一个事项通过 Meeting
实体表示。需要提供特定的属性才能正确显示:
-
name
- 事项标题。 -
startDate
- 事项的开始日期和时间。组件不会显示没有startDate
的事项。 -
endDate
- 事项的结束日期。如果未指定endDate
,组件将根据allDay
属性设置事项的默认时长。本示例中省略了allDay
属性,事项都作为非全天事项处理。
创建会议实体
参考入门教程的 简单 CRUD 部分了解创建 JPA 实体的详细说明。
Meeting
实体具有以下属性:
-
name
,String
类型。勾选 Mandatory 复选框。 -
startDate
,LocalDateTime
类型。勾选 Mandatory 复选框。 -
endDate
,LocalDateTime
类型。 -
user
- 属性类型为Association
、Java 类型为User
实体,关系为多对一。勾选 Mandatory 复选框。
Meeting
实体不需要生成标准的列表和详情视图,因为该实体将以编程方式生成并显示在 FullCalendar
组件中。
生成会议
用户完成所有入职步骤后,应用程序会生成会议事项,该会议的目的是评估已完成的入职任务。该事项将显示在用户的 MyCalendar 视图中。
检查用户是否已完成所有步骤的最佳时机是在 DataContext 的 PreSaveEvent 中。在该事件的监听器中,检查是否有没完成的入职步骤。如果没有未完成的步骤,则创建新的会议事项。
@Subscribe(target = Target.DATA_CONTEXT)
public void onPreSave(final DataContext.PreSaveEvent event) {
List<UserStep> userSteps = userStepsDc.getItems().stream()
.filter(us -> us.getCompletedDate() == null)
.toList();
if (userSteps.isEmpty()) {
generateOnboardingResultsMeeting();
}
}
下一步,我们实现 generateOnboardingResultsMeeting()
方法。该方法创建一个 Meeting
的实例,并将该事项计划在下一工作日。
protected void generateOnboardingResultsMeeting() {
Meeting meeting = dataContext.create(Meeting.class); (1)
meeting.setName("Results meeting");
meeting.setUser((User) currentAuthentication.getUser());
int inDays = LocalDate.now().getDayOfWeek() == DayOfWeek.FRIDAY ? 3 : 1; (2)
LocalDateTime start = LocalDateTime.of( (3)
LocalDate.now().plusDays(inDays),
LocalTime.of(9, 30));
meeting.setStartDate(start);
meeting.setEndDate(start.plusMinutes(30));
}
1 | 创建 Meeting 实例,合并到 DataContext 中,实体会自动持久化。 |
2 | 计算下一个工作日,如果今天是星期五,则事项计划在下个星期一。 |
3 | 设置会议的开始日期和时间。 |
在 MyCalendar 添加组件
首先,创建一个新的空视图,名为 MyCalendar。
Studio 会生成空视图并打开视图设计器。
加载数据
在添加 FullCalendar
组件之前,需要先为 Meeting
实体创建一个 集合数据容器。
点击操作面板中的 Add Component,双击 Data components 中的 Collection container。在打开的弹窗中,Entity 字段选择 Meeting
,点击 OK。
<collection id="meetingsDc" class="com.company.onboarding.entity.Meeting">
<loader id="meetingsDl" readOnly="true">
<query>
<![CDATA[select e from Meeting e]]>
</query>
</loader>
<fetchPlan extends="_base"/>
</collection>
当前数据加载器的配置是查询所有用户的所有事项。但是,每个用户应该只能看到自己的事项。需要通过编辑器或手动修改 JPQL,添加按当前登录用户过滤的条件:
<query>
<![CDATA[select e from Meeting e where e.user = :user]]>
</query>
我们从 CurrentAuthentication
bean 获取当前登录的用户,并将此信息传递给 BeforeShowEvent 中的数据加载器:
-
订阅
BeforeShowEvent
。 -
注入
meetingsDl
数据加载器。 -
注入
CurrentAuthentication
bean。
现在可以为加载器设置一个参数来获取当前用户的事项:
@ViewComponent
private CollectionLoader<Meeting> meetingsDl;
@Autowired
private CurrentAuthentication currentAuthentication;
@Subscribe
public void onBeforeShow(final BeforeShowEvent event) {
final User user = (User) currentAuthentication.getUser();
meetingsDl.setParameter("user", user);
meetingsDl.load();
}
添加 FullCalendar 组件
在操作面板中,点击 Add Component,找到 FullCalendar
并双击。
新的 calendar
元素会被添加到视图中。按以下代码配置 id
、height
和 width
属性。
<calendar:calendar id="calendar"
height="100%"
width="100%"/>
添加 Data Provider
data provider 是 FullCalendar
中显示的事项来源。有不同类型的 data provider,我们将使用基于 数据容器 的 provider。
为 FullCalendar
添加 ContainerDataProvider:
-
在 Jmix UI 结构面板或视图 XML 中选择
calendar
组件。 -
点击组件属性面板中的 Add 按钮。
-
从下拉菜单中,选择 Data Providers → ContainerDataProvider。
在弹窗中,选择 meetingsDc
。
在 containerDataProvider
元素中,可以配置实体属性映射。Meeting
实体有以下属性:
-
name
-
startDate
-
endDate
因此,需要配置下列属性:
<calendar:dataProviders>
<calendar:containerDataProvider dataContainer="meetingsDc"
title="name"
startDateTime="startDate"
endDateTime="endDate"/>
</calendar:dataProviders>
完整的日历组件 XML 如下:
<calendar:calendar id="calendar"
height="100%"
width="100%">
<calendar:dataProviders>
<calendar:containerDataProvider dataContainer="meetingsDc"
title="name"
startDateTime="startDate"
endDateTime="endDate"/>
</calendar:dataProviders>
</calendar:calendar>
启动应用程序并以 admin
用户登录。admin
用户没有入职步骤,我们需要生成一下:
-
从菜单中选择 Users 打开
User.list
视图。 -
在表格中选择
admin
用户,点击 Edit 按钮。然后,填写 Joining Date 字段,生成入职步骤并保存更改。 -
从菜单中选择 MyCalendar 即可访问日历视图。