Skip to content

Commit

Permalink
栏目、标签、文章管理
Browse files Browse the repository at this point in the history
  • Loading branch information
JontyMin committed Jul 3, 2020
1 parent 267792b commit 4ce7300
Show file tree
Hide file tree
Showing 18 changed files with 852 additions and 155 deletions.
13 changes: 13 additions & 0 deletions src/Jonty.Blog.BlazorApp/Commons/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,18 @@ public async Task<Uri> CurrentUri()

return await Task.FromResult(uri);
}
/// <summary>
/// 切换编辑器主题
/// </summary>
/// <param name="currentTheme"></param>
/// <returns></returns>
public async Task SwitchEditorTheme(string currentTheme)
{
var editorTheme = currentTheme == "Light" ? "default" : "dark";

await SetStorageAsync("editorTheme", editorTheme);

await InvokeAsync("window.func.switchEditorTheme");
}
}
}
1 change: 1 addition & 0 deletions src/Jonty.Blog.BlazorApp/Pages/Admin/Categories.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/admin/categories"
@using Jonty.Blog.BlazorApp.Response.Blog.Params

<AdminLayout>
@if (categories == null)
Expand Down
166 changes: 166 additions & 0 deletions src/Jonty.Blog.BlazorApp/Pages/Admin/Friendlinks.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
@page "/admin/friendlinks"
@using Jonty.Blog.BlazorApp.Response.Blog.Params

<AdminLayout>
@if (friendlinks == null)
{
<Loading /> }
else
{
<div class="post-wrap categories">
<h2 class="post-title">-&nbsp;FriendLinks&nbsp;-</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;
}
} }
199 changes: 199 additions & 0 deletions src/Jonty.Blog.BlazorApp/Pages/Admin/Post.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
@page "/admin/post"
@page "/admin/post/{id:int}"

<link href="./editor.md/css/editormd.css" rel="stylesheet" />

<AdminLayout>
@if (isLoading)
{
<Loading /> }
else
{
<div class="post-box">
<div class="post-box-item">
<input type="text" placeholder="标题" autocomplete="off" @bind="@input.Title" @bind:event="oninput" @onclick="@(() => { Open = false; })" />
<input type="text" placeholder="作者" autocomplete="off" @bind="@input.Author" @bind:event="oninput" @onclick="@(() => { Open = false; })" />
</div>
<div class="post-box-item">
<input type="text" placeholder="URL" autocomplete="off" @bind="@input.Url" @bind:event="oninput" @onclick="@(() => { Open = false; })" />
<input type="text" placeholder="时间" autocomplete="off" @bind="@input.CreationTime" @bind:format="yyyy-MM-dd HH:mm:sss" @bind:event="oninput" @onclick="@(() => { Open = false; })" />
</div>
<div id="editor">
<textarea style="display:none;">@input.Markdown</textarea>
</div>

<Box OnClickCallback="@SubmitAsync" Open="@Open" ButtonText="发布">
<div class="box-item">
<b>分类:</b>
@if (categories.Success && categories.Result.Any())
{
@foreach (var item in categories.Result)
{
<label><input type="radio" name="category" value="@item.Id" @onchange="@(() => { input.CategoryId = item.Id; })" checked="@(item.Id == input.CategoryId)" />@item.CategoryName</label>}}
</div>
<div class="box-item"></div>
<div class="box-item">
<b>标签:</b>
<input type="text" @bind="@tags" @bind:event="oninput" />
</div>
</Box>
</div>}
</AdminLayout>

@code { /// <summary>
/// 定义一个委托方法,用于组件实例方法调用
/// </summary>
private static Func<Task> action;

/// <summary>
/// 默认隐藏Box
/// </summary>
private bool Open { get; set; } = false;

/// <summary>
/// 修改时的文章Id
/// </summary>
[Parameter]
public int? Id { get; set; }

/// <summary>
/// 格式化的标签
/// </summary>
private string tags { get; set; }

/// <summary>
/// 默认显示加载中
/// </summary>
private bool isLoading = true;

/// <summary>
/// 文章新增或者修改输入参数
/// </summary>
private PostForAdminDto input;

/// <summary>
/// API返回的分类列表数据
/// </summary>
private ServiceResult<IEnumerable<QueryCategoryForAdminDto>> categories;

/// <summary>
/// 初始化
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
action = ChangeOpenStatus;

var token = await Common.GetStorageAsync("token");
Http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");

if (Id.HasValue)
{
var post = await Http.GetFromJsonAsync<ServiceResult<PostForAdminDto>>($"/blog/admin/post?id={Id}");

if (post.Success)
{
var _post = post.Result;
input = new PostForAdminDto
{
Title = _post.Title,
Author = _post.Author,
Url = _post.Url,
Html = _post.Html,
Markdown = _post.Markdown,
CategoryId = _post.CategoryId,
Tags = _post.Tags,
CreationTime = _post.CreationTime
};

tags = string.Join(",", input.Tags);
}
}
else
{
input = new PostForAdminDto()
{
Author = "Jonty",
CreationTime = DateTime.Now
};
}

categories = await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryCategoryForAdminDto>>>("/blog/admin/categories");

// 渲染编辑器
await Common.InvokeAsync("window.func.renderEditor");

// 关闭加载
isLoading = !isLoading;
}

/// <summary>
/// 改变Open状态,通知组件渲染
/// </summary>
private async Task ChangeOpenStatus()
{
Open = true;

var markdown = await Common.InvokeAsync<string>("editor.getMarkdown");
var html = await Common.InvokeAsync<string>("editor.getHTML");

if (string.IsNullOrEmpty(input.Title) || string.IsNullOrEmpty(input.Url) ||
string.IsNullOrEmpty(input.Author) || string.IsNullOrEmpty(markdown) ||
string.IsNullOrEmpty(html))
{
await Alert();
}

input.Html = html;
input.Markdown = markdown;

StateHasChanged();
}

/// <summary>
/// 暴漏给JS执行,弹窗确认框
/// </summary>
[JSInvokable("showbox")]
public static void ShowBox()
{
action.Invoke();
}

/// <summary>
/// 确认按钮点击事件
/// </summary>
/// <returns></returns>
private async Task SubmitAsync()
{
if (string.IsNullOrEmpty(tags) || input.CategoryId == 0)
{
await Alert();
}

input.Tags = tags.Split(",");

var responseMessage = new HttpResponseMessage();

if (Id.HasValue)
responseMessage = await Http.PutAsJsonAsync($"/blog/post?id={Id}", input);
else
responseMessage = await Http.PostAsJsonAsync("/blog/post", input);

var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>();
if (result.Success)
{
await Common.NavigateTo("/admin/posts");
}
}

/// <summary>
/// alert提示
/// </summary>
/// <returns></returns>
private async Task Alert()
{
Open = false;

await Common.InvokeAsync("alert", "\n💥💢好像漏了点什么吧💢💥");
return;
} }
Loading

0 comments on commit 4ce7300

Please sign in to comment.