ASP.NET Core 打造一個簡單的圖書館管理系統(八)學生借閱/預約/查詢書籍事務


前言:

本系列文章主要為我之前所學知識的一次微小的實踐,以我學校圖書館管理系統為雛形所作。

本系列文章主要參考資料:

微軟文檔:https://docs.microsoft.com/zh-cn/aspnet/core/getting-started/?view=aspnetcore-2.1&tabs=windows

《Pro ASP.NET MVC 5》、《鋒利的 jQuery》

 

當此系列文章寫完后會在一周內推出修正版。

 

此系列皆使用 VS2017+C# 作為開發環境。如果有什么問題或者意見歡迎在留言區進行留言。 

項目 github 地址:https://github.com/NanaseRuri/LibraryDemo

修改前地址:https://github.com/NanaseRuri/LibraryDemo/tree/SomeError

 

 

本章內容:自定義布局頁、自定義 EditorFor 模板、EF 多對多數據的更新

 

 

一、更新模型

折騰許久找不到同時更新具有依賴關系的兩個數據庫的方法,遂對原 Student 模型進行精簡,並添加一個 StudentInfo 模型用來保存相應的借書信息。同時原程序中原來非登錄界面對 Student 類型的引用改為對 StudentInfo 的引用。

同時由於書籍和學生存在多對多的關系——一本書可被多人預約,而一個人可以借閱多本書,因此在此更新模型使書籍與學生有多對多的關系。

此處僅展示模型的修改,控制器方面的修改請在查看源碼:

 

引入中間導航類:

這里新增的 AppointingDateTime 用於將借閱的書籍以及預約的書籍進行區分。

1     public class AppointmentOrLending
2     {
3         public Book Book { get; set; }
4         public string BookId { get; set; }
5         public StudentInfo Student { get; set; }
6         public string StudentId { get; set; }
7         public DateTime? AppointingDateTime { get; set; }
8     }

 

Student 模型改動

 1     public class Student : IdentityUser
 2     {
 3         /// <summary>
 4         /// 學號
 5         /// </summary>
 6         [ProtectedPersonalData]
 7         [RegularExpression("[UIA]\\d{9}")]
 8         public override string UserName { get; set; }
 9 
10         [StringLength(14, MinimumLength = 11)] public override string PhoneNumber { get; set; }
11 
12         public string Name { get; set; }
13         public Degrees Degree { get; set; }
14         public int MaxBooksNumber { get; set; }
15     }
View Code

 

添加新模型 StudentInfo:

 1     public class StudentInfo
 2     {
 3         [Key]
 4         public string UserName { get; set; }
 5 
 6         [Required]
 7         public string Name { get; set; }
 8 
 9         /// <summary>
10         /// 學位,用來限制借書數目
11         /// </summary>
12         [Required]
13         public Degrees Degree { get; set; }
14 
15         /// <summary>
16         /// 最大借書數目
17         /// </summary>
18         [Required]
19         public int MaxBooksNumber { get; set; }
20 
21         /// <summary>
22         /// 已借圖書
23         /// </summary>
24         public ICollection<AppointmentOrLending> KeepingBooks { get; set; }
25 
26         public string AppointingBookBarCode { get; set; }
27 
28         [StringLength(14, MinimumLength = 11)]
29         public string PhoneNumber { get; set; }
30 
31         /// <summary>
32         /// 罰款
33         /// </summary>
34         public decimal Fine { get; set; }               
35     }

 

