ASP.NET 大學(xué)場地預(yù)約借用系統(tǒng)(源碼+數(shù)據(jù)庫)
這個是我在修專業(yè)課《Web應(yīng)用開發(fā)技術(shù)》時(shí)的結(jié)課作業(yè),分組是按5人一組的。結(jié)果由于我是大四老學(xué)長回來補(bǔ)修的。就自己單干了。采用了asp.net技術(shù)開發(fā)的,前端用了一些CSS框架進(jìn)行美化。數(shù)據(jù)交互采用AJAX,數(shù)據(jù)庫用的SQL Sever。
1、目標(biāo)與應(yīng)用場景
同學(xué)們在進(jìn)行各類活動時(shí),通常需要一定的場地配合。如果是室外場地,例如操場等無需進(jìn)行借用預(yù)約便可使用。但是大部分活動都需要在室內(nèi)場地完成,例如開團(tuán)員大會,開班會,班級聯(lián)誼等。再者,教師群體需要舉辦學(xué)術(shù)交流活動等也需要室內(nèi)的場地完成。華中科技大學(xué)的教室和公用場地十分充足,即使在工作日,也有很多空閑的場地剩余。場地包括啟明學(xué)院、教學(xué)樓、學(xué)生公寓內(nèi)部的公用房、學(xué)院內(nèi)的教室等。為滿足廣大同學(xué)的學(xué)習(xí)活動需求,促進(jìn)同學(xué)之間的交流,同時(shí)更加充分地利用公共教室范圍內(nèi)的場地,我們小組決定設(shè)計(jì)并實(shí)現(xiàn)華中科技大學(xué)的場地預(yù)約系統(tǒng),該系統(tǒng)的需求如下:
- 用戶可以登錄系統(tǒng),進(jìn)行教室的預(yù)約。
- 系統(tǒng)需要支持多用戶使用,用戶之間同一教室的預(yù)約時(shí)間段不能沖突。
- 如果不需要教室了,用戶可以選擇取消自己的預(yù)約。
- 用戶能看到自己的歷史預(yù)約信息。
根據(jù)以上的需求,擬實(shí)現(xiàn)的系統(tǒng)功能如下:
- 登錄注冊:新用戶可以通過注冊頁面進(jìn)行注冊,隨后使用注冊的賬號密碼進(jìn)行系統(tǒng)登錄并使用。密碼采用MD5密文保存到數(shù)據(jù)庫中,確保用戶的隱私安全。
- 場地展示:系統(tǒng)從數(shù)據(jù)庫讀取當(dāng)前的場地信息,如場地類型、場地的名稱、是否空閑等信息。并將其展示到頁面前臺,供用戶查看選擇。
- 預(yù)約:用戶根據(jù)自己需要的場地類型,選擇合適的場地,選中后系統(tǒng)顯示該場地已被預(yù)約的時(shí)段,避免產(chǎn)生沖突。用戶選擇好時(shí)間段以后即可進(jìn)行預(yù)約,系統(tǒng)檢測預(yù)約是否沖突,如果不沖突則預(yù)約成功。
- 取消預(yù)約:展示用戶已經(jīng)預(yù)約成功的場地和時(shí)段,用戶不需要了可以取消預(yù)約。
- 歷史展示:顯示用戶的歷史預(yù)約記錄。
該系統(tǒng)的應(yīng)用群體主要為大學(xué)生和大學(xué)教師。場景面向大學(xué)校園。旨在打造一個方便的場地預(yù)約管理系統(tǒng)。
2、設(shè)計(jì)思路
系統(tǒng)的設(shè)計(jì)分為前端、后端和數(shù)據(jù)庫三大塊。初步確定的開發(fā)平臺為微軟的.net平臺+SQL Sever數(shù)據(jù)庫(當(dāng)然也是課程設(shè)計(jì)要求的)。前端對相關(guān)的頁面進(jìn)行設(shè)計(jì)布局,還可以使用現(xiàn)成的CSS框架進(jìn)行一定的美化。后端可以使用老師封裝好的SqlHelper.cs進(jìn)行數(shù)據(jù)庫的一些請求。前后端交互采用的主要是AJAX技術(shù),實(shí)現(xiàn)輕量級的交互。關(guān)于前后端主要的思路如下:
- 前端:分頁面進(jìn)行開發(fā),可以使得結(jié)構(gòu)更加清晰。頁面可劃分為登錄注冊頁面和主功能頁面。
- 后端:交互技術(shù)使用AJAX進(jìn)行交互,后端可以使用.ashx文件進(jìn)行API的編寫,采用參數(shù)action控制請求的類型,例如action=”login”時(shí)表示請求的是登錄功能,從而進(jìn)行判斷。
- 數(shù)據(jù)庫:確定系統(tǒng)的功能,提取相應(yīng)的數(shù)據(jù)結(jié)構(gòu),建立數(shù)據(jù)庫表。系統(tǒng)功能結(jié)構(gòu)設(shè)計(jì)圖如下:

3、關(guān)鍵問題與實(shí)現(xiàn)代碼
在該系統(tǒng)中,關(guān)鍵性的問題主要有以下幾個:
(1)AJAX接口的設(shè)計(jì)問題,項(xiàng)目屬于輕量級項(xiàng)目,不需要多個后臺接口文件(.ashx),避免造成管理上的不便。采用一個.ashx實(shí)現(xiàn)多個請求,需要在請求時(shí)加上該請求所需要的功能,即action參數(shù)。因此采用了以下的框架:
public?void?ProcessRequest(HttpContext?context)
????????{
????????????context.Response.ContentType?=?"text/plain";
????????????string?action?=?context.Request["action"];
????????????if?(!string.IsNullOrEmpty(action))
????????????{
????????????????switch?(action)
????????????????{
????????????????????case?"bookRoom":
在開頭便判斷Request的action參數(shù),確定該請求所需要的功能,然后調(diào)用相應(yīng)的代碼進(jìn)行Response。
(2)利用請求返回的json數(shù)據(jù)創(chuàng)建相應(yīng)的HTML代碼,顯示到頁面上。以場地信息的展示為例:
后臺代碼:
case?"flushRoom":
????DataTable?dtRoom?=?SqlHelper.getDataTable("select?*?from?RoomInfo");
????string?sJson?=?JsonConvert.SerializeObject(dtRoom);
????context.Response.Write(sJson);
????break;
使用sql語句獲取所有記錄,轉(zhuǎn)為json字符串以后返回到前臺。前臺AJAX請求代碼:
function?flushRoom()?{
????????$.ajax({
????????????type:?'get',
????????????url:?'RoomBookHandler.ashx',
????????????async:?true,
????????????data:?{
????????????????action:?'flushRoom',
????????????},
????????????success:?function?(result)?{
????????????????document.getElementById("roomInfo").innerHTML?=?creatRoomTable(result);
????????????????var?footerStr?=?'<footer?id="bookTimeSpan"?></footer?>';
????????????????document.getElementById("bookTimeSpan").innerHTML?=?footerStr;
????????????},
????????????error:?function?()?{
????????????????alert('獲取數(shù)據(jù)失敗!');
????????????}
????????});
????}
將AJAX返回的結(jié)果,使用creatRoomTable函數(shù)生成HTML表格,并設(shè)置到頁面的元素上面。creatRoomTable的代碼如下:
function?creatRoomTable(dataStr)?{
????????var?dataList?=?JSON.parse(dataStr);
????????var?trStr?=?'<table?class="primary"?id="roomInfo"?style="width:?100%"><tr>'?+
????????????'<th>?教室號</th>?<th>教室類型</th><th>容納人數(shù)</th>'?+
????????????'<th>?教室狀態(tài)</th>?<th>教室說明</th><th>是否預(yù)約</th></tr?>';
????????//循環(huán)遍歷出json對象中的每一個數(shù)據(jù)并顯示在對應(yīng)的td中
????????for?(i?=?0;?i?<?dataList.length;?i++)?{
????????????trStr?+=?'<tr>';
????????????trStr?+=?'<td>'?+?dataList[i].RoomNumber?+?'</td>';
????????????trStr?+=?'<td>'?+?dataList[i].RoomType?+?'</td>';
????????????trStr?+=?'<td>'?+?dataList[i].RoomPeople?+?'</td>';
????????????trStr?+=?'<td>'?+?dataList[i].RoomStatus?+?'</td>';
????????????trStr?+=?'<td>'?+?dataList[i].Remarks?+?'</td>';
????????????trStr?+=?'<td>';
????????????if?(dataList[i].RoomStatus.toString().trim()?===?"空閑")?{
????????????????trStr?+=?'<label><input?type="radio"?onClick="getRoomTimeSpan()"?name="selectRoom"?value="'?+?dataList[i].RoomNumber.toString()?+?'"?/><span class="checkable">預(yù)定</span></label>';
????????????}
????????????else?{
????????????????trStr?+=?"不可用";
????????????}
????????????trStr?+=?'</td>';
????????????trStr?+=?'</tr>';
????????}
????????trStr?+=?'</table>'
????????return?trStr;
????}
首先需要將字符串轉(zhuǎn)成json對象,隨后構(gòu)建表格的HTML代碼,遍歷json對象逐個生成表格元素。
(3)檢測預(yù)約時(shí)間段是否重復(fù)。數(shù)據(jù)庫中存儲的時(shí)間段是以字符串形式存儲的,其實(shí)判斷區(qū)間有無重復(fù)可以直接對字符串進(jìn)行比較。思路是先檢索該場地已預(yù)約的時(shí)間段。隨后一一進(jìn)行對比,如果全部通過,則不存在沖突。檢測的思路如下圖所示:

只需要判斷新的預(yù)約是否在已預(yù)約時(shí)間段的左側(cè)或者右側(cè)即可。具體的代碼如下:
for?(int?i?=?0;?i?<?dtBookInfo.Rows.Count;?i++)
{
????//大于已預(yù)約右邊,小于已預(yù)約左邊
????notOverlap?&=?(?(string.Compare(bookSt,?dtBookInfo.Rows[i][1].ToString().Trim(),?true)?>?0)?||
????????????????????(string.Compare(bookEt,?dtBookInfo.Rows[i][0].ToString().Trim(),?true)?<?0)?);
}
if?(!notOverlap)
{
????context.Response.Write("該時(shí)間段已經(jīng)有別人預(yù)約啦,請重新選擇!");
}
4、數(shù)據(jù)庫結(jié)構(gòu)
數(shù)據(jù)庫的設(shè)計(jì)中,使用了三個數(shù)據(jù)庫表用以系統(tǒng)數(shù)據(jù)的存儲。分別為:
- RoomInfo:記錄場地的信息,諸如場地類型,容納人數(shù),是否可用等。
- BookInfo:記錄預(yù)定的信息,例如預(yù)定的用戶,預(yù)定的場地,預(yù)定的時(shí)間段等。
- WebUser:記錄系統(tǒng)的用戶信息,如用戶名,密碼的MD5密文,手機(jī)號等。
RoomInfo表的結(jié)構(gòu)如下:
| 列名 | 數(shù)據(jù)類型 | 說明 | 實(shí)例 |
|---|---|---|---|
| RoomNumber | nchar(10) | 場地號 | 東九A101 |
| RoomType | nchar(10) | 場地類型 | 階梯教室 |
| RoomPeople | nchar(10) | 場地能容納的人數(shù) | 100 |
| RoomStatus | nchar(10) | 場地狀態(tài) | 空閑 |
| Remarks | nchar(10) | 備注 | 正在裝修 |
BookInfo表的結(jié)構(gòu)如下:
| 列名 | 數(shù)據(jù)類型 | 說明 | 實(shí)例 |
|---|---|---|---|
| ID | int | 預(yù)定號 | 1 |
| CustomerName | varchar(255) | 用戶名 | 張三 |
| MyRemark | nvarchar(50) | 備注 | 預(yù)定教室開班會 |
| BookDate | nchar(10) | 預(yù)定日期 | 2021-06-01 |
| BookSt | nchar(50) | 預(yù)定開始時(shí)間 | 09:30 |
| BookEt | nchar(50) | 預(yù)定結(jié)束時(shí)間 | 11:20 |
| BookDuration | float | 預(yù)定時(shí)長 | 2.5 |
| RoomNumber | nchar(10) | 預(yù)定的場地號 | 東九A101 |
WebUser表的結(jié)構(gòu)如下:
| 列名 | 數(shù)據(jù)類型 | 說明 | 實(shí)例 |
|---|---|---|---|
| username | varchar(255) | 用戶名 | 張三 |
| password | varchar(255) | 密碼MD5 | 202…… |
| telephone | varchar(50) | 電話 | 17798253366 |
數(shù)據(jù)庫的ER圖如下:

5、程序主要代碼及其說明
項(xiàng)目結(jié)構(gòu)如下,css、js等文件都放入了相應(yīng)的文件夾。前端分為登錄注冊頁面(login.aspx)和預(yù)定頁面(indextem.aspx)。用到了一些幫助類(SqlHelper.cs等):

5.1 前端
前端開發(fā)時(shí),JavaScript部分用到了json3和jQuery的庫,需要在aspx文件開頭中引入:
<script?src="https://cdn.bootcss.com/json3/3.3.2/json3.js"></script>
<script?src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
前端的界面使用了一個小型而時(shí)尚CSS庫Picnic CSS(https://picnicss.com/) 進(jìn)行美化,并且自定義了一些css的樣式,需要在頭部引入相關(guān)文件:
<link?rel="stylesheet"?href="css/templatemo-style.css"?/>
<link?rel="stylesheet"?href="css/picnic.css"?/>
登錄頁面

登錄頁面需要在成功以后做跳轉(zhuǎn),因此采用的是form提交的信息:
<div?id="section1"?class="section-w3ls">
????<input?type="radio"?name="sections"?id="option1"?checked>
????<label?for="option1"?class="icon-left-w3pvt"><span class="fa?fa-user-circle"?aria-hidden="true"></span>登錄</label>
????<article>
????????<form?runat="server">
????????????<h3?class="legend">賬號登錄</h3>
????????????<div?class="input">
????????????????<span class="fa?fa-user-o"?aria-hidden="true"></span>
????????????????<input?type="text"?placeholder="用戶名"?name="inputEmail"?required?/>
????????????</div>
????????????<div?class="input">
????????????????<span class="fa?fa-key"?aria-hidden="true"></span>
????????????????<input?type="password"?placeholder="密碼"?name="inputPassword"?required?/>
????????????</div>
????????????<asp:Button?ID="Button1"?class="btn?submit"?runat="server"?Text="登陸"?OnClick="Button1_Click"?/>
????????????<a?href="#"?class="bottom-text-w3ls">忘記密碼?</a>
????????</form>
????</article>
</div>
注冊用戶進(jìn)行用戶名的檢測:


預(yù)約頁面
預(yù)約頁面需要顯示的信息較多,如下圖所示:

可以在HTML頁面編寫元素,然后使用js動態(tài)生成,例如:
<table?class="primary"?id="roomInfo"?style="width:?100%"></table>
document.getElementById("roomInfo").innerHTML?=?creatRoomTable(result);
也可以直接在aspx文件中使用C#的腳本進(jìn)行生成:
<%
System.Data.DataSet?ds2?=?MyDBUtils.DBHelper.ExecuteQuery("select?BookInfo.ID,?BookInfo.RoomNumber,?RoomType,?RoomPeople,?MyRemark,BookSt,?"?+
????"BookEt,?BookDuration?from?BookInfo?join?RoomInfo?on?"?+
????"BookInfo.RoomNumber?=?RoomInfo.RoomNumber?where?"?+
????"BookDate?>?'"?+?DateTime.Now.ToString("yyyy-MM-dd")?+?"'?and?CustomerName='"?+?Request.Cookies["login_name"].Value?+?"'");
for?(int?i?=?0;?i?<?ds2.Tables[0].Rows.Count;?i++)
{
????Context.Response.Write("<tr>");
????for?(int?j?=?1;?j?<?8;?j++)
????{
????????Context.Response.Write("<td>");
????????Context.Response.Write(ds2.Tables[0].Rows[i][j].ToString());
????????Context.Response.Write("</td>");
????}
????Context.Response.Write("<td>");
????Context.Response.Write("<label><input?type='checkbox'?name='checkbokRoom'?value='"?+?ds2.Tables[0].Rows[i][0].ToString()+"-"+?ds2.Tables[0].Rows[i][1].ToString()?+?"'?/><span class='checkable'>退訂</span></label>");
????Context.Response.Write("</td>");
????Context.Response.Write("</tr>");
}
%>
表格中的radio單選按鈕,需要綁定單擊的事件,這部分代碼獲取選中的場地所預(yù)約的時(shí)間段,并將其顯示到表格下方的框框中,為AJAX局部更新,改變選中的場地時(shí)(單選按鈕的改變),也會在下面更新該場地的預(yù)約時(shí)間段:
function?getRoomTimeSpan()?{
??var?roomNumber?=?getSelectedRadioValue();
??//發(fā)送請求獲預(yù)約的時(shí)間段
??$.ajax({
??????type:?'get',
??????url:?'RoomBookHandler.ashx',
??????async:?true,
??????data:?{
??????????action:?'getBookTime',
??????????roomNo:?roomNumber
??????},
??????success:?function?(result)?{
??????????var?dataList?=?JSON.parse(result);
??????????var?footerStr?=?'<footer?id="bookTimeSpan"?>';
??????????for?(var?ind?in?dataList)?{
??????????????footerStr?+=?'<span class="label?warning"?style="font-size:?110%">';
??????????????footerStr?+=?dataList[ind].BookSt.toString().trim().substring(0,?5);
??????????????footerStr?+=?'?-?';
??????????????footerStr?+=?dataList[ind].BookEt.toString().trim().substring(0,?5);
??????????????footerStr?+=?'</span >';
??????????}
??????????footerStr?+=?'</footer?>';
??????????document.getElementById("bookTimeSpan").innerHTML?=?footerStr;
??????},
??????error:?function?()?{
??????????alert('獲取數(shù)據(jù)失敗!');
??????}
??});
}
時(shí)間段的選擇使用了一個時(shí)間選擇控件,效果如下:

預(yù)定時(shí),獲取用戶輸入的一系列數(shù)據(jù),然后使用AJAX發(fā)送到后臺進(jìn)行處理:
function?bookRoom()?{
????var?bookT?=?document.getElementById("timeArrange").value;
????if?(bookT?===?"")?{
????????alert("必須選擇要借用的時(shí)間范圍!");
????????return?false;
????}
????var?myR?=?document.getElementById("myRemarks").value;
????var?roomNumber?=?getSelectedRadioValue();
????if?(roomNumber?===?"")?{
????????alert("必須選擇要借用的教室!");
????????return?false;
????}
????//要發(fā)送的數(shù)據(jù),教室號,預(yù)定開始時(shí)間-結(jié)束時(shí)間,我的備注
????$.ajax({
????????type:?'post',
????????url:?'RoomBookHandler.ashx',
????????async:?true,
????????data:?{
????????????action:?'bookRoom',
????????????roomNo:?roomNumber,
????????????bookTime:?bookT,
????????????myRemark:?myR
????????},
????????success:?function?(result)?{
????????????alert(result);
????????????getRoomTimeSpan();
????????????updateBookedTable();
????????},
????????error:?function?()?{
????????????alert('請求失敗!');
????????}
????});
}
注意,如果用戶輸入不合法,比如未選中時(shí)間段,未選中教室,時(shí)間段沖突等都無法有效完成預(yù)定。
預(yù)約成功顯示預(yù)約的教室:

表格創(chuàng)建代碼與場地顯示的表格創(chuàng)建代碼類似,取消預(yù)約的需要將取消的預(yù)定號(預(yù)定號綁定到了checkbox的value中)發(fā)送到后臺,進(jìn)行記錄刪除:
function?cancelBook()?{
????var?checkList?=?[];
????var?timeSpanUpList?=?[];
????var?checkbokContext?=?document.getElementsByName("checkbokRoom");
????for?(i?=?0;?i?<?checkbokContext.length;?++i)?{
????????if?(checkbokContext[i].checked)?{
????????????var?dataStr?=?checkbokContext[i].value.split('-');
????????????checkList.push(dataStr[0]);
????????????timeSpanUpList.push(dataStr[1]);
????????}
????}
????if?(checkList.length?==?0)?{
????????alert("請選擇您需要取消預(yù)約的教室!");
????????return?false;
????}
????var?cancelListStr?=?checkList.join(',');?//轉(zhuǎn)成1,3,4這種形式,后臺再解析
????$.ajax({
????????type:?'post',
????????url:?'RoomBookHandler.ashx',
????????async:?true,
????????data:?{
????????????action:?'cancelBook',
????????????cancel:?cancelListStr
????????},
????????success:?function?(result)?{
????????????alert(result);
????????????//刷新本表
????????????updateBookedTable();
????????????//刷新foot
????????????if?(timeSpanUpList.indexOf(getSelectedRadioValue())?!=?-1)?{
????????????????getRoomTimeSpan();
????????????}
????????},
????????error:?function?()?{
????????????alert('連接失敗!');
????????}
????});
}
成功以后,更新該表格。但是需要注意的是,此外還做了一個小細(xì)節(jié),取消某一時(shí)間段以后,如果恰好在場地展示頁面選中的也是這個教室,那么下面的預(yù)約時(shí)間段也會同步更新,采用的同樣為AJAX技術(shù)。

success:?function?(result)?{
????alert(result);
????//刷新本表
????updateBookedTable();
????//刷新foot
????if?(timeSpanUpList.indexOf(getSelectedRadioValue())?!=?-1)?{
????????getRoomTimeSpan();
????}
},
歷史預(yù)約表格的生成,采用的是aspx中嵌入腳本的形式生成的:

<table?class="primary"??style="width:?100%">
????<tr>
????????<th>教室號</th>
????????<th>教室類型</th>
????????<th>容納人數(shù)</th>
????????<th>我的備注</th>
????????<th>日期</th>
????????<th>開始時(shí)間</th>
????????<th>結(jié)束時(shí)間</th>
????????<th>借用時(shí)長(小時(shí))</th>
????</tr>
????<tbody>
????<%
????????System.Data.DataSet?ds3?=?MyDBUtils.DBHelper.ExecuteQuery("select?BookInfo.RoomNumber,?RoomType,?RoomPeople,?MyRemark,BookDate,BookSt,?"?+
????????????"BookEt,?BookDuration?from?BookInfo?join?RoomInfo?on?"?+
????????????"BookInfo.RoomNumber?=?RoomInfo.RoomNumber?"?+
????????????"where?BookDate?<?'"?+?DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")?+"'?and?CustomerName='"?+?Request.Cookies["login_name"].Value?+?"'");
????????for?(int?i?=?0;?i?<?ds3.Tables[0].Rows.Count;?i++)
????????{
????????????Context.Response.Write("<tr>");
????????????for?(int?j?=?0;?j?<?8;?j++)
????????????{
????????????????Context.Response.Write("<td>");
????????????????Context.Response.Write(ds3.Tables[0].Rows[i][j].ToString());
????????????????Context.Response.Write("</td>");
????????????}
????????????Context.Response.Write("</tr>");
????????}
????%>
????</tbody>
</table>
檢索的時(shí)候,系統(tǒng)將自動從預(yù)訂表中檢索該用戶在今天之前的預(yù)約信息,并展示出來。
5.2 后臺
登錄頁面
后臺代碼進(jìn)行校驗(yàn),需要先將密碼轉(zhuǎn)成MD5密文,然后實(shí)行字符串匹配:
string?username?=?Request.Params["inputEmail"].ToString();
string?password?=?MD5Helper.ToMD5(Request.Params["inputPassword"].ToString());
if?(DBHelper.ExecuteQuery("select?*?from?WebUser?where?username='"?+?username?+?"'?and?password='"?+?password?+?"'").Tables[0].Rows.Count?>?0)
{
????//放一個Cookie來指示是哪名用戶登陸了
????HttpCookie?cookie?=?new?HttpCookie("login_name",?username);
????Response.Cookies.Add(cookie);
????Response.Redirect("indextem.aspx");
}
else
{
????Response.Write("<script?language=javascript>alert('用戶名或密碼錯誤');</script>");
}
注冊頁面的前端類似,后端代碼以數(shù)據(jù)庫插入為主,需要判斷用戶名是否重復(fù),如下:
var?name?=?Request["regName"];
if?(!string.IsNullOrEmpty(name))
{
????if?(DBHelper.ExecuteQuery("select?*?from?WebUser?where?username='"?+?name?+?"'").Tables[0].Rows.Count?>?0)
????{
????????//檢測該用戶名是否注冊
????????Response.Write("<script language=javascript>alert('注冊失敗,用戶名已被使用!');</script>");
????}
????else
????{
????????var?passwd?=?Request["regPassword"];
????????passwd?=?MD5Helper.ToMD5(passwd.ToString());
????????var?telephone?=?Request["regTelephone"];
????????var?sql?=?"INSERT?INTO?WebUser(username,password,telephone)?VALUES?('{0}','{1}','{2}')";
????????sql?=?string.Format(sql,?name,?passwd,?telephone);
????????if?(SqlHelper.ExecuteSql(sql)?>?0)
????????{
????????????var?str?=?"注冊成功,您的用戶名:"?+?name?+?"?,現(xiàn)在去登錄試試吧~";
????????????Response.Write("<script?language=javascript>alert('"?+?str?+?"');</script>");
????????}
????????else
????????{
????????????Response.Write("<script language=javascript>alert('注冊失敗,數(shù)據(jù)庫出錯!');</script>");
????????}
????}
}
預(yù)約頁面
預(yù)定的后臺處理代碼,后臺需要做預(yù)定沖突的檢測:
string[]?bookTime?=?context.Request["bookTime"].Split('-');
string?bookSt?=?bookTime[0].Trim();
string?bookEt?=?bookTime[1].Trim();
string?bookDate?=?DateTime.Now.AddDays(1).ToString("yyyy-MM-dd");
string?roomNumber?=?context.Request["roomNo"];
//預(yù)定時(shí)間區(qū)間判斷
var?bookInfoSql?=?"select?BookSt,?BookSt?from?BookInfo?where?"?+
????"BookDate='{0}'?And?RoomNumber='{1}'";
bookInfoSql?=?string.Format(bookInfoSql,?bookDate,?roomNumber);
DataTable?dtBookInfo?=?SqlHelper.getDataTable(bookInfoSql);
Boolean?notOverlap?=?true;
for?(int?i?=?0;?i?<?dtBookInfo.Rows.Count;?i++)
{
????//大于已預(yù)約右邊,小于已預(yù)約左邊
????notOverlap?&=?(?(string.Compare(bookSt,?dtBookInfo.Rows[i][1].ToString().Trim(),?true)?>?0)?||
????????????????????(string.Compare(bookEt,?dtBookInfo.Rows[i][0].ToString().Trim(),?true)?<?0)?);
}
if?(!notOverlap)
{
????context.Response.Write("該時(shí)間段已經(jīng)有別人預(yù)約啦,請重新選擇!");
}
else
{
????string?customerName?=?context.Request.Cookies["login_name"].Value;
????string?myRemark?=?context.Request["myRemark"];
????if?(string.IsNullOrEmpty(myRemark))
????{
????????myRemark?=?"無";
????}
????DateTime?dt1?=?DateTime.Parse(bookDate?+?"?"?+?bookSt);
????DateTime?dt2?=?DateTime.Parse(bookDate?+?"?"?+?bookEt);
????TimeSpan?ts?=?dt2.Subtract(dt1);
????double?bookDurationHours?=?Math.Round(ts.TotalHours,?2);
????DataTable?dtLastID?=?SqlHelper.getDataTable("select?top?1?ID?from?BookInfo?order?by?ID?DESC");
????string?insIdStr?=?dtLastID.Rows[0][0].ToString();
????int?insId?=?int.Parse(insIdStr)?+?1;
????//插入到數(shù)據(jù)庫中去
????var?bookSql?=?"INSERT?INTO?BookInfo(ID,?CustomerName,MyRemark,BookDate,BookSt,BookDuration,RoomNumber,BookEt)?"?+
????????"VALUES?({0},'{1}','{2}','{3}','{4}','{5}','{6}','{7}')";
????bookSql?=?string.Format(bookSql,?insId,?customerName,?myRemark,?bookDate,?bookSt,?bookDurationHours,
????????roomNumber,?bookEt);
????if?(SqlHelper.ExecuteSql(bookSql)?>?0)
????{
????????context.Response.Write("預(yù)定成功!");
????}
????else
????{
????????context.Response.Write("后臺數(shù)據(jù)插入出錯!");
????}
}
獲取預(yù)訂時(shí)間段后臺處理代碼:
string?roomNum?=?context.Request["roomNo"];
var?sqlBookSp?=?"select?BookSt,?BookEt?from?BookInfo?"?+
????"where?BookDate?=?'"?+?DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")?+?"'?and?RoomNumber?=?'{0}'?order?by?BookSt";
sqlBookSp?=?string.Format(sqlBookSp,?roomNum);
DataTable?dtTimeSp?=?SqlHelper.getDataTable(sqlBookSp);
string?sJson2?=?JsonConvert.SerializeObject(dtTimeSp);
context.Response.Write(sJson2);
break;
取消預(yù)約的代碼:
//刪除預(yù)訂的數(shù)據(jù)
string[]?delListStr?=?context.Request["cancel"].Split(',');
int?totalCancel?=?0;
foreach(var?delRoom?in?delListStr)
{
??var?delSql?=?"delete?from?BookInfo?where?ID?=?"?+?delRoom;
??if?(SqlHelper.ExecuteSql(delSql)?>?0)
??{
??????
??????totalCancel++;
??}
}
context.Response.Write("取消預(yù)訂完成,共取消?"?+?totalCancel.ToString()?+?"?間教室!");
6、運(yùn)行效果圖
登錄

注冊:


預(yù)訂(可以手動刷新教室信息):




時(shí)間沖突:

我的預(yù)訂:

取消預(yù)訂(支持多個一起取消):

取消以后自動刷新該場地下預(yù)約的時(shí)間段:

歷史預(yù)約 && 我的信息顯示:

7、小結(jié)
場地信息的發(fā)布應(yīng)該還需要一個管理端,即管理員可以編輯場地信息,然后進(jìn)行發(fā)布,但是由于個人能力有限,管理端沒有進(jìn)行設(shè)計(jì)。或者將系統(tǒng)與hub直接對接,檢索空閑的教室場地等進(jìn)行借用,也是可以的。不過需要學(xué)校方面的支持。
附錄
數(shù)據(jù)庫腳本【已附在程序目錄】運(yùn)行時(shí)可能需要修改文件存儲目錄,默認(rèn)為D盤下的DataBase文件夾:

利用VS2019及其以上版本打開項(xiàng)目文件.sln:

運(yùn)行l(wèi)ogin.aspx即可:

