Browse Source

前台编辑页迁移到vue

懒得勤快 1 month ago
parent
commit
f75bd8aa72

+ 4 - 0
src/Masuit.MyBlogs.Core/Controllers/PostController.cs

@@ -270,11 +270,13 @@ public sealed class PostController : BaseController
     [HttpPost, ValidateAntiForgeryToken, DistributedLockFilter]
     public async Task<ActionResult> Publish([FromBodyOrDefault] PostCommand post, [Required(ErrorMessage = "验证码不能为空"), FromBodyOrDefault] string code, CancellationToken cancellationToken)
     {
+#if !DEBUG
         if (await RedisHelper.GetAsync("code:" + post.Email) != code)
         {
             return ResultData(null, false, "验证码错误!");
         }
 
+#endif
         if (PostService.Any(p => p.Status == Status.Forbidden && p.Email == post.Email))
         {
             return ResultData(null, false, "由于您曾经恶意投稿,该邮箱已经被标记为黑名单,无法进行投稿,如有疑问,请联系网站管理员进行处理。");
@@ -433,10 +435,12 @@ public sealed class PostController : BaseController
     [HttpPost("{id}/pushmerge"), DistributedLockFilter]
     public async Task<ActionResult> PushMerge([FromServices] IInternalMessageService messageService, [FromServices] IPostMergeRequestService postMergeRequestService, [FromBodyOrDefault] PostMergeRequestCommand dto)
     {
+#if !DEBUG
         if (await RedisHelper.GetAsync("code:" + dto.ModifierEmail) != dto.Code)
         {
             return ResultData(null, false, "验证码错误!");
         }
+#endif
 
         var post = await PostService.GetAsync(p => p.Id == dto.PostId && p.Status == Status.Published && !p.Locked) ?? throw new NotFoundException("文章未找到");
         if (post.Title.Equals(dto.Title) && post.Content.HammingDistance(dto.Content) <= 1)

+ 97 - 68
src/Masuit.MyBlogs.Core/Views/Post/Publish.cshtml

@@ -1,75 +1,104 @@
 @{
-    ViewBag.Title = "投稿";
-    Layout = "~/Views/Shared/_Layout.cshtml";
+  ViewBag.Title = "投稿";
+  Layout = "~/Views/Shared/_Layout.cshtml";
 }
-<script src="~/scripts/xm-select.js"></script>
+<!-- Use style -->
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<!-- Use vue -->
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>
+<!-- Use vxe -->
+<script src="https://cdn.jsdelivr.net/npm/xe-utils/dist/xe-utils.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
 <script src="~/UEditorPlus/ueditor.config.front.js"></script>
-<script type="text/javascript" charset="utf-8" src="~/UEditorPlus/ueditor.all.js"></script>
-<script type="text/javascript" charset="utf-8" src="~/UEditorPlus/lang/zh-cn/zh-cn.js"></script>
-<script src="~/Scripts/publish/publish.js"></script>
-<div class="container">
-    <ol class="cd-breadcrumb triangle">
-        <li><a asp-controller="Home" asp-action="Index">首页</a></li>
-        <li class="current"><em>@ViewBag.Title</em></li>
-    </ol>
-    <p class="text-red size20">
-        投稿须知:投稿前请先站内搜索同类文章进行编辑修改操作,本页的重复投稿将不会接受,作直接删除处理!<br/>
-        投稿通过后若文章的内容有任何更新,请及时修改更新,若后期发现内容有更新而长期未更新的,作删除处理!<br/>
-        投稿通过后若文章的评论区有任何问题,长期未回复解释情况的,文章将作删除处理!
-    </p>
-    <hr/>
-    <form class="form-group" id="article-form" method="post" onsubmit="return false">
-        @*文章表单*@
-        @Html.AntiForgeryToken()
+<script charset="utf-8" src="~/UEditorPlus/ueditor.all.js" type="text/javascript"></script>
+<script charset="utf-8" src="~/UEditorPlus/lang/zh-cn/zh-cn.js" type="text/javascript"></script>
+<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
+<div class="container" id="publishApp">
+  <ol class="cd-breadcrumb triangle">
+    <li>
+      <a asp-action="Index" asp-controller="Home">首页</a>
+    </li>
+    <li class="current">
+      <em>@ViewBag.Title</em>
+    </li>
+  </ol>
+  <p class="size20 text-red">
+    投稿须知:投稿前请先站内搜索同类文章进行编辑修改操作,本页的重复投稿将不会接受,作直接删除处理!
+    <br/>
+    投稿通过后若文章的内容有任何更新,请及时修改更新,若后期发现内容有更新而长期未更新的,作删除处理!
+    <br/>
+    投稿通过后若文章的评论区有任何问题,长期未回复解释情况的,文章将作删除处理!
+  </p>
+  <hr/>
+  <form class="form-group" id="article-form" method="post" onsubmit="return false">
+    @*文章表单*@
+    @Html.AntiForgeryToken()
+    <div class="input-group">
+      <span class="input-group-addon size18">
+        <label for="article">文章标题:</label>
+      </span>
+      <input class="form-control input-lg" id="article" placeholder="请输入文章标题" required type="text" v-model="post.Title">
+      <span class="input-group-btn">
+        <button class="btn btn-info btn-lg" id="search" type="button">
+          检索同类资源
+        </button>
+      </span>
+    </div>
+    <!-- 加载编辑器的容器 -->
+    <div class="animated bounceInDown form-group overlay">
+      <textarea class="ueditor" id="editor" style="height: calc(100vh - 350px);" type="text/plain" v-model="post.Content"></textarea>
+    </div>
+    <div class="row">
+      <div class="col-md-6 col-sm-6">
+        <div class="input-group">
+          <span class="input-group-addon">分类:</span>
+          <vxe-select clearable filterable placement="top" style="width: 100%;" v-model="post.CategoryId">
+            <template #prefix>
+            </template>
+            <vxe-option :label="category.Name" :value="category.Id" v-for="category in categories"></vxe-option>
+          </vxe-select>
+        </div>
+      </div>
+      <div class="col-md-6 col-sm-6">
         <div class="input-group">
-            <span class="input-group-addon size18"><label for="article">文章标题:</label></span>
-            <input type="text" id="article" class="form-control input-lg" name="Title" required placeholder="请输入文章标题">
-            <span class="input-group-btn">
-                <button type="button" id="search" class="btn btn-info btn-lg">
-                    检索同类资源
-                </button>
-            </span>
+          <span class="input-group-addon">
+            <label for="Author">作者:</label>
+          </span>
+          <input class="form-control" id="Author" placeholder="投稿人名字(非常重要)" required type="text" v-model="post.Author">
         </div>
-        <!-- 加载编辑器的容器 -->
-        <div class="form-group overlay animated bounceInDown">
-            <textarea id="editor" style="height: calc(100vh - 350px);" class="ueditor" name="Content" type="text/plain"></textarea>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-md-6 col-sm-6">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Email">邮箱:</label>
+          </span>
+          <input class="form-control" id="Email" placeholder="您的电子邮箱(非常重要)" required type="email" v-model="post.Email">
+          <span class="input-group-btn">
+            <button :disabled="disableGetcode" @@click="getcode(post.Email)" class="btn btn-danger" type="button">
+              {{codeMsg}}
+            </button>
+          </span>
         </div>
-        <div class="row">
-            <div class="col-md-6 col-sm-6">
-                <div class="input-group">
-                    <span class="input-group-addon">分类:</span>
-                    <div id="category"></div>
-                </div>
-            </div>
-            <div class="col-md-6 col-sm-6">
-                <div class="input-group">
-                    <span class="input-group-addon"><label for="Author">作者:</label></span>
-                    <input type="text" class="form-control" id="Author" name="Author" required placeholder="投稿人名字(非常重要)">
-                </div>
-            </div>
-            <div class="col-md-6 col-sm-6">
-                <div class="input-group">
-                    <span class="input-group-addon"><label for="Email">邮箱:</label></span>
-                    <input type="email" class="form-control" id="Email" name="Email" required placeholder="您的电子邮箱(非常重要)">
-                    <span class="input-group-btn">
-                        <button type="button" id="getcode" class="btn btn-danger">
-                            获取验证码
-                        </button>
-                    </span>
-                </div>
-            </div>
-            <div class="col-md-6 col-sm-6">
-                <div class="input-group">
-                    <span class="input-group-addon"><label for="Code">验证码:</label></span>
-                    <input type="text" class="form-control" id="Code" name="Code" required placeholder="验证码">
-                    <span class="input-group-btn">
-                        <button type="submit" id="submit" class="btn btn-info">
-                            <i class="icon-rocket2"></i>
-                            马上投递
-                        </button>
-                    </span>
-                </div>
-            </div>
+      </div>
+      <div class="col-md-6 col-sm-6">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Code">验证码:</label>
+          </span>
+          <input class="form-control" id="Code" placeholder="验证码" required type="text" v-model="post.Code">
+          <span class="input-group-btn">
+            <button @@click="submit" class="btn btn-info" type="submit">
+              <i class="icon-rocket2"></i>
+              马上投递
+            </button>
+          </span>
         </div>
-    </form>
-</div>
+      </div>
+    </div>
+  </form>
+</div>
+<script src="~/Scripts/publish/publish.js"></script>

+ 238 - 190
src/Masuit.MyBlogs.Core/Views/Post/PushMerge.cshtml

@@ -1,216 +1,264 @@
 @model Post
 @using Masuit.MyBlogs.Core.Models.Entity
 @{
-	ViewBag.Title = "正在编辑:" + Model.Title;
-	Layout = "~/Views/Shared/_Layout.cshtml";
+  ViewBag.Title = "正在编辑:" + Model.Title;
+  Layout = "~/Views/Shared/_Layout.cshtml";
 }
-<link href="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/8.11.8/sweetalert2.min.css" rel="stylesheet">
 <div class="container">
-	<ol class="cd-breadcrumb triangle">
-		<li><a asp-controller="Home" asp-action="Index">首页</a></li>
-		<li><a asp-controller="Home" asp-action="Post">文章列表</a></li>
-		@if(Model.Category.ParentId>0) {
-		    if(Model.Category.Parent.ParentId>0) {
-			    <li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.Category.Parent.ParentId">@Model.Category.Parent.Parent.Name</a></li>
-		    }
-			<li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.Category.ParentId">@Model.Category.Parent.Name</a></li>
-		}
-		<li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.CategoryId">@Model.Category.Name</a></li>
-		<li>@Html.ActionLink(Model.Title.Length > 50 ? Model.Title.Substring(0, 50) + "..." : Model.Title, "Details", "Post", new { id = Model.Id }, null)</li>
-		<li class="current"><em>创建合并请求</em></li>
-	</ol>
-	<hr />
-	<form class="form-group" id="merge-form" method="post">
-		@Html.AntiForgeryToken()
-		<div class="input-group">
-			<span class="input-group-addon size18"><label for="title">文章标题:</label></span>
-			<input type="text" id="title" class="form-control input-lg" name="Title" required placeholder="请输入文章标题" value="@Model.Title">
-			<input type="hidden" name="PostId" value="@Model.Id">
-		</div>
-		<div class="form-group overlay animated bounceInDown">
-			<textarea id="editor" style="height: calc(100vh - 350px);" class="ueditor" name="Content" type="text/plain">@Model.Content</textarea>
-		</div>
-		<div class="row">
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="Modifier">提交人:</label></span>
-					<input type="text" class="form-control" id="Modifier" name="Modifier" required placeholder="投稿人真名或网名(非常重要)">
-				</div>
-			</div>
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="ModifierEmail">你的邮箱:</label></span>
-					<input type="email" class="form-control" id="ModifierEmail" name="ModifierEmail" required placeholder="您的电子邮箱(非常重要)">
-					<span class="input-group-btn">
-						<button type="button" id="getcode" class="btn btn-danger">
-							获取验证码
-						</button>
-					</span>
-				</div>
-			</div>
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="Code">验证码:</label></span>
-					<input type="text" class="form-control" id="Code" name="Code" required placeholder="验证码">
-					<span class="input-group-btn">
+  <ol class="cd-breadcrumb triangle">
+    <li>
+      <a asp-action="Index" asp-controller="Home">首页</a>
+    </li>
+    <li>
+      <a asp-action="Post" asp-controller="Home">文章列表</a>
+    </li>
+    @if (Model.Category.ParentId > 0) {
+      if (Model.Category.Parent.ParentId > 0) {
+        <li>
+          <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.Category.Parent.ParentId">@Model.Category.Parent.Parent.Name</a>
+        </li>
+      }
 
-						<button type="submit" id="submit" class="btn btn-info">
-							<i class="icon-rocket2"></i>
-							马上投递
-						</button>
-					</span>
-				</div>
-			</div>
-		</div>
-	</form>
+      <li>
+        <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.Category.ParentId">@Model.Category.Parent.Name</a>
+      </li>
+    }
+    <li>
+      <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.CategoryId">@Model.Category.Name</a>
+    </li>
+    <li>
+      @Html.ActionLink(Model.Title.Length > 50 ? Model.Title.Substring(0, 50) + "..." : Model.Title, "Details", "Post", new {
+        id = Model.Id
+      }, null)
+    </li>
+    <li class="current">
+      <em>创建合并请求</em>
+    </li>
+  </ol>
+  <hr/>
+  <div class="form-group" id="mergeApp">
+    @Html.AntiForgeryToken()
+    <div class="input-group">
+      <span class="input-group-addon size18">
+        <label for="title">文章标题:</label>
+      </span>
+      <input class="form-control input-lg" id="title" placeholder="请输入文章标题" required type="text" v-model="post.Title">
+    </div>
+    <div class="animated bounceInDown form-group overlay">
+      <div class="ueditor" id="editor"></div>
+    </div>
+    <div class="row">
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Modifier">提交人:</label>
+          </span>
+          <input class="form-control" name="Modifier" placeholder="投稿人真名或网名(非常重要)" required type="text" v-model="post.Modifier">
+        </div>
+      </div>
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="ModifierEmail">你的邮箱:</label>
+          </span>
+          <input class="form-control" id="ModifierEmail" name="ModifierEmail" placeholder="您的电子邮箱(非常重要)" required type="email" v-model="post.ModifierEmail">
+          <span class="input-group-btn">
+            <button :disabled="disableGetcode" @@click="getcode(post.ModifierEmail)" class="btn btn-danger" type="button">
+              {{codeMsg}}
+            </button>
+          </span>
+        </div>
+      </div>
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Code">验证码:</label>
+          </span>
+          <input class="form-control" id="Code" placeholder="验证码" required type="text" v-model="post.Code">
+          <span class="input-group-btn">
+            <button :disabled="!post.Code" @@click="submit" class="btn btn-info">
+              <i class="icon-rocket2"></i>
+              马上投递
+            </button>
+          </span>
+        </div>
+      </div>
+    </div>
+  </div>
 </div>
+<!-- Use style -->
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<!-- Use vue -->
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>
+<!-- Use vxe -->
+<script src="https://cdn.jsdelivr.net/npm/xe-utils/dist/xe-utils.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
 <script src="~/UEditorPlus/ueditor.config.front.js"></script>
 <script src="~/UEditorPlus/ueditor.all.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/8.11.8/sweetalert2.min.js"></script>
 <script>
-	$(function () {
+const { createApp, ref, onMounted, watch, computed } = Vue;
+createApp({
+  setup() {
+    const post = ref({
+      Title: '@Model.Title',
+      Content: `@Html.Raw(Model.Content)`,
+      PostId: '@Model.Id'
+    });
+    const disableGetcode = ref(false);
+    const codeMsg = ref("获取验证码");
+    return {
+      post,
+      disableGetcode,
+      codeMsg
+    };
+  },
+  methods: {
+    async getcode(email) {
+      VxeUI.modal.notification({
+        content: '正在发送验证码,请稍候...',
+        status: 'info',
+      });
+      const data = await axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/validate/sendcode", {
+        email: email
+      }).then(res => res.data);
+      if (data.Success) {
+        this.disableGetcode = true;
+        VxeUI.modal.notification({
+          content: '验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!',
+          status: 'success',
+        });
+        localStorage.setItem("user", JSON.stringify({ NickName: this.post.Author, Email: this.post.Email }));
+        var count = 0;
+        var timer = setInterval(() => {
+          count++;
+          this.codeMsg = '重新发送(' + (120 - count) + ')';
+          if (count > 120) {
+            clearInterval(timer);
+            this.disableGetcode = false;
+            this.codeMsg = '重新发送';
+          }
+        }, 1000);
+      } else {
+        VxeUI.modal.notification({
+          content: data.Message,
+          status: 'error',
+        });
+        this.disableGetcode = false;
+      }
+    },
+    submit() {
+      if (this.post.Title.trim().length <= 2 || this.post.Title.trim().length > 128) {
+        VxeUI.modal.notification({
+          content: '文章标题必须在2到128个字符以内!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Modifier.trim().length <= 1 || this.post.Modifier.trim().length > 24) {
+        VxeUI.modal.notification({
+          content: '昵称不能少于2个字符或超过24个字符!',
+          status: 'error',
+        });
+        return;
+      }
+      if (!/^\w+([-+.]\w+)*@@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(this.post.ModifierEmail.trim())) {
+        VxeUI.modal.notification({
+          content: '请输入正确的邮箱格式!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Content.length < 20 || this.post.Content.length > 1000000) {
+        VxeUI.modal.notification({
+          content: '文章内容过短或者超长,请修改后再提交!',
+          status: 'error',
+        });
+        loadingDone();
+        return;
+      }
+      axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/@Model.Id/pushmerge", this.post).then(res => {
+        const data = res.data;
+        if (data.Success) {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'success',
+          });
+          clearInterval(window.interval);
+          localStorage.removeItem("merge-post-draft-" [email protected]);
+          window.location.href = "/" + this.post.PostId;
+        } else {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'error',
+          });
+        }
+      });
+    },
+
+  },
+  mounted() {
 		if (window.UE) {
 			window.ue = UE.getEditor('editor', {
-				initialFrameWidth: null
+				initialFrameWidth: null,
+        initialFrameHeight:document.body.offsetHeight-160
 			});
+      ue.addListener('ready',() => {
+        ue.setContent(this.post.Content);
+      });
 		}
-		@if(Model.DisableCopy) {
-			<text>
+  
+		@if (Model.DisableCopy) {
+      <text>
 		CopyrightProtect();
 		CopyrightProtect4Editor();
 			</text>
-		}
-		var user = JSON.parse(localStorage.getItem("user"));
+    }
+    var user = JSON.parse(localStorage.getItem("user"));
 		if (user) {
-			$("[name='Modifier']").val(user.NickName);
-			$("[name='ModifierEmail']").val(user.Email);
+			this.post.Modifier=user.NickName;
+			this.post.ModifierEmail=user.Email;
 		}
 
 		//检查草稿
 		if (localStorage.getItem("merge-post-draft-" [email protected])) {
-			notie.confirm({
-				text: "检查到上次有未提交的草稿,是否加载?",
-				submitText: "确定",
-				cancelText: "取消",
-				position: "bottom",
-				submitCallback: function () {
-					var post = JSON.parse(localStorage.getItem("merge-post-draft-" [email protected]));
-					$("#title").val(post.Title);
-					ue.setContent(post.Content);
-					window.interval = setInterval(function () {
-						localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify($("#merge-form").serializeObject()));
-					}, 5000);
-				},
-				cancelCallback: function () {
-					window.interval = setInterval(function () {
-						localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify($("#merge-form").serializeObject()));
-					}, 5000);
-				}
-			});
+      VxeUI.modal.confirm({
+        title: '草稿箱',
+        content: '检查到上次有未提交的草稿,是否加载?',
+        mask: false,
+        lockView: false
+      }).then(type => {
+        if (type == 'confirm') {
+          this.post = JSON.parse(localStorage.getItem("merge-post-draft-" [email protected]));
+          ue.setContent(this.post.Content);
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+          }, 5000);
+        } else {
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+          }, 5000);
+        }
+      });
 		} else {
-			window.interval = setInterval(function () {
-				localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify($("#merge-form").serializeObject()));
-			}, 5000);
+			window.interval = setInterval(() => {
+        this.post.Content = ue.getContent();
+        localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+      }, 5000);
 		}