在借書信息處添加學生信息和中間類的表,同時在此指定中間類的外鍵——指定其外鍵由學生學號和書籍條形碼共同組成,需要重寫 DbContext 父類的 OnModelCreating 方法使其覆蓋對應表格在 EF 的默認生成方式:

 1     public class LendingInfoDbContext:DbContext
 2     {
 3         public LendingInfoDbContext(DbContextOptions<LendingInfoDbContext> options) : base(options)
 4         {
 5         }
 6 
 7         public DbSet<Book> Books { get; set; }
 8         public DbSet<BookDetails> BooksDetail { get; set; }
 9         public DbSet<Bookshelf> Bookshelves { get; set; }
10         public DbSet<RecommendedBook> RecommendedBooks { get; set; }
11         public DbSet<StudentInfo> Students { get; set; }
12         public DbSet<AppointmentOrLending> AppointmentOrLendings { get; set; }
13 
14         protected override void OnModelCreating(ModelBuilder modelBuilder)
15         {
16             base.OnModelCreating(modelBuilder);
17             modelBuilder.Entity<AppointmentOrLending>()
18                 .HasKey(c => new { c.BookId, c.StudentId });
19         }
20     }

 

然后例行的更新數據庫:

cd librarydemo
add-migration AddStudents -c LibraryDemo.Data.LendingInfoDbContext
update-database -c LibraryDemo.Data.LendingInfoDbContext

 

在原 BookInitiator 中對 Students 表進行初始化:

 1             if (!context.Students.Any())
 2             {
 3                 IEnumerable<StudentInfo> initialStudents = new[]
 4                 {
 5                     new StudentInfo()
 6                     {
 7                         UserName = "U201600001",
 8                         Name = "Nanase",
 9                         PhoneNumber = "12345678910",
10                         Degree = Degrees.CollegeStudent,
11                         MaxBooksNumber = 10,
12                     },
13                     new StudentInfo()
14                     {
15                         UserName = "U201600002",
16                         Name = "Ruri",
17                         PhoneNumber = "12345678911",
18                         Degree = Degrees.DoctorateDegree,
19                         MaxBooksNumber = 15
20                     }
21                 };
22 
23                 IEnumerable<StudentInfo> initialAdmins = new[]
24                 {
25                     new StudentInfo()
26                     {
27                         UserName = "A000000000",
28                         Name="Admin0000",
29                         PhoneNumber = "12345678912",
30                         Degree = Degrees.CollegeStudent,
31                         MaxBooksNumber = 20
32                     },
33                     new StudentInfo()
34                     {
35                         UserName = "A000000001",
36                         Name = "Admin0001",
37                         PhoneNumber = "12345678910",
38                         Degree = Degrees.CollegeStudent,
39                         MaxBooksNumber = 20
40                     },
41                 };
42                 foreach (var student in initialStudents)
43                 {
44                     context.Students.Add(student);
45                     await context.SaveChangesAsync();
46                 }
47                 foreach (var admin in initialAdmins)
48                 {
49                     context.Students.Add(admin);
50                     await context.SaveChangesAsync();
51                 }
52             }

 

 

 

二、自定義布局頁 

在 ASP.NET 中,默認將 HTML 頁面的 body 元素一部分抽出來,該部分稱作 RenderBody ;然后將這部分放到一個布局即大體頁面框架中即可完成對同一系列的頁面進行精簡的布局實現。

默認布局頁為 _Layout.cshtml,可在視圖文件夾中根目錄或各個控制器視圖目錄的 _ViewStart.cshtml 修改默認布局頁,或者在每個 Razor 頁面的開頭中指定布局頁:

1 @{
2     ViewData["Title"] = "EditLendingInfo";
3     Layout = "_LendingLayout";
4 }

 

之前一直使用的是 VS 的默認布局頁,現在以該默認布局頁為基礎,添加自己所需要的信息:

 1 @using Microsoft.AspNetCore.Http.Extensions
 2 @using Microsoft.AspNetCore.Authorization
 3 @inject IAuthorizationService AuthorizationService
 4 <!DOCTYPE html>
 5 <html>
 6 <head>
 7     <meta charset="utf-8" />
 8     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 9     <title>@ViewData["Title"] - LibraryDemo</title>
10     <environment include="Development">
11         <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
12         <link rel="stylesheet" href="~/css/site.css" />
13     </environment>
14     <environment exclude="Development">
15         <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
16               asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
17               asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
18         <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
19     </environment>
20 </head>
21 <body>
22     <nav class="navbar navbar-inverse navbar-fixed-top">
23         <div class="container">
24             <div class="navbar-header">
25                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
26                     <span class="sr-only">Toggle navigation</span>
27                     <span class="icon-bar"></span>
28                     <span class="icon-bar"></span>
29                     <span class="icon-bar"></span>
30                 </button>
31                 <a asp-area="" asp-controller="BookInfo" asp-action="Index" class="navbar-brand">LibraryDemo</a>
32             </div>
33             <div class="navbar-collapse collapse">
34                 <ul class="nav navbar-nav">
35                     <li><a asp-area="" asp-controller="BookInfo" asp-action="Index">首頁</a></li>
36                     <li>
37                         @if (User.Identity.IsAuthenticated)
38                         {
39                             <a asp-controller="BookInfo" asp-action="PersonalInfo">@User.Identity.Name</a>
40                         }
41                         else
42                         {
43                             <a asp-area="" asp-controller="StudentAccount" asp-action="Login"
44                                asp-route-returnUrl="@(Context.Request.GetDisplayUrl())">登錄</a>
45                         }
46                 </li>
47                 <li><a asp-area="" asp-controller="BookInfo" asp-action="Recommend">推薦圖書</a></li>
48                     <li><a href="mailto:Nanase@cnblogs.com">聯系我們</a></li>
49                     @if (User.Identity.IsAuthenticated)
50                     {
51                         <li>
52                             <a asp-action="Logout" asp-controller="StudentAccount" asp-route-returnUrl="@(Context.Request.GetDisplayUrl())">注銷</a>                            
53                         </li>
54                     }
55             </ul>
56         </div>
57     </div>
58 </nav>
59 <partial name="_CookieConsentPartial" />
60 <div class="container body-content">
61     @if (TempData["message"] != null)
62     {
63         <br/>
64         <p class="text-success">@TempData["message"]</p>
65     }   
66     @RenderBody()
67     <hr/>
68 </div>
69 
70 <div class="container" style="margin-top: 20px;">
71     <footer>
72         <p>&copy; 2018 - LibraryDemo</p>
73     </footer>
74 </div>
75 <environment include="Development">
76     <script src="~/lib/jquery/dist/jquery.js"></script>
77     <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
78     <script src="~/js/site.js" asp-append-version="true"></script>
79 </environment>
80 <environment exclude="Development">
81     <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
82             asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
83             asp-fallback-test="window.jQuery"
84             crossorigin="anonymous"
85             integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"></script>
86     <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
87             asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
88             asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
89             crossorigin="anonymous"
90             integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"></script>
91     <script src="~/js/site.min.js" asp-append-version="true"></script>
92 </environment>
93 @RenderSection("Scripts", required: false)
94 </body>
95 </html>
View Code

 

現在大體框架:

 

除了默認的 RenderBody 外,可以指定特定的部分放在頁面的不同地方,在布局頁中使用@RenderSection("SectionName"):

1 @RenderSection("SectionName")

 

且在視圖頁中使用指定特定的節@section SectionName{  };

1 @section SectionName{ 
2 
3  };

則該視圖頁中的 SectionName 部分會被提取出來放到布局頁對應的位置。

 

 

 

三、管理員編輯借閱信息

動作方法:

在此對數據庫的表格使用 Include 方法使 EF 應用其導航屬性以獲得 KeepingBooks 列表,否則使用 Student 對象 KeepingBooks 屬性只會返回空。

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult EditLendingInfo(string barcode)
 3         {
 4             if (barcode == null)
 5             {
 6                 return RedirectToAction("BookDetails");
 7             }
 8             Book book = _lendingInfoDbContext.Books.FirstOrDefault(b => b.BarCode == barcode);
 9             return View(book);
10         }
11 
12         [HttpPost]
13         [Authorize(Roles = "Admin")]
14         [ValidateAntiForgeryToken]
15         public async Task<IActionResult> EditLendingInfo([Bind("BarCode,ISBN,BorrowTime,KeeperId,AppointedLatestTime,State")]Book book)
16         {
17             if (ModelState.IsValid)
18             {
19                 if (book.BorrowTime > DateTime.Now)
20                 {
21                     ModelState.AddModelError("", "請檢查外借時間");
22                     return View(book);
23                 }
24                 if (book.AppointedLatestTime.HasValue)
25                 {
26                     if (book.AppointedLatestTime < DateTime.Now)
27                     {
28                         ModelState.AddModelError("", "請檢查預約時間");
29                         return View(book);
30                     }
31 
32                     if (book.KeeperId == null)
33                     {
34                         ModelState.AddModelError("", "不存在該學生");
35                         return View(book);
36                     }
37                 }
38 
39                 StudentInfo student = await _lendingInfoDbContext.Students.Include(s => s.KeepingBooks).FirstOrDefaultAsync(s => s.UserName == book.KeeperId);
40 
41                 Book addedBook = _lendingInfoDbContext.Books
42                     .Include(b => b.Keeper).ThenInclude(k => k.KeepingBooks)
43                     .FirstOrDefault(b => b.BarCode == book.BarCode);
44                 if (addedBook == null)
45                 {
46                     return RedirectToAction("Books", new { isbn = book.ISBN });
47                 }
48 
49                 StudentInfo preStudent = addedBook.Keeper;
50                 AppointmentOrLending targetLending =
51                     preStudent?.KeepingBooks.FirstOrDefault(b => b.BookId == addedBook.BarCode);
52 
53                 addedBook.AppointedLatestTime = book.AppointedLatestTime;
54                 addedBook.State = book.State;
55                 addedBook.BorrowTime = book.BorrowTime;
56                 addedBook.MatureTime = null;
57 
58                 preStudent?.KeepingBooks.Remove(targetLending);
59 
60                 if (addedBook.BorrowTime.HasValue)
61                 {
62                     if (book.KeeperId == null)
63                     {
64                         ModelState.AddModelError("", "請檢查借閱者");
65                         return View(book);
66                     }
67 
68                     if (student == null)
69                     {
70                         ModelState.AddModelError("", "不存在該學生");
71                         return View(book);
72                     }
73                     if (student != null)
74                     {
75                         if (student.KeepingBooks.Count >= student.MaxBooksNumber)
76                         {
77                             TempData["message"] = "該學生借書已超過上限";
78                         }
79 
80                         addedBook.State = BookState.Borrowed;
81                         student.KeepingBooks.Add(new AppointmentOrLending()
82                         {
83                             BookId = addedBook.BarCode,
84                             StudentId = student.UserName
85                         });
86                         addedBook.Keeper = student;
87 
88                     }
89                     addedBook.MatureTime = addedBook.BorrowTime + TimeSpan.FromDays(28);
90                 }
91 
92 
93                 TempData["message"] = "保存成功";
94                 await _lendingInfoDbContext.SaveChangesAsync();
95                 return RedirectToAction("Books", new { isbn = book.ISBN });
96             }
97             return View(book);
98         }

 

將 BookState 枚舉提取成分部視圖 _BookStatePartial:

 1 @using LibraryDemo.Models.DomainModels
 2 @model Book
 3     <div class="form-group">
 4     @Html.LabelFor(b => b.State)
 5         @Html.DropDownListFor(b => b.State, Enum.GetValues(typeof(BookState)).Cast<Enum>().Select(state =>
 6         {
 7             string enumVal = Enum.GetName(typeof(BookState), state);
 8             string displayVal;
 9             switch (enumVal)
10             {
11                 case "Normal":
12                     displayVal = "可借閱";
13                     break;
14                 case "Readonly":
15                     displayVal = "館內閱覽";
16                     break;
17                 case "Borrowed":
18                     displayVal = "已借出";
19                     break;
20                 case "ReBorrowed":
21                     displayVal = "被續借";
22                     break;
23                 case "Appointed":
24                     displayVal = "被預約";
25                     break;
26                 default:
27                     displayVal = "";
28                     break;
29             }
30             return new SelectListItem()
31             {
32                 Text = displayVal,
33                 Value = enumVal,
34                 Selected = Model.State.ToString() == enumVal
35             };
36         }))
37     </div>

 

Html.DisplayFor 方法是 ASP.NET 內置對各種屬性進行展示的方法,可以在項目的 Views 文件夾中的 Shared 文件夾創建對應類型的 Editor 模板供其使用:

在此創建一個 DateTime.cshtml,於是我們使用 Html.DisplayFor 用於展示 DateTime 數據時只會顯示年份/月份/天數:

1 @model DateTime?
2 
3 @Model?.ToString("yyyy/M/dd")

 

視圖中使用 partial TagHelper 指定其 name 為 _BookStatePartial 以應用分部視圖:

 1 @using LibraryDemo.Models.DomainModels
 2 @model LibraryDemo.Models.DomainModels.Book
 3 @{
 4     ViewData["Title"] = "EditLendingInfo";
 5     Layout="_LendingLayout";
 6 }
 7 
 8 <h2>@Model.BarCode</h2>
 9 <h3>@Model.Name</h3>
10 <br/>
11 
12 <script>
13     window.onload = function() {
14         $("input").addClass("form-control");
15     }
16     window.onbeforeunload = function (event) {
17         return "您的數據未保存,確定退出?";
18     }
19     function removeOnbeforeunload() {
20         window.onbeforeunload = "";
21     }
22 </script>
23 
24 @Html.ValidationSummary(false,"",new{@class="text-danger"})
25 
26 <form asp-action="EditLendingInfo" method="post">
27     @Html.HiddenFor(b => b.BarCode)
28     @Html.HiddenFor(b => b.ISBN)
29     <div class="form-group">
30         @Html.LabelFor(b => b.KeeperId)
31         @Html.EditorFor(b => b.KeeperId)
32     </div>
33     <div class="form-group">
34         @Html.LabelFor(b => b.BorrowTime)
35         @Html.EditorFor(b => b.BorrowTime)
36     </div>
37     <div class="form-group">
38         @Html.LabelFor(b => b.AppointedLatestTime)
39         @Html.EditorFor(b => b.AppointedLatestTime)
40     </div>
41     <partial model="@Model" name="_BookStatePartial"/>
42     <input type="submit" onclick="return removeOnbeforeunload()" class="btn-primary"/>
43 </form>

 

 

結果:

 

 

 

 

 

 

 

 

四、查看個人信息

這里通過 User.Identity.Name 獲取當前登錄人的信息以選定特定的學生:

 1         [Authorize]
 2         public async Task<IActionResult> PersonalInfo()
 3         {
 4             StudentInfo student = await _lendingInfoDbContext.Students.Include(s => s.KeepingBooks).ThenInclude(k => k.Book)
 5                 .FirstOrDefaultAsync(s => s.UserName == User.Identity.Name);
 6             decimal fine = 0;            
 7             foreach (var book in student.KeepingBooks.Where(b => b.Book.MatureTime < DateTime.Now && !b.AppointingDateTime.HasValue))
 8             {
 9                 fine += (DateTime.Now - book.Book.MatureTime.Value).Days * (decimal)0.2;
10                 book.Book.State = book.Book.State == BookState.Appointed ? BookState.Appointed : BookState.Expired;
11             }
12 
13             student.Fine = fine;
14             PersonalInfoViewModel model = new PersonalInfoViewModel()
15             {
16                 Student = student,
17                 BookingBook = _lendingInfoDbContext.Books.FirstOrDefault(b => b.BarCode == student.AppointingBookBarCode)
18             };
19             return View(model);
20         }

 

 

視圖:

 1 @model LibraryDemo.Models.PersonalInfoViewModel
 2 @{
 3     ViewData["Title"] = "PersonalInfo";
 4     Layout = "_LendingLayout";
 5     double fine = 0;
 6 }
 7 <link rel="stylesheet" href="~/css/BookInfo.css" />
 8 
 9 <h2>@Model.Student.Name</h2>
10 <br />
11 @if (Model.Student.KeepingBooks.Any(b => b.Book.MatureTime < DateTime.Now))
12 {
13     <p>
14         罰款:@foreach (var matureBook in Model.Student.KeepingBooks.Where(b => !b.AppointingDateTime.HasValue&&b.Book.MatureTime < DateTime.Now))
15         {
16             fine += (DateTime.Now - matureBook.Book.MatureTime).Value.TotalDays * 0.2;
17         }
18         @fine
19     </p>
20 }
21 <form asp-action="ReBorrow" method="post">
22     <table>
23         <tr>
24             <th>續借</th>
25             <th>書名</th>
26             <th>條形碼</th>
27             <th>狀態</th>
28             <th>到期時間</th>
29             <th>索書號</th>
30         </tr>
31         @if (!Model.Student.KeepingBooks.Any())
32         {
33             <tr>
34                 <td colspan="6" style="text-align: center">未借閱書本</td>
35             </tr>
36         }
37         else
38         {
39             foreach (var keepingBook in Model.Student.KeepingBooks.Where(b=>!b.AppointingDateTime.HasValue))
40             {                
41                 <tr>
42                     <td><input type="checkbox" value="@keepingBook.Book.BarCode" name="barcodes"/></td>
43                     <td>@keepingBook.Book.Name</td>
44                     <td>@keepingBook.Book.BarCode</td>
45                     <td>@Html.DisplayFor(b=>keepingBook.Book.State)</td>
46                     <td>@keepingBook.Book.MatureTime?.ToString("yyyy/MM/dd")</td>
47                     <td>@keepingBook.Book.FetchBookNumber</td>
48                 </tr>
49             }
50         }
51     </table>    
52     <br/>
53     <input type="submit" class="btn-primary btn" value="續借"/>
54 </form>
55 
56 <br />
57 @if (Model.BookingBook != null)
58 {
59     <form asp-action="CancelAppointing">        
60         <table>
61             <tr>
62                 <th>書名</th>
63                 <th>條形碼</th>
64                 <th>狀態</th>
65                 <th>預約時間</th>
66                 <th>索書號</th>
67             </tr>
68             <book-info book="@Model.BookingBook" is-booking-book="true"></book-info>
69         </table>
70         <br />
71         <input type="hidden" name="barcode" value="@Model.BookingBook.BarCode"/>
72         <input type="submit" value="取消預約" class="btn btn-danger"/>
73     </form>
74 }

 

 

 

 

 

 

五、借閱書籍

由於暫時未有獲取二維碼的接口,僅通過直接訪問 Lending 模擬借閱:

 1         [Authorize]
 2         public async Task<IActionResult> Lending(string barcode) 3  { 4 Book targetBook=await _lendingInfoDbContext.Books.Include(b=>b.Appointments).FirstOrDefaultAsync(b => b.BarCode == barcode); 5 if (targetBook==null) 6  { 7 TempData["message"] = "請重新掃描書籍"; 8 return RedirectToAction("PersonalInfo"); 9  } 10 11 if (targetBook.Appointments.Any(a=>a.AppointingDateTime.HasValue)) 12  { 13 TempData["message"] = "此書已被預約"; 14 return RedirectToAction("PersonalInfo"); 15  } 16 17 if (targetBook.State==BookState.Readonly) 18  { 19 TempData["message"] = "此書不供外借"; 20 return RedirectToAction("PersonalInfo"); 21  } 22 23 targetBook.State = BookState.Borrowed; 24 targetBook.BorrowTime = DateTime.Now.Date; 25 targetBook.MatureTime = DateTime.Now.Date+TimeSpan.FromDays(28); 26 StudentInfo student = 27 await _lendingInfoDbContext.Students.Include(s=>s.KeepingBooks).FirstOrDefaultAsync(s => s.UserName == User.Identity.Name); 28 student.KeepingBooks.Add(new AppointmentOrLending() 29  { 30 BookId = targetBook.BarCode, 31 StudentId = student.UserName 32  }); 33 await _lendingInfoDbContext.SaveChangesAsync(); 34 TempData["message"] = "借書成功"; 35 return RedirectToAction("PersonalInfo"); 36 }

 

 

 

 

 

 

 六、續借書籍

動作方法:

 1         [Authorize]
 2         [HttpPost]
 3         public async Task<IActionResult> ReBorrow(IEnumerable<string> barcodes)
 4         {
 5             StringBuilder borrowSuccess = new StringBuilder();
 6             StringBuilder borrowFail = new StringBuilder();
 7             borrowSuccess.Append("成功續借書籍:");
 8             borrowFail.Append("續借失敗書籍:");
 9             foreach (var barcode in barcodes)
10             {   
11                 Book reBorrowBook = _lendingInfoDbContext.Books.FirstOrDefault(b => b.BarCode == barcode);
12                 if (reBorrowBook != null)
13                 {
14                     if (reBorrowBook.State == BookState.Borrowed && DateTime.Now-reBorrowBook.MatureTime?.Date<=TimeSpan.FromDays(3))
15                     {
16                         reBorrowBook.State = BookState.ReBorrowed;
17                         reBorrowBook.BorrowTime = DateTime.Now.Date;
18                         reBorrowBook.MatureTime = DateTime.Now.Date+TimeSpan.FromDays(28);
19                         borrowSuccess.Append($"《{reBorrowBook.Name}》、");
20                     }
21                     else
22                     {
23                         borrowFail.Append($"《{reBorrowBook.Name}》、");
24                     }
25                 }
26             }
27             borrowSuccess.AppendLine(borrowFail.ToString());
28             await _lendingInfoDbContext.SaveChangesAsync();
29             TempData["message"] = borrowSuccess.ToString();
30             return RedirectToAction("PersonalInfo");
31         }

 

 

 

 

 

 

七、查詢書籍

修改之前的 Search 方法使其通過當前用戶的身份返回不同頁面,以及在 _LendingInfoLayout 中添加搜索框部分:

19 行通過短路使未授權用戶不用登錄。

 1         public async Task<IActionResult> Search(string keyWord, string value)
 2         {
 3             BookDetails bookDetails = new BookDetails();
 4             switch (keyWord)
 5             {
 6                 case "Name":
 7                     bookDetails = await _lendingInfoDbContext.BooksDetail.AsNoTracking().FirstOrDefaultAsync(b => b.Name == value);
 8                     break;
 9                 case "ISBN":
10                     bookDetails = await _lendingInfoDbContext.BooksDetail.AsNoTracking().FirstOrDefaultAsync(b => b.ISBN == value);
11                     break;
12                 case "FetchBookNumber":
13                     bookDetails = await _lendingInfoDbContext.BooksDetail.AsNoTracking().FirstOrDefaultAsync(b => b.FetchBookNumber == value);
14                     break;
15             }
16 
17             if (bookDetails != null)
18             {
19                 if (User.Identity.IsAuthenticated&& User.IsInRole("Admin"))
20                 {
21                     return RedirectToAction("EditBookDetails", new { isbn = bookDetails.ISBN });
22                 }
23                 else
24                 {
25                     return RedirectToAction("Detail", new {isbn = bookDetails.ISBN});
26                 }                
27             }
28 
29             TempData["message"] = "找不到該書籍";
30             return RedirectToAction("BookDetails");
31         }

 

