上一篇完成了後臺分類模塊的全部功能,本篇繼續將標籤模塊和友情連接模塊的增刪改查完成。html
實現方式和以前的分類管理是同樣的,在Admin文件夾下面添加Tags.razor
組件,設置路由@page "/admin/tags"
。git
一樣的內容也須要放在AdminLayout
組件下面,添加幾個參數:彈窗狀態bool Open
、新增或更新時標籤字段string tagName, displayName
、更新時的標籤Idint id
、API返回的標籤列表接收參數ServiceResult<IEnumerable<QueryTagForAdminDto>> tags
。github
/// <summary> /// 默認隱藏Box /// </summary> private bool Open { get; set; } = false; /// <summary> /// 新增或者更新時候的標籤字段值 /// </summary> private string tagName, displayName; /// <summary> /// 更新標籤的Id值 /// </summary> private int id; /// <summary> /// API返回的標籤列表數據 /// </summary> private ServiceResult<IEnumerable<QueryTagForAdminDto>> tags;
//QueryTagForAdminDto.cs namespace Meowv.Blog.BlazorApp.Response.Blog { public class QueryTagForAdminDto : QueryTagDto { /// <summary> /// 主鍵 /// </summary> public int Id { get; set; } } }
在初始化方法OnInitializedAsync()
中獲取數據。緩存
/// <summary> /// 初始化 /// </summary> /// <returns></returns> protected override async Task OnInitializedAsync() { var token = await Common.GetStorageAsync("token"); Http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"); tags = await FetchData(); } /// <summary> /// 獲取數據 /// </summary> /// <returns></returns> private async Task<ServiceResult<IEnumerable<QueryTagForAdminDto>>> FetchData() { return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryTagForAdminDto>>>("/blog/admin/tags"); }
注意須要設置請求頭,進行受權訪問,而後頁面上綁定數據。app
<AdminLayout> @if (tags == null) { <Loading /> } else { <div class="post-wrap tags"> <h2 class="post-title">- Tags -</h2> @if (tags.Success && tags.Result.Any()) { <div class="categories-card"> @foreach (var item in tags.Result) { <div class="card-item"> <div class="categories"> <NavLink title="❌刪除" @onclick="@(async () => await DeleteAsync(item.Id))">❌</NavLink> <NavLink title="📝編輯" @onclick="@(() => ShowBox(item))">📝</NavLink> <NavLink target="_blank" href="@($"/tag/{item.DisplayName}")"> <h3>@item.TagName</h3> <small>(@item.Count)</small> </NavLink> </div> </div> } <div class="card-item"> <div class="categories"> <NavLink><h3 @onclick="@(() => ShowBox())">📘~~~ 新增標籤 ~~~📘</h3></NavLink> </div> </div> </div> } else { <ErrorTip /> } </div> <Box OnClickCallback="@SubmitAsync" Open="@Open"> <div class="box-item"> <b>DisplayName:</b><input type="text" @bind="@displayName" @bind:event="oninput" /> </div> <div class="box-item"> <b>TagName:</b><input type="text" @bind="@tagName" @bind:event="oninput" /> </div> </Box> } </AdminLayout>
tags
沒獲取到數據的時候顯示<Loading />
組件內容,循環遍歷數據進行綁定,刪除按鈕綁定點擊事件調用DeleteAsync()
方法。新增和編輯按鈕點擊事件調用ShowBox()
方法顯示彈窗。新增的時候不須要傳遞參數,編輯的時候須要將當前item即QueryTagForAdminDto
傳遞進去。async
<Box>
組件中綁定了標籤的兩個參數,是否打開參數Opne
和確認按鈕回調事件方法SubmitAsync()
。ide
刪除標籤的方法DeleteAsync(...)
以下:post
// 彈窗確認 bool confirmed = await Common.InvokeAsync<bool>("confirm", "\n💥💢真的要幹掉這個該死的標籤嗎💢💥"); if (confirmed) { var response = await Http.DeleteAsync($"/blog/tag?id={id}"); var result = await response.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { tags = await FetchData(); } }
刪除以前進行二次確認,避免誤傷,刪除成功從新加載一遍數據。spa
彈窗的方法ShowBox(...)
以下:日誌
/// <summary> /// 顯示box,綁定字段 /// </summary> /// <param name="dto"></param> private void ShowBox(QueryTagForAdminDto dto = null) { Open = true; id = 0; // 新增 if (dto == null) { displayName = null; tagName = null; } else // 更新 { id = dto.Id; displayName = dto.DisplayName; tagName = dto.TagName; } }
最後在彈窗中確認按鈕的回調事件方法SubmitAsync()
以下:
/// <summary> /// 確認按鈕點擊事件 /// </summary> /// <returns></returns> private async Task SubmitAsync() { var input = new EditTagInput() { DisplayName = displayName.Trim(), TagName = tagName.Trim() }; if (string.IsNullOrEmpty(input.DisplayName) || string.IsNullOrEmpty(input.TagName)) { return; } var responseMessage = new HttpResponseMessage(); if (id > 0) responseMessage = await Http.PutAsJsonAsync($"/blog/tag?id={id}", input); else responseMessage = await Http.PostAsJsonAsync("/blog/tag", input); var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { tags = await FetchData(); Open = false; } }
輸入參數EditTagInput
。
namespace Meowv.Blog.BlazorApp.Response.Blog { public class EditTagInput : TagDto { } }
最終執行新增或者更新數據都在點擊事件中進行,將變量的值賦值給EditTagInput
,根據id判斷走新增仍是更新,成功後從新加載數據,關掉彈窗。
標籤管理頁面所有代碼以下:
@page "/admin/categories" <AdminLayout> @if (categories == null) { <Loading /> } else { <div class="post-wrap categories"> <h2 class="post-title">- Categories -</h2> @if (categories.Success && categories.Result.Any()) { <div class="categories-card"> @foreach (var item in categories.Result) { <div class="card-item"> <div class="categories"> <NavLink title="❌刪除" @onclick="@(async () => await DeleteAsync(item.Id))">❌</NavLink> <NavLink title="📝編輯" @onclick="@(() => ShowBox(item))">📝</NavLink> <NavLink target="_blank" href="@($"/category/{item.DisplayName}")"> <h3>@item.CategoryName</h3> <small>(@item.Count)</small> </NavLink> </div> </div> } <div class="card-item"> <div class="categories"> <NavLink><h3 @onclick="@(() => ShowBox())">📕~~~ 新增分類 ~~~📕</h3></NavLink> </div> </div> </div> } else { <ErrorTip /> } </div> <Box OnClickCallback="@SubmitAsync" Open="@Open"> <div class="box-item"> <b>DisplayName:</b><input type="text" @bind="@displayName" @bind:event="oninput" /> </div> <div class="box-item"> <b>CategoryName:</b><input type="text" @bind="@categoryName" @bind:event="oninput" /> </div> </Box> } </AdminLayout> @code { /// <summary> /// 默認隱藏Box /// </summary> private bool Open { get; set; } = false; /// <summary> /// 新增或者更新時候的分類字段值 /// </summary> private string categoryName, displayName; /// <summary> /// 更新分類的Id值 /// </summary> private int id; /// <summary> /// API返回的分類列表數據 /// </summary> private ServiceResult<IEnumerable<QueryCategoryForAdminDto>> categories; /// <summary> /// 初始化 /// </summary> /// <returns></returns> protected override async Task OnInitializedAsync() { var token = await Common.GetStorageAsync("token"); Http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"); categories = await FetchData(); } /// <summary> /// 獲取數據 /// </summary> /// <returns></returns> private async Task<ServiceResult<IEnumerable<QueryCategoryForAdminDto>>> FetchData() { return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryCategoryForAdminDto>>>("/blog/admin/categories"); } /// <summary> /// 刪除分類 /// </summary> /// <param name="id"></param> /// <returns></returns> private async Task DeleteAsync(int id) { Open = false; // 彈窗確認 bool confirmed = await Common.InvokeAsync<bool>("confirm", "\n💥💢真的要幹掉這個該死的分類嗎💢💥"); if (confirmed) { var response = await Http.DeleteAsync($"/blog/category?id={id}"); var result = await response.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { categories = await FetchData(); } } } /// <summary> /// 顯示box,綁定字段 /// </summary> /// <param name="dto"></param> private void ShowBox(QueryCategoryForAdminDto dto = null) { Open = true; id = 0; // 新增 if (dto == null) { displayName = null; categoryName = null; } else // 更新 { id = dto.Id; displayName = dto.DisplayName; categoryName = dto.CategoryName; } } /// <summary> /// 確認按鈕點擊事件 /// </summary> /// <returns></returns> private async Task SubmitAsync() { var input = new EditCategoryInput() { DisplayName = displayName.Trim(), CategoryName = categoryName.Trim() }; if (string.IsNullOrEmpty(input.DisplayName) || string.IsNullOrEmpty(input.CategoryName)) { return; } var responseMessage = new HttpResponseMessage(); if (id > 0) responseMessage = await Http.PutAsJsonAsync($"/blog/category?id={id}", input); else responseMessage = await Http.PostAsJsonAsync("/blog/category", input); var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { categories = await FetchData(); Open = false; } } }
實現方式都是同樣的,這個就很少說了,直接上代碼。
先將API返回的接收參數和新增編輯的輸入參數添加一下。
//QueryFriendLinkForAdminDto.cs namespace Meowv.Blog.BlazorApp.Response.Blog { public class QueryFriendLinkForAdminDto : FriendLinkDto { /// <summary> /// 主鍵 /// </summary> public int Id { get; set; } } } //EditFriendLinkInput.cs namespace Meowv.Blog.BlazorApp.Response.Blog { public class EditFriendLinkInput : FriendLinkDto { } }
@page "/admin/friendlinks" <AdminLayout> @if (friendlinks == null) { <Loading /> } else { <div class="post-wrap categories"> <h2 class="post-title">- FriendLinks -</h2> @if (friendlinks.Success && friendlinks.Result.Any()) { <div class="categories-card"> @foreach (var item in friendlinks.Result) { <div class="card-item"> <div class="categories"> <NavLink title="❌刪除" @onclick="@(async () => await DeleteAsync(item.Id))">❌</NavLink> <NavLink title="📝編輯" @onclick="@(() => ShowBox(item))">📝</NavLink> <NavLink target="_blank" href="@item.LinkUrl"> <h3>@item.Title</h3> </NavLink> </div> </div> } <div class="card-item"> <div class="categories"> <NavLink><h3 @onclick="@(() => ShowBox())">📒~~~ 新增友鏈 ~~~📒</h3></NavLink> </div> </div> </div> } else { <ErrorTip /> } </div> <Box OnClickCallback="@SubmitAsync" Open="@Open"> <div class="box-item"> <b>Title:</b><input type="text" @bind="@title" @bind:event="oninput" /> </div> <div class="box-item"> <b>LinkUrl:</b><input type="text" @bind="@linkUrl" @bind:event="oninput" /> </div> </Box> } </AdminLayout> @code { /// <summary> /// 默認隱藏Box /// </summary> private bool Open { get; set; } = false; /// <summary> /// 新增或者更新時候的友鏈字段值 /// </summary> private string title, linkUrl; /// <summary> /// 更新友鏈的Id值 /// </summary> private int id; /// <summary> /// API返回的友鏈列表數據 /// </summary> private ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>> friendlinks; /// <summary> /// 初始化 /// </summary> /// <returns></returns> protected override async Task OnInitializedAsync() { var token = await Common.GetStorageAsync("token"); Http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"); friendlinks = await FetchData(); } /// <summary> /// 獲取數據 /// </summary> /// <returns></returns> private async Task<ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>>> FetchData() { return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>>>("/blog/admin/friendlinks"); } /// <summary> /// 刪除分類 /// </summary> /// <param name="id"></param> /// <returns></returns> private async Task DeleteAsync(int id) { Open = false; // 彈窗確認 bool confirmed = await Common.InvokeAsync<bool>("confirm", "\n💥💢真的要幹掉這個該死的分類嗎💢💥"); if (confirmed) { var response = await Http.DeleteAsync($"/blog/friendlink?id={id}"); var result = await response.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { friendlinks = await FetchData(); } } } /// <summary> /// 顯示box,綁定字段 /// </summary> /// <param name="dto"></param> private void ShowBox(QueryFriendLinkForAdminDto dto = null) { Open = true; id = 0; // 新增 if (dto == null) { title = null; linkUrl = null; } else // 更新 { id = dto.Id; title = dto.Title; linkUrl = dto.LinkUrl; } } /// <summary> /// 確認按鈕點擊事件 /// </summary> /// <returns></returns> private async Task SubmitAsync() { var input = new EditFriendLinkInput() { Title = title.Trim(), LinkUrl = linkUrl.Trim() }; if (string.IsNullOrEmpty(input.Title) || string.IsNullOrEmpty(input.LinkUrl)) { return; } var responseMessage = new HttpResponseMessage(); if (id > 0) responseMessage = await Http.PutAsJsonAsync($"/blog/friendlink?id={id}", input); else responseMessage = await Http.PostAsJsonAsync("/blog/friendlink", input); var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>(); if (result.Success) { friendlinks = await FetchData(); Open = false; } } }
截至目前爲止,還剩下文章模塊的功能還沒作了,今天到這裏吧,明天繼續剛,未完待續...