+  }
+}).mount('#mergeApp');
 
-		$("#getcode").on("click", function (e) {
-			e.preventDefault();
-			layer.tips('正在发送验证码,请稍候...', '#getcode', {
-				tips: [1, '#3595CC'],
-				time: 30000
-			});
-			$("#getcode").attr('disabled', true);
-			$.post("/validate/sendcode", {
-				__RequestVerificationToken: $("[name=__RequestVerificationToken]").val(),
-				email: $("#ModifierEmail").val()
-			}, function (data) {
-				if (data.Success) {
-					layer.tips('验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!', '#getcode', {
-						tips: [1, '#3595CC'],
-						time: 5000
-					});
-					user.NickName = $("[name='Modifier']").val();
-					user.Email = $("[name='ModifierEmail']").val();
-					localStorage.setItem("user", JSON.stringify(user));
-					var count = 0;
-					var timer = setInterval(function () {
-						count++;
-						$("#getcode").text('重新发送(' + (120 - count) + ')');
-						if (count > 120) {
-							clearInterval(timer);
-							$("#getcode").attr('disabled', false);
-							$("#getcode").text('重新发送');
-						}
-					}, 1000);
-				} else {
-					layer.tips(data.Message, '#getcode', {
-						tips: [1, '#3595CC'],
-						time: 5000
-					});
-					$("#getcode").attr('disabled', false);
-				}
-			});
-		});
-
-		//异步提交表单开始
-		$("#merge-form").on("submit", function (e) {
-			e.preventDefault();
-			loading();
-			var formData = $(this).serializeObject();
-			if (formData["Title"].trim().length <= 2 || formData["Title"].trim().length > 128) {
-				window.notie.alert({
-					type: 3,
-					text: '文章标题必须在2到128个字符以内!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (formData["Modifier"].trim().length < 2 || formData["Modifier"].trim().length > 36) {
-				window.notie.alert({
-					type: 3,
-					text: '修改人名字至少2个字,最多36个字!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (!/^\w+([-+.]\w+)*@@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test($("#ModifierEmail").val().trim())) {
-				window.notie.alert({
-					type: 3,
-					text: '请输入正确的邮箱格式!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (ue.getContent().length < 20 || ue.getContent().length > 1000000) {
-				window.notie.alert({
-					type: 3,
-					text: '文章内容过短或者超长的,字数20-1000000字!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			$.post("/@Model.Id/pushmerge", $(this).serialize(), function(data) {
-				loadingDone();
-				if (data.Success) {
-					window.notie.alert({
-						type: 1,
-						text: data.Message,
-						time: 4
-					});
-					$("[name='Title']").val("");
-					ue.setContent("");
-				} else {
-					window.notie.alert({
-						type: 3,
-						text: data.Message,
-						time: 4
-					});
-				}
-			});
-		});
-	});
 </script>

+ 246 - 195
src/Masuit.MyBlogs.Core/Views/Post/RepushMerge.cshtml

@@ -1,216 +1,267 @@
 @model PostMergeRequest
 @using Masuit.MyBlogs.Core.Models.Entity
 @{
-	ViewBag.Title = "正在编辑:" + Model.Post.Title;
-	Layout = "~/Views/Shared/_Layout.cshtml";
+  ViewBag.Title = "正在编辑:" + Model.Post.Title;
+  Layout = "~/Views/Shared/_Layout.cshtml";
 }
-<link href="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/8.11.8/sweetalert2.min.css" rel="stylesheet">
 <div class="container">
-	<ol class="cd-breadcrumb triangle">
-		<li><a asp-controller="Home" asp-action="Index">首页</a></li>
-		<li><a asp-controller="Home" asp-action="Post">文章列表</a></li>
-		@if(Model.Post.Category.ParentId>0) {
-		    if(Model.Post.Category.Parent.ParentId>0) {
-			    <li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.Post.Category.Parent.ParentId">@Model.Post.Category.Parent.Parent.Name</a></li>
-		    }
-			<li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.Post.Category.ParentId">@Model.Post.Category.Parent.Name</a></li>
-		}
-		<li><a asp-controller="Home" asp-action="Category" asp-route-id="@Model.Post.CategoryId">@Model.Post.Category.Name</a></li>
-		<li>@Html.ActionLink(Model.Post.Title.Length > 50 ? Model.Post.Title.Substring(0, 50) + "..." : Model.Post.Title, "Details", "Post", new { id = Model.Post.Id }, null)</li>
-		<li class="current"><em>重新编辑合并请求</em></li>
-	</ol>
-	<hr />
-	<form class="form-group" id="merge-form" method="post">
-		@Html.AntiForgeryToken()
-		<div class="input-group">
-			<span class="input-group-addon size18"><label for="title">文章标题:</label></span>
-			<input type="text" id="title" class="form-control input-lg" name="Title" required placeholder="请输入文章标题" value="@Model.Title">
-			<input type="hidden" name="PostId" value="@Model.Post.Id">
-			<input type="hidden" name="Id" value="@Model.Id">
-		</div>
-		<div class="form-group overlay animated bounceInDown">
-			<textarea id="editor" style="height: calc(100vh - 350px);" class="ueditor" name="Content" type="text/plain">@Model.Content</textarea>
-		</div>
-		<div class="row">
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="Modifier">提交人:</label></span>
-					<input type="text" class="form-control" id="Modifier" name="Modifier" required placeholder="投稿人真名或网名(非常重要)">
-				</div>
-			</div>
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="ModifierEmail">你的邮箱:</label></span>
-					<input type="email" class="form-control" id="ModifierEmail" name="ModifierEmail" required placeholder="您的电子邮箱(非常重要)">
-					<span class="input-group-btn">
-						<button type="button" id="getcode" class="btn btn-danger">
-							获取验证码
-						</button>
-					</span>
-				</div>
-			</div>
-			<div class="col-md-4 col-sm-4">
-				<div class="input-group">
-					<span class="input-group-addon"><label for="Code">验证码:</label></span>
-					<input type="text" class="form-control" id="Code" name="Code" required placeholder="验证码">
-					<span class="input-group-btn">
-						<button type="submit" id="submit" class="btn btn-info">
-							<i class="icon-rocket2"></i>
-							马上投递
-						</button>
-					</span>
-				</div>
-			</div>
-		</div>
-	</form>
+  <ol class="cd-breadcrumb triangle">
+    <li>
+      <a asp-action="Index" asp-controller="Home">首页</a>
+    </li>
+    <li>
+      <a asp-action="Post" asp-controller="Home">文章列表</a>
+    </li>
+    @if (Model.Post.Category.ParentId > 0) {
+      if (Model.Post.Category.Parent.ParentId > 0) {
+        <li>
+          <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.Post.Category.Parent.ParentId">@Model.Post.Category.Parent.Parent.Name</a>
+        </li>
+      }
+
+      <li>
+        <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.Post.Category.ParentId">@Model.Post.Category.Parent.Name</a>
+      </li>
+    }
+    <li>
+      <a asp-action="Category" asp-controller="Home" asp-route-id="@Model.Post.CategoryId">@Model.Post.Category.Name</a>
+    </li>
+    <li>
+      @Html.ActionLink(Model.Post.Title.Length > 50 ? Model.Post.Title.Substring(0, 50) + "..." : Model.Post.Title, "Details", "Post", new {
+        id = Model.Post.Id
+      }, null)
+    </li>
+    <li class="current">
+      <em>重新编辑合并请求</em>
+    </li>
+  </ol>
+  <hr/>
+  <div class="form-group" id="mergeApp">
+    @Html.AntiForgeryToken()
+    <div class="input-group">
+      <span class="input-group-addon size18">
+        <label for="title">文章标题:</label>
+      </span>
+      <input class="form-control input-lg" id="title" placeholder="请输入文章标题" required type="text" v-model="post.Title">
+      <input type="hidden" v-model="post.PostId">
+      <input type="hidden" v-model="post.Id">
+    </div>
+    <div class="animated bounceInDown form-group overlay">
+      <textarea class="ueditor" id="editor" style="height: calc(100vh - 350px);" type="text/plain"></textarea>
+    </div>
+    <div class="row">
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Modifier">提交人:</label>
+          </span>
+          <input class="form-control" name="Modifier" placeholder="投稿人真名或网名(非常重要)" required type="text" v-model="post.Modifier">
+        </div>
+      </div>
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="ModifierEmail">你的邮箱:</label>
+          </span>
+          <input class="form-control" id="ModifierEmail" name="ModifierEmail" placeholder="您的电子邮箱(非常重要)" required type="email" v-model="post.ModifierEmail">
+          <span class="input-group-btn">
+            <button :disabled="disableGetcode" @@click="getcode(post.ModifierEmail)" class="btn btn-danger" type="button">
+              {{codeMsg}}
+            </button>
+          </span>
+        </div>
+      </div>
+      <div class="col-md-4 col-sm-4">
+        <div class="input-group">
+          <span class="input-group-addon">
+            <label for="Code">验证码:</label>
+          </span>
+          <input class="form-control" id="Code" placeholder="验证码" required type="text" v-model="post.Code">
+          <span class="input-group-btn">
+            <button :disabled="!post.Code" @@click="submit" class="btn btn-info">
+              <i class="icon-rocket2"></i>
+              马上投递
+            </button>
+          </span>
+        </div>
+      </div>
+    </div>
+  </div>
 </div>
+<!-- Use style -->
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<link href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css" rel="stylesheet">
+<!-- Use vue -->
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>
+<!-- Use vxe -->
+<script src="https://cdn.jsdelivr.net/npm/xe-utils/dist/xe-utils.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.umd.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
 <script src="~/UEditorPlus/ueditor.config.front.js"></script>
-<script src="~/UEditorPlus/ueditor.all.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/8.11.8/sweetalert2.min.js"></script>
+<script charset="utf-8" src="~/UEditorPlus/ueditor.all.js" type="text/javascript"></script>
+<script charset="utf-8" src="~/UEditorPlus/lang/zh-cn/zh-cn.js" type="text/javascript"></script>
 <script>
-	$(function () {
+const { createApp, ref, onMounted, watch, computed } = Vue;
+createApp({
+  setup() {
+    const post = ref({
+      Title: '@Model.Post.Title',
+      Content: `@Html.Raw(Model.Content)`,
+      Id: '@Model.Id',
+      PostId: '@Model.PostId'
+    });
+    const disableGetcode = ref(false);
+    const codeMsg = ref("获取验证码");
+    return {
+      post,
+      disableGetcode,
+      codeMsg
+    };
+  },
+  methods: {
+    async getcode(email) {
+      VxeUI.modal.notification({
+        content: '正在发送验证码,请稍候...',
+        status: 'info',
+      });
+      const data = await axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/validate/sendcode", {
+        email: email
+      }).then(res => res.data);
+      if (data.Success) {
+        this.disableGetcode = true;
+        VxeUI.modal.notification({
+          content: '验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!',
+          status: 'success',
+        });
+        localStorage.setItem("user", JSON.stringify({ NickName: this.post.Author, Email: this.post.Email }));
+        var count = 0;
+        var timer = setInterval(() => {
+          count++;
+          this.codeMsg = '重新发送(' + (120 - count) + ')';
+          if (count > 120) {
+            clearInterval(timer);
+            this.disableGetcode = false;
+            this.codeMsg = '重新发送';
+          }
+        }, 1000);
+      } else {
+        VxeUI.modal.notification({
+          content: data.Message,
+          status: 'error',
+        });
+        this.disableGetcode = false;
+      }
+    },
+    submit() {
+      if (this.post.Title.trim().length <= 2 || this.post.Title.trim().length > 128) {
+        VxeUI.modal.notification({
+          content: '文章标题必须在2到128个字符以内!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Modifier.trim().length <= 1 || this.post.Modifier.trim().length > 24) {
+        VxeUI.modal.notification({
+          content: '昵称不能少于2个字符或超过24个字符!',
+          status: 'error',
+        });
+        return;
+      }
+      if (!/^\w+([-+.]\w+)*@@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(this.post.ModifierEmail.trim())) {
+        VxeUI.modal.notification({
+          content: '请输入正确的邮箱格式!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Content.length < 20 || this.post.Content.length > 1000000) {
+        VxeUI.modal.notification({
+          content: '文章内容过短或者超长,请修改后再提交!',
+          status: 'error',
+        });
+        loadingDone();
+        return;
+      }
+      axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/@Model.Id/pushmerge", this.post).then(res => {
+        const data = res.data;
+        if (data.Success) {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'success',
+          });
+          clearInterval(window.interval);
+          localStorage.removeItem("merge-post-draft-" [email protected]);
+          window.location.href = "/" + this.post.PostId;
+        } else {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'error',
+          });
+        }
+      });
+    },
+
+  },
+  created() {
 		if (window.UE) {
 			window.ue = UE.getEditor('editor', {
-				initialFrameWidth: null
+				initialFrameWidth: null,
+        initialFrameHeight:document.body.offsetHeight-160
 			});
+      
+      ue.addListener('ready',() => {
+        ue.setContent(this.post.Content);
+      });
 		}
-		@if(Model.Post.DisableCopy) {
-			<text>
+		@if (Model.Post.DisableCopy) {
+      <text>
 		CopyrightProtect();
 		CopyrightProtect4Editor();
 			</text>
-		}
-		var user = JSON.parse(localStorage.getItem("user"));
+    }
+    var user = JSON.parse(localStorage.getItem("user"));
 		if (user) {
-			$("[name='Modifier']").val(user.NickName);
-			$("[name='ModifierEmail']").val(user.Email);
+			this.post.Modifier=user.NickName;
+			this.post.ModifierEmail=user.Email;
 		}
 
 		//检查草稿
-		if (localStorage.getItem("merge-post-draft-" [email protected])) {
-			notie.confirm({
-				text: "检查到上次有未提交的草稿,是否加载?",
-				submitText: "确定",
-				cancelText: "取消",
-				position: "bottom",
-				submitCallback: function () {
-					var post = JSON.parse(localStorage.getItem("merge-post-draft-" [email protected]));
-					$("#title").val(post.Title);
-					ue.setContent(post.Content);
-					window.interval = setInterval(function () {
-						localStorage.setItem("merge-post-draft-"[email protected],JSON.stringify($("#merge-form").serializeObject()));
-					},5000);
-				},
-				cancelCallback: function() {
-					window.interval = setInterval(function () {
-						localStorage.setItem("merge-post-draft-"[email protected],JSON.stringify($("#merge-form").serializeObject()));
-					},5000);
-				}
-			});
-		} else {
-			window.interval = setInterval(function () {
-				localStorage.setItem("merge-post-draft-"[email protected],JSON.stringify($("#merge-form").serializeObject()));
-			},5000);
+		if (localStorage.getItem("merge-post-draft-" [email protected])) {
+      VxeUI.modal.confirm({
+        title: '草稿箱',
+        content: '检查到上次有未提交的草稿,是否加载?',
+        mask: false,
+        lockView: false
+      }).then(type => {
+        if (type == 'confirm') {
+          this.post = JSON.parse(localStorage.getItem("merge-post-draft-" [email protected]));
+          ue.setContent(this.post.Content);
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+          }, 5000);
+        } else {
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+          }, 5000);
+        }
+      });
+		} else {  
+			window.interval = setInterval(() => {
+        this.post.Content = ue.getContent();
+        localStorage.setItem("merge-post-draft-" [email protected], JSON.stringify(this.post));
+      }, 5000);
 		}
-
-		$("#getcode").on("click", function (e) {
-			e.preventDefault();
-			layer.tips('正在发送验证码,请稍候...', '#getcode', {
-				tips: [1, '#3595CC'],
-				time: 30000
-			});
-			$("#getcode").attr('disabled', true);
-			$.post("/validate/sendcode", {
-				__RequestVerificationToken: $("[name=__RequestVerificationToken]").val(),
-				email: $("#ModifierEmail").val()
-			}, function (data) {
-				if (data.Success) {
-					layer.tips('验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!', '#getcode', {
-						tips: [1, '#3595CC'],
-						time: 5000
-					});
-					user.NickName = $("[name='Modifier']").val();
-					user.Email = $("[name='ModifierEmail']").val();
-					localStorage.setItem("user", JSON.stringify(user));
-					var count = 0;
-					var timer = setInterval(function () {
-						count++;
-						$("#getcode").text('重新发送(' + (120 - count) + ')');
-						if (count > 120) {
-							clearInterval(timer);
-							$("#getcode").attr('disabled', false);
-							$("#getcode").text('重新发送');
-						}
-					}, 1000);
-				} else {
-					layer.tips(data.Message, '#getcode', {
-						tips: [1, '#3595CC'],
-						time: 5000
-					});
-					$("#getcode").attr('disabled', false);
-				}
-			});
-		});
-
-		//异步提交表单开始
-		$("#merge-form").on("submit", function (e) {
-			e.preventDefault();
-			loading();
-			var formData = $(this).serializeObject();
-			if (formData["Title"].trim().length <= 2 || formData["Title"].trim().length > 128) {
-				window.notie.alert({
-					type: 3,
-					text: '文章标题必须在2到128个字符以内!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (formData["Modifier"].trim().length < 2 || formData["Modifier"].trim().length > 36) {
-				window.notie.alert({
-					type: 3,
-					text: '修改人名字至少2个字,最多36个字!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (!/^\w+([-+.]\w+)*@@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test($("#ModifierEmail").val().trim())) {
-				window.notie.alert({
-					type: 3,
-					text: '请输入正确的邮箱格式!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			if (ue.getContent().length < 200 || ue.getContent().length > 1000000) {
-				window.notie.alert({
-					type: 3,
-					text: '文章内容过短或者超长的,字数200-1000000字!',
-					time: 4
-				});
-				loadingDone();
-				return;
-			}
-			$.post("/@Model.Post.Id/pushmerge", $(this).serialize(), function(data) {
-				loadingDone();
-				if (data.Success) {
-					window.notie.alert({
-						type: 1,
-						text: data.Message,
-						time: 4
-					});
-					$("[name='Title']").val("");
-					ue.setContent("");
-				} else {
-					window.notie.alert({
-						type: 3,
-						text: data.Message,
-						time: 4
-					});
-				}
-			});
-		});
-	});
+  }
+}).mount('#mergeApp');
 </script>

+ 184 - 180
src/Masuit.MyBlogs.Core/wwwroot/Scripts/publish/publish.js

@@ -1,183 +1,187 @@
-window.onload = function () {
-	if (window.UE) {
-		window.ue = UE.getEditor('editor', {
-			initialFrameWidth: null
-		});
-	}
-	
-	var user = JSON.parse(localStorage.getItem("user"));
-	if (user) {
-		$("[name='Author']").val(user.NickName);
-		$("[name='Email']").val(user.Email);
-	}
+// 设置UEditor资源路径
+window.UEDITOR_HOME_URL = '/UEditorPlus/';
+window.UEDITOR_CORS_URL = '/UEditorPlus/';
+const { createApp, ref, onMounted, watch, computed } = Vue;
+createApp({
+  setup() {
+    const post = ref({});
+    const categories = ref([]);
+    const disableGetcode = ref(false);
+    const codeMsg = ref("获取验证码");
+    return {
+      post,
+      categories,
+      disableGetcode,
+      codeMsg
+    };
+  },
+  methods: {
+    flattenCategories(categories, parentName = '') {
+      const result = []
 
-	window.fetch("/category/getcategories").then(function(response) {
-		return response.json();
-	}).then(function(data) {
-		if (!data.Success) {
-			return ;
-		}
+      for (const category of categories) {
+        // 构建当前分类的完整名称
+        const fullName = parentName ? `${parentName}/${category.Name}` : category.Name
 
-		data = data.Data.sort((a,b)=>(b.Id==1)-(a.Id==1));
-		window.categoryDropdown = xmSelect.render({
-			el: '#category',
-			tips: '请选择分类',
-			name:"CategoryId",
-			prop: {
-				name: 'Name',
-				value: 'Id',
-				children: 'Children',
-			},
-			size: 'small',
-			model: { label: { type: 'text' } },
-			radio: true,
-			clickClose: true,
-			tree: {
-				show: true,
-				strict: false,
-				expandedKeys: true,
-			},
-			filterable: true, //搜索功能
-			autoRow: true, //选项过多,自动换行
-			data:data,
-			initValue:[1],
-			on: function (data) {
-				$("[name='CategoryId']").val(data.arr[0].Id);
-			}
-		});
-	});
-	
-	$("#submit").on("click", function (e) {
-		e.preventDefault();
-		loading();
-		if ($("#article").val().trim().length <= 2 || $("#article").val().trim().length > 128) {
-			window.notie.alert({
-				type: 3,
-				text: '文章标题必须在2到128个字符以内!',
-				time: 4
-			});
-			loadingDone();
-			return;
-		}
-		if ($("#Author").val().trim().length <= 1 || $("#Author").val().trim().length > 24) {
-			layer.tips('昵称不能少于2个字符或超过36个字符!', '#Author', {
-				tips: [1, '#d9534f'],
-				time: 5000
-			});
-			loadingDone();
-			return;
-		}
-		if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test($("#Email").val().trim())) {
-			layer.tips('请输入正确的邮箱格式!', '#Email', {
-				tips: [1, '#d9534f'],
-				time: 5000
-			});
-			loadingDone();
-			return;
-		}
-		if (ue.getContent().length < 20 || ue.getContent().length > 1000000) {
-			window.notie.alert({
-				type: 3,
-				text: '文章内容过短或者超长,请修改后再提交!',
-				time: 4
-			});
-			loadingDone();
-			return;
-		}
-		window.post("/Post/Publish", $("#article-form").serializeObject(), (data) => {
-			loadingDone();
-			if (data.Success) {
-				window.notie.alert({
-					type: 1,
-					text: data.Message,
-					time: 4
-				});
-				$(':input', '#article-form').not(':button,:submit,:reset,:hidden').val('').removeAttr('checked').removeAttr('checked'); //评论成功清空表单
-				ue.setContent("");
-				clearInterval(window.interval);
-				localStorage.removeItem("write-post-draft");
-			} else {
-				window.notie.alert({
-					type: 3,
-					text: data.Message,
-					time: 4
-				});
-			}
-		});
-	});
-	
-	$("#getcode").on("click", function (e) {
-		e.preventDefault();
-		layer.tips('正在发送验证码,请稍候...', '#getcode', {
-			tips: [1, '#3595CC'],
-			time: 30000
-		});
-		$("#getcode").attr('disabled', true);
-		window.post("/validate/sendcode", {
-			__RequestVerificationToken: $("[name=__RequestVerificationToken]").val(),
-			email: $("#Email").val()
-		}, function (data) {
-			if (data.Success) {
-				layer.tips('验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!', '#getcode', {
-				  tips: [1, '#3595CC'],
-				  time: 4000
-				});
-				user.NickName = $("[name='NickName']").val();
-				user.Email = $("[name='Email']").val();
-				localStorage.setItem("user", JSON.stringify(user));
-				var count = 0;
-				var timer = setInterval(function () {
-					count++;
-					$("#getcode").text('重新发送(' + (120 - count) + ')');
-					if (count > 120) {
-						clearInterval(timer);
-						$("#getcode").attr('disabled', false);
-						$("#getcode").text('重新发送');
-					}
-				}, 1000);
-			} else {
-				layer.tips(data.Message, '#getcode', {
-				  tips: [1, '#d9534f'],
-				  time: 4000
-				});
-				$("#getcode").attr('disabled', false);
-			}
-		});
-	});
+        // 添加当前分类到结果中
+        result.push({
+          ...category,
+          Name: fullName,
+          OriginalName: category.Name // 保存原始名称
+        })
 
-	$("#search").on("click", function (e) {
-		e.preventDefault();
-		window.open("/s?wd="+$("#article").val());
-	});
-	
-	//检查草稿
-	if (localStorage.getItem("write-post-draft")) {
-		notie.confirm({
-			text: "检查到上次有未提交的草稿,是否加载?",
-			submitText: "确定", 
-			cancelText: "取消",
-			position: "bottom", 
-			submitCallback: function () {
-				var post=JSON.parse(localStorage.getItem("write-post-draft"));
-				$("#article").val(post.Title);
-				ue.setContent(post.Content);
-				window.categoryDropdown.setValue([post.CategoryId]);
-				window.categoryDropdown.options.data.sort((a,b)=>(b.Id==post.CategoryId||b.Children.some(c=>c.Id==post.CategoryId||c.Children.some(cc=>cc.Id==post.CategoryId)))-(a.Id==post.CategoryId||a.Children.some(c=>c.Id==post.CategoryId||c.Children.some(cc=>cc.Id==post.CategoryId))));
-				$("[name='Author']").val(post.Author);
-				$("[name='Email']").val(post.Email);
-				window.interval = setInterval(function () {
-					localStorage.setItem("write-post-draft",JSON.stringify($("#article-form").serializeObject()));
-				},5000);
-			},
-			cancelCallback: function() {
-				window.interval = setInterval(function () {
-					localStorage.setItem("write-post-draft",JSON.stringify($("#article-form").serializeObject()));
-				},5000);
-			}
-		});	
-	} else {
-		window.interval = setInterval(function () {
-			localStorage.setItem("write-post-draft",JSON.stringify($("#article-form").serializeObject()));
-		},5000);
-	}
-};
+        // 递归处理子分类
+        if (category.Children && category.Children.length > 0) {
+          const childCategories = this.flattenCategories(category.Children, fullName)
+          result.push(...childCategories)
+        }
+      }
+
+      return result
+    },
+    async getCategories() {
+      const data = await axios.get("/category/getcategories").then(function (response) {
+        return response.data;
+      });
+      if (!data.Success) {
+        return;
+      }
+
+      this.categories = this.flattenCategories(data.Data.sort((a, b) => (b.Id == 1) - (a.Id == 1)));
+    },
+    submit() {
+      if (this.post.Title.trim().length <= 2 || this.post.Title.trim().length > 128) {
+        VxeUI.modal.notification({
+          content: '文章标题必须在2到128个字符以内!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Author.trim().length <= 1 || this.post.Author.trim().length > 24) {
+        VxeUI.modal.notification({
+          content: '昵称不能少于2个字符或超过24个字符!',
+          status: 'error',
+        });
+        return;
+      }
+      if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(this.post.Email.trim())) {
+        VxeUI.modal.notification({
+          content: '请输入正确的邮箱格式!',
+          status: 'error',
+        });
+        return;
+      }
+      if (this.post.Content.length < 20 || this.post.Content.length > 1000000) {
+        VxeUI.modal.notification({
+          content: '文章内容过短或者超长,请修改后再提交!',
+          status: 'error',
+        });
+        loadingDone();
+        return;
+      }
+      axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/Post/Publish", this.post).then(res => {
+        const data = res.data;
+        if (data.Success) {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'success',
+          });
+          clearInterval(window.interval);
+          localStorage.removeItem("write-post-draft");
+        } else {
+          VxeUI.modal.notification({
+            content: data.Message,
+            status: 'error',
+          });
+        }
+      });
+    },
+    async getcode(email) {
+      VxeUI.modal.notification({
+        content: '正在发送验证码,请稍候...',
+        status: 'info',
+      });
+      const data = await axios.create({
+        headers: {
+          'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+        }
+      }).post("/validate/sendcode", {
+        //__RequestVerificationToken: document.querySelector('input[name="__RequestVerificationToken"]').value,
+        email: email
+      }).then(res => res.data);
+      if (data.Success) {
+        this.disableGetcode = true;
+        VxeUI.modal.notification({
+          content: '验证码发送成功,请注意查收邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!',
+          status: 'success',
+        });
+        localStorage.setItem("user", JSON.stringify({ NickName: this.post.Author, Email: this.post.Email }));
+        var count = 0;
+        var timer = setInterval(() => {
+          count++;
+          this.codeMsg = '重新发送(' + (120 - count) + ')';
+          if (count > 120) {
+            clearInterval(timer);
+            this.disableGetcode = false;
+            this.codeMsg = '重新发送';
+          }
+        }, 1000);
+      } else {
+        VxeUI.modal.notification({
+          content: data.Message,
+          status: 'error',
+        });
+        this.disableGetcode = false;
+      }
+    },
+    search() {
+      window.open("/s?wd=" + this.post.Title);
+    }
+  },
+  created() {
+    if (window.UE) {
+      window.ue = UE.getEditor('editor', {
+        initialFrameWidth: null
+      });
+    }
+    this.getCategories();
+    var user = JSON.parse(localStorage.getItem("user"));
+    if (user) {
+      this.post.Author = user.NickName;
+      this.post.Email = user.Email;
+    }
+    //检查草稿
+    if (localStorage.getItem("write-post-draft")) {
+      VxeUI.modal.confirm({
+        title: '草稿箱',
+        content: '检查到上次有未提交的草稿,是否加载?',
+        mask: false,
+        lockView: false
+      }).then(type => {
+        if (type == 'confirm') {
+          this.post = JSON.parse(localStorage.getItem("write-post-draft"));
+          ue.setContent(this.post.Content);
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("write-post-draft", JSON.stringify(this.post));
+          }, 5000);
+        } else {
+          window.interval = setInterval(() => {
+            this.post.Content = ue.getContent();
+            localStorage.setItem("write-post-draft", JSON.stringify(this.post));
+          }, 5000);
+        }
+      });
+    } else {
+      window.interval = setInterval(() => {
+        this.post.Content = ue.getContent();
+        localStorage.setItem("write-post-draft", JSON.stringify(this.post));
+      }, 5000);
+    }
+  },
+}).use(VxeUI).mount('#publishApp');
+// }

+ 3 - 3
src/Masuit.MyBlogs.Core/wwwroot/UEditorPlus/ueditor.config.front.js

@@ -325,7 +325,7 @@
         // 初始化编辑器宽度,默认 1000
         // ,initialFrameWidth:1000
         // 初始化编辑器高度,默认 320
-        // ,initialFrameHeight:320
+        , initialFrameHeight: 500
 
         // 编辑器初始化结束后,编辑区域是否是只读的,默认是false
         , readonly: false
@@ -536,7 +536,7 @@
         , maxInputCount: 1
 
         // 是否自动长高,默认true
-        , autoHeightEnabled: true
+        , autoHeightEnabled: false
 
         // 是否可以拉伸长高,默认true(当开启时,自动长高失效)
         //,scaleEnabled:false
@@ -548,7 +548,7 @@
         // 是否保持toolbar的位置不动,默认true
         , autoFloatEnabled: true
         // 浮动时工具栏距离浏览器顶部的高度,用于某些具有固定头部的页面
-        , topOffset: 120
+        , topOffset: 80
         // 编辑器底部距离工具栏高度(如果参数大于等于编辑器高度,则设置无效)
         , toolbarTopOffset: 0