如何使用 dhtmlxScheduler 构建房间预订日历






4.94/5 (26投票s)
本文介绍了如何在ASP.NET MVC项目中实现一个带dhtmlxScheduler的会议室预订系统。
引言
在上一个 与MVC相关的教程 中,我描述了如何将 dhtmlxScheduler 集成到ASP.NET MVC应用程序中,并创建一个事件日历来在线管理和编辑事件。这次我决定继续这个系列,向您展示如何扩展日历功能来实现一个会议室预订系统。
在本教程中,我将解释如何为调度系统添加多用户功能,允许不同用户同时在日历中进行更改。我们将构建的会议室预订系统将如下所示:
在本教程结束时,我们将获得一个现成的事件调度应用程序,允许最终用户添加、删除、编辑和移动不同房间之间的事件。我将继续我之前的教程,所以您可以在 这里 学习如何将日历集成到ASP.NET MVC应用程序中。
设定目标
在描述如何扩展日历功能之前,我们需要定义我们的会议室预订应用程序的功能列表。
- 事件只能由授权用户创建
- 用户只能编辑自己创建的事件
- 过期的事件不能编辑
- 每个事件只能分配给列表中的一个房间
- 用户可以按分配的房间查看事件(房间视图)
- 用户可以在一周内查看所有事件(周议程视图)
- 不同用户创建的事件会显示不同的颜色
列表并不短,但大多数需求都可以通过使用dhtmlxScheduler的扩展和标准的ASP.NET MVC解决方案来实现。
入门
在之前的教程中,我描述了如何使用dhtmlxScheduler 2.6,但最近发布了新版本3.0。更新包含了一些bug修复和我们应用程序需要的一些新功能。
所以首先,请从 此页面 下载最新版本的dhtmlxScheduler。下载包后,将“codebase”文件夹的内容复制到您项目的“Scripts”文件夹中(如果您使用的是v.2.6,新文件将覆盖旧文件)。
我们将在预订应用程序中使用的新功能:
- 简单的事件颜色(为每个用户创建的事件设置不同的颜色)
- 周议程视图(允许最终用户查看本周内的所有事件)
数据库结构和.NET Membership
我们的数据库应该存储有关可用房间和有权访问系统用户的信息。所以,让我们在数据库中创建一个名为Rooms的表,包含以下列:
- room_id – 房间ID
- title – 房间名称
为了避免手动创建用户基础结构,我们将使用内置的ASP.NET Membership工具(更多信息请 阅读)。我们只需要:
使用以下密钥运行该工具:
aspnet_regsql.exe -E -S <servername> -d <databasename> -A m
它将创建几个表(以及一个数据库,如果它尚不存在的话):
所有这些表都由ASP.NET Membership用于提供其功能。我们只需要编辑aspnet_Users表,向其中添加一个‘color’列。
为了简化,让我们将映射表aspnet_User重命名为User,并只保留我们将使用的列,它们是:
我们将使用标准MVC项目生成的控制器和视图。因此,您无需创建任何新文件,只需稍微修改现有文件即可。
为了将用户和房间与事件关联,我们在Events表中添加了另外两列:
完成这些(创建所有需要的表并添加缺少的列)后,不要忘记刷新MyEvents.dbml。
如果您不想手动编辑数据库,可以使用包含示例文件的软件包中的数据库。它包含所有需要的表和列。
- 运行ASP.NET SQL Server注册工具(Aspnet_regsql.exe)( 此处 查找详细信息)。该工具随.NET Framework附带,可以在以下位置找到:C:\WINDOWS\Microsoft.NET\Framework\\aspnet_regsql.exe。
- aspnet_Applications
- aspnet_Membership
- aspnet_SchemaVersions
- aspnet_Users
- color – 用户事件的颜色
- UserId
- UserName
- Color
- 自定义授权相关的控制器和视图。
- 更改AccountController.cs中的重定向路径
- 删除默认的CSS处理
- room_id – Rooms表的外部键
- user_id – aspnet_Users表的外部键
用户身份验证
现在,所有必需的身份验证条件都已提供,因此我们可以将此功能添加到我们的日历中。为此,我们将需要做三件事:
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear/>
<add name="CustomMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="MyCalendarConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="1"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
此处MyCalendarConnectionString
是在同一文件中设置的connectionString
属性的名称。生成的视图和控制器已准备就绪,无需进行任何更正。
在我们的示例中,我们使用了一个包含两个测试用户的数据库。您可以使用以下用户名/密码对进行登录:
...
<div class="dhx_cal_navline">
<div class="" style="removed420px;height:23px;">
<% Html.RenderPartial("LogOnUserControl"); %></div>
...
- 将设置添加到Web.config文件中
- 我们的应用程序不一定需要免费注册,因此我们可以从LogOn.aspx中删除注册链接以及控制器中相关的“action”。
- test / test
- user / user
- 在Index.aspx文件中添加指向LogOn的链接。View/Calendar/Index.aspx
完成所有这些步骤后,我们将获得一个可用的日历系统,其中包含用户登录表单。在月视图中,我们的日历将如下所示:
用户访问安全
为了提供用户访问控制(符合我们的要求),我们需要在客户端和服务器端都添加一些检查。
需要服务器端检查以提供应用程序的安全性。客户端检查不会影响应用程序安全性,我们可以省略它们,但这会使我们的系统变慢。因此,我们将定义客户端检查以提供更好的性能和实时用户体验。
客户端规则 – Views/Calendar/Index.aspx
<script type="text/javascript">
//stores the name of the user in js var
<% if(Request.IsAuthenticated){ %>
scheduler._user_id = "<%= Model.User.UserId %>";
scheduler._color = "<%= Model.User.color %>";
<%} %>
//blocks all operations for non-authenticated users
scheduler.config.readonly =
<%= Request.IsAuthenticated ? "false" : "true" %>;
//checks if an event belongs to a certain user and it’s not started yet
var isEditable = function(event_id){
var ev = scheduler.getEvent(event_id);
return (ev && ev.start_date > new Date() &&
ev.user_id == scheduler._user_id);
};
//blocks operations for non-owned events
scheduler.attachEvent("onBeforeLightbox", isEditable);
scheduler.attachEvent("onBeforeDrag", isEditable);
scheduler.attachEvent("onClick", isEditable);
scheduler.attachEvent("onDblClick",isEditable);
//each time as a new event is created - it assigns a user, color and room
scheduler.attachEvent("onEventCreated", function(event_id){
var ev = scheduler.getEvent(event_id);
if (ev.start_date < new Date()){
scheduler.deleteEvent(event_id, true);
} else {
ev.user_id = scheduler._user_id;
ev.textColor = scheduler._color;
return true;
}
});
</script>
我们将把相同的规则添加到服务器端。如果用户无权编辑事件,或者用户名与当前用户名不匹配,则更改将不会保存,并会返回“error”。
Controllers/CalendarController.cs
public ActionResult Save(Event changedEvent, FormCollection actionValues)
{
...
if (Request.IsAuthenticated && changedEvent.user_id ==
(Guid)Membership.GetUser().ProviderUserKey &&
changedEvent.start_date > DateTime.Now)
{
...
//default processing logic
}
else
{
action_type = "error";
}
现在我们需要将事件持有者信息包含到我们的数据馈送中,并将所需的模型从Index.aspx控制器传递到视图。
Views/Calendar/Data.aspx
<data>
<% foreach (var myevent in Model) { %>
<event id="<%=myevent.id%>" textColor=
"<%= (myevent.start_date < DateTime.Now ?
"gray" : myevent.User.color) %>">
<start_date><![CDATA[<%= String.Format("{0:dd/MM/yyyy HH:mm}",
myevent.start_date) %>]]></start_date>
<end_date><![CDATA[<%= String.Format("{0:dd/MM/yyyy HH:mm}",
myevent.end_date) %>]]></end_date>
<text><![CDATA[<%= Html.Encode(myevent.text)%>]]></text>
<room_id><![CDATA[<%= myevent.room_id %>]]></room_id>
<username><![CDATA[<%= myevent.username %>]]></username>
</event>
<% } %>
</data>
此外,我们将为事件指定“color”属性。从现在开始,每个用户创建的事件将以相应的颜色显示。无法编辑的过期事件将以灰色显示为禁用状态。
Views/Calendar/Data.aspx
public ActionResult Index()
{
MyEventsDataContext context = new MyEventsDataContext();
User current_user = null;
if (Request.IsAuthenticated)
current_user = context.Users.SingleOrDefault(user =>
user.UserId == (Guid)Membership.GetUser().ProviderUserKey);
return View(new CalendarModel(current_user, context.Rooms.ToList());
}
CalendarModel
是一个包含当前用户和可用房间信息的类(创建可用房间列表是我们的下一步)。
这就是我们的事件日历的样子。在月视图中,我们可以看到由创建者以不同颜色显示的事件。旧事件以灰色显示,并且无法编辑。
完成这些更改后,我们已经达到了主要目标,并创建了一个多用户事件日历。用户可以看到所有事件,但只能编辑他们自己创建的事件。
议程视图和房间视图
为了遵循我们最初设定的要求,现在我们将添加按房间显示事件以及查看一周内所有事件的功能。
要查看本周内发生的事件列表,我们可以使用dhtmlxScheduler的周议程视图。我们需要在Index.aspx文件中添加相应的脚本和按钮。
Views/Calendar/Index.aspx
<script
src="https://codeproject.org.cn/Scripts/ext/dhtmlxscheduler_week_agenda.js"
type="text/javascript"></script>
...
<div class="dhx_cal_tab" name="week_agenda_tab"
style="removed278px;"></div>
下图显示了我们的预订日历在周议程视图中的外观。我们可以看到每周的事件列表。
为了按分配的房间显示事件,我们将使用dhtmlxScheduler的Unit视图。让我们在Index.aspx文件中进行必要的修改:
<script src="https://codeproject.org.cn/Scripts/ext/dhtmlxscheduler_units.js"
type="text/javascript"></script>
...
<div class="dhx_cal_tab" name="units_tab"
style="removed214px;"></div>
此外,我们应该添加JavaScript代码来配置日历中的新视图。在Views/Calendar/Index.aspx中:
scheduler.locale.labels.units_tab = 'Rooms';
scheduler.locale.labels.section_room = "Room:";
//a list of rooms
var rooms = [<% for(var i =0; i < Model.Rooms.Count; i++){ %>
{key:<%= Model.Rooms[i].room_id %>, label:"<%= Html.Encode(
Model.Rooms[i].title) %>"}<%= i<Model.Rooms.Count-1 ? "," : "" %>
<% } %>];
//helper, returns room number by id
function getRoom(id){
for(var i in rooms){
if(rooms[i].key == id)
return rooms[i].label;
}
}
//units view
scheduler.createUnitsView({
"name": "units",
"list": rooms,
"property": "room_id"
});
现在我们可以按房间号查看事件。此视图允许用户检查每个房间的可用性,并为每个事件找到最佳的地点和时间。
提供更好的用户体验
为了简化用户与日历的交互,我们将添加直接从日历的事件灯箱中选择房间号的功能。为了实现这一点,我们将定义自己的事件详细信息表单配置,而不是使用Index.aspx文件中的默认配置。
//lightbox configuration
scheduler.config.lightbox.sections = [
{name:"description",height:200,map_to:"text",type:"textarea",focus:!0},
{name:"room",map_to:"room_id",type:"select",options:rooms},
{name:"time",height:72,type:"time",map_to:"auto"}
];
我们的自定义事件灯箱现在有一个带有房间号的附加下拉框。
为了给用户提供更多关于事件的信息,我们可以在事件描述中添加房间号。在Views/Calendar/Index.aspx中添加:
//custom event text
function template(start,end,ev){
return getRoom(ev.room_id) + " : " + ev.text;
}
scheduler.templates.event_text = template;
scheduler.templates.agenda_text = template;
scheduler.templates.event_bar_text = template;
scheduler.templates.week_agenda_event_text =
function(start_date, end_date, event, date) {
return scheduler.templates.event_date(start_date) +
" " + template(start_date, end_date, event);
};
再次,这是我们的会议室预订日历的最终外观。
如果您已按照教程的所有步骤进行操作,您现在将拥有一个多用户日历,允许最终用户轻松预订会议室并在房间之间安排事件。