視圖頁:

  1 @using Microsoft.AspNetCore.Http.Extensions
  2 @using Microsoft.AspNetCore.Authorization
  3 @inject IAuthorizationService AuthorizationService
  4 <!DOCTYPE html>
  5 <html>
  6 <head>
  7     <meta charset="utf-8" />
  8     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  9     <title>@ViewData["Title"] - LibraryDemo</title>
 10     <environment include="Development">
 11         <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
 12         <link rel="stylesheet" href="~/css/site.css" />
 13     </environment>
 14     <environment exclude="Development">
 15         <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
 16               asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
 17               asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
 18         <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
 19     </environment>
 20 </head>
 21 <body>
 22     <nav class="navbar navbar-inverse navbar-fixed-top">
 23         <div class="container">
 24             <div class="navbar-header">
 25                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
 26                     <span class="sr-only">Toggle navigation</span>
 27                     <span class="icon-bar"></span>
 28                     <span class="icon-bar"></span>
 29                     <span class="icon-bar"></span>
 30                 </button>
 31                 <a asp-area="" asp-controller="BookInfo" asp-action="Index" class="navbar-brand">LibraryDemo</a>
 32             </div>
 33             <div class="navbar-collapse collapse">
 34                 <ul class="nav navbar-nav">
 35                     <li><a asp-area="" asp-controller="BookInfo" asp-action="Index">首頁</a></li>
 36                     <li>
 37                         @if (User.Identity.IsAuthenticated)
 38                         {
 39                             <a asp-controller="BookInfo" asp-action="PersonalInfo">@User.Identity.Name</a>
 40                         }
 41                         else
 42                         {
 43                             <a asp-area="" asp-controller="StudentAccount" asp-action="Login"
 44                                asp-route-returnUrl="@(Context.Request.GetDisplayUrl())">登錄</a>
 45                         }
 46                     </li>
 47                     <li><a asp-area="" asp-controller="BookInfo" asp-action="Recommend">推薦圖書</a></li>
 48                     <li><a href="mailto:Nanase@cnblogs.com">聯系我們</a></li>
 49                     @if (User.Identity.IsAuthenticated)
 50                     {
 51                         <li>
 52                             <a asp-action="Logout" asp-controller="StudentAccount" asp-route-returnUrl="@(Context.Request.GetDisplayUrl())">注銷</a>
 53                         </li>
 54                     }
 55                 </ul>
 56             </div>
 57         </div>
 58     </nav>
 59     @if (TempData["message"] != null)
 60     {
 61         <br />
 62         <p class="text-success">@TempData["message"]</p>
 63     }
 64     <br />
 65     <div align="center">
 66         <form action="@Url.Action("Search","BookInfo")">
 67             @Html.DropDownList("keyword",new List<SelectListItem>()
 68             {
 69                 new SelectListItem("書名","Name"),
 70                 new SelectListItem("ISBN","ISBN"),
 71                 new SelectListItem("索書號","FetchBookNumber"),
 72             })
 73             <input type="text" name="value" />
 74             <button type="submit"><span class="glyphicon glyphicon-search"></span></button>
 75         </form>
 76     </div>
 77     <partial name="_CookieConsentPartial" />
 78     <div class="container body-content">
 79 
 80         @RenderBody()
 81         <hr />
 82     </div>
 83 
 84     <div class="container" style="margin-top: 20px;">
 85         <footer>
 86             <p>&copy; 2018 - LibraryDemo</p>
 87         </footer>
 88     </div>
 89     <environment include="Development">
 90         <script src="~/lib/jquery/dist/jquery.js"></script>
 91         <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
 92         <script src="~/js/site.js" asp-append-version="true"></script>
 93     </environment>
 94     <environment exclude="Development">
 95         <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
 96                 asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
 97                 asp-fallback-test="window.jQuery"
 98                 crossorigin="anonymous"
 99                 integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"></script>
100         <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
101                 asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
102                 asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
103                 crossorigin="anonymous"
104                 integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"></script>
105         <script src="~/js/site.min.js" asp-append-version="true"></script>
106     </environment>
107     @RenderSection("Scripts", required: false)
108 </body>
109 </html>

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM