Details_Admin.cshtml 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. @using System.Web
  2. @using Masuit.MyBlogs.Core.Common
  3. @using Masuit.MyBlogs.Core.Models.DTO
  4. @using Masuit.MyBlogs.Core.Models.Entity
  5. @using Masuit.MyBlogs.Core.Models.Enum
  6. @using Masuit.MyBlogs.Core.Models.ViewModel
  7. @using Masuit.Tools.Core.Net
  8. @using Masuit.Tools.Systems
  9. @model Masuit.MyBlogs.Core.Models.Entity.Post
  10. @{
  11. ViewBag.Title = Model.Title;
  12. Layout = "~/Views/Shared/_Layout.cshtml";
  13. string[] colors = { "success", "info", "primary", "warning", "danger", "default", "primary" };
  14. UserInfoOutputDto user = Context.Session.Get<UserInfoOutputDto>(SessionKey.UserInfo);
  15. string cid = string.IsNullOrEmpty(Context.Request.Query["cid"]) ? "0" : Context.Request.Query["cid"].ToString();
  16. Advertisement ad = ViewBag.Ads;
  17. }
  18. <style>
  19. #gooey-h {
  20. position: fixed;
  21. bottom: 250px;
  22. right: 0;
  23. z-index: 3;
  24. }
  25. </style>
  26. <link href="~/Assets/layui/css/layui.min.css" rel="stylesheet" />
  27. <link href="~/Assets/gooey/gooey.min.css" rel="stylesheet" />
  28. <link href="~/Assets/jquery.tocify/jquery.tocify.min.css" rel="stylesheet" />
  29. <script src="~/Assets/layui/layui.all.js"></script>
  30. <script src="~/Assets/gooey/gooey.min.js"></script>
  31. <link href="~/Assets/UEditor/third-party/SyntaxHighlighter/styles/shCore.min.css" rel="stylesheet" />
  32. <link href="~/Assets/highlight/css/highlight.css" rel="stylesheet" />
  33. <link href="~/Assets/share/share.css" rel="stylesheet" />
  34. <script src="~/Assets/share/jquery.qrcode.min.js"></script>
  35. <script src="~/Assets/share/jquery.share.min.js"></script>
  36. <div class="container">
  37. <ol class="cd-breadcrumb triangle">
  38. <li>@Html.ActionLink("首页", "Index", "Home")</li>
  39. <li>@Html.ActionLink("文章列表", "Post", "Home")</li>
  40. <li class="current"><em>@ViewBag.Title</em></li>
  41. </ol>
  42. <div class="wrapper-content article">
  43. <div class="ibox">
  44. <div class="ibox-content animated fadeIn">
  45. <main>
  46. <section>
  47. <header class="page-header">
  48. <div class="text-center">
  49. <a>
  50. <h2 class="padding-bot10">
  51. @Model.Title
  52. </h2>
  53. </a>
  54. </div>
  55. <div class="row">
  56. <div class="col-sm-8">
  57. <div class="padding-bot10">
  58. <span class="label label-@colors[new Random().Next() % colors.Length]">
  59. <a asp-controller="Home" asp-action="Author" asp-route-author="@Model.Author">@Model.Author</a>
  60. </span>发表于<span class="text-info">@Model.PostDate.ToString("yyyy-MM-dd HH:mm:ss")</span> |
  61. <span class="label label-@colors[new Random().Next() % colors.Length]">
  62. <a asp-controller="Home" asp-action="Author" asp-route-author="@Model.Modifier">@Model.Modifier</a>
  63. </span>最后修改于<span class="text-success">@Model.ModifyDate.ToString("yyyy-MM-dd HH:mm:ss")</span>
  64. </div>
  65. </div>
  66. @{
  67. if (!string.IsNullOrEmpty(Model.Label))
  68. {
  69. <div class="pull-right margin-right20">
  70. <div>
  71. @foreach (string s in Model.Label.Split(',', ',', ' '))
  72. {
  73. if (!string.IsNullOrEmpty(s))
  74. {
  75. <a asp-controller="Home" asp-action="Tag" asp-route-id="@s">
  76. <span class="label label-@colors[new Random().Next() % colors.Length]">@s</span>
  77. </a>
  78. }
  79. }
  80. </div>
  81. </div>
  82. }
  83. }
  84. </div>
  85. <div class="row">
  86. <div class="col-md-12 line-height24">
  87. 分类:<i class="icon-map-pin"></i>@Html.ActionLink(Model.Category.Name, "Category", "Home", new { id = Model.CategoryId }, new { @class = "label label-" + colors[new Random().Next() % colors.Length] }) | 评论总数:<span class="text-danger">@Model.Comment.Count</span>条 | 热度:<span class="text-danger">@Model.TotalViewCount</span>℃ | 状态:@Model.Status.GetDisplay()
  88. @if (Model.Seminar.Any())
  89. {
  90. <span> | 所属专题:</span>
  91. var seminars = Model.Seminar;
  92. foreach (var s in seminars)
  93. {
  94. @Html.ActionLink(s.Seminar.Title, "Index", "Seminar", new { id = s.SeminarId }, new { @class = "label label-" + colors[new Random().Next() % colors.Length] })<text> </text>
  95. }
  96. }
  97. <div class="pull-right margin-right20">
  98. @Html.ActionLink("我要编辑", "PushMerge", "Post", new { id = Model.Id }, new { @class = "btn btn-danger" })
  99. </div>
  100. </div>
  101. </div>
  102. </header>
  103. <article class="article" id="article">
  104. @Html.Raw(Model.Content)
  105. @if (!string.IsNullOrEmpty(Model.ProtectContent))
  106. {
  107. <div class="row protected">
  108. @Html.Raw(Model.ProtectContent)
  109. </div>
  110. }
  111. </article>
  112. <h3>分享到:</h3>
  113. <div class="social-share"></div>
  114. <div id="cyReward" role="cylabs" data-use="reward"></div>
  115. </section>
  116. </main>
  117. @if (ad != null)
  118. {
  119. <section class="protected">
  120. <a asp-controller="Advertisement" asp-action="Redirect" asp-route-id="@ad.Id" target="_blank">
  121. <h3>
  122. @ad.Title
  123. <span class="text-red">[推广]</span>
  124. </h3>
  125. <div class="row padding-bot10">
  126. @{
  127. string imgSrc = ad.ThumbImgUrl;
  128. if (!string.IsNullOrEmpty(imgSrc))
  129. {
  130. <div class="col-md-3">
  131. <img class="img-thumbnail img-responsive thumb" data-original="@imgSrc" alt="@ad.Title" title="@ad.Title ">
  132. </div>
  133. }
  134. }
  135. <div class="col-md-@(string.IsNullOrEmpty(imgSrc) ? 12 : 9)">
  136. <p>
  137. @ad.Description
  138. </p>
  139. </div>
  140. </div>
  141. </a>
  142. </section>
  143. }
  144. <section class="wow fadeIn row padding-top40 padding-bot20">
  145. <div class="col-xs-6">
  146. <div class="btn-group">
  147. <button type="button" id="voteup" class="btn btn-success btn-lg">
  148. <i class="icon-thumbsup"></i><span>@Model.VoteUpCount</span>
  149. </button>
  150. <button type="button" id="votedown" class="btn btn-danger btn-lg">
  151. <i class="icon-thumbsdown"></i><span>@Model.VoteDownCount</span>
  152. </button>
  153. </div>
  154. </div>
  155. <div class="col-xs-6 text-right">
  156. <div class="btn-group">
  157. <button type="button" id="donate" class="btn btn-@colors[new Random().Next() % colors.Length] btn-lg">
  158. <i class="icon-coin-yen"></i><span>支持站长</span>
  159. </button>
  160. </div>
  161. </div>
  162. </section>
  163. <section class="wow row size16 animated fadeIn">
  164. <div class="col-xs-6">
  165. 上一篇:
  166. @{
  167. PostModelBase prev = ViewBag.Prev;
  168. if (prev != null)
  169. {
  170. @Html.ActionLink(prev.Title, "Details", "Post", new { id = prev.Id }, null)
  171. }
  172. else
  173. {
  174. <a>没有了</a>
  175. }
  176. }
  177. </div>
  178. <div class="col-xs-6 text-right">
  179. 下一篇:
  180. @{
  181. PostModelBase next = ViewBag.Next;
  182. if (next != null)
  183. {
  184. @Html.ActionLink(next.Title, "Details", "Post", new { id = next.Id }, null)
  185. }
  186. else
  187. {
  188. <a>没有了</a>
  189. }
  190. }
  191. </div>
  192. </section>
  193. @if (Model.PostHistoryVersion.Any())
  194. {
  195. <section class="wow margintop20 animated fadeIn">
  196. <h3>文章历史版本:</h3>
  197. <p>
  198. 修改次数:@Model.PostHistoryVersion.Count 次
  199. @Html.ActionLink("查看历史版本", "History", "Post", new { id = Model.Id }, null)
  200. </p>
  201. </section>
  202. }
  203. <section class="wow padding-bot20 animated fadeIn">
  204. <h3>版权声明:</h3>
  205. <p class="text-danger size16">
  206. 本文仅用于学习、研究和交流目的,欢迎非商业性质转载。本文链接:<a href="@(Context.Request.Scheme + "://" +Context.Request.Host+Context.Request.Path)">@(HttpUtility.UrlDecode(Context.Request.Scheme + "://" + Context.Request.Host + Context.Request.Path))</a>。
  207. @Html.Raw(CommonHelper.SystemSettings["Disclaimer"])
  208. </p>
  209. </section>
  210. @{
  211. var posts = Model.Category.Post.Where(p => p.Status == Status.Pended && p.Id != Model.Id).OrderBy(p => Guid.NewGuid()).ToList();
  212. int count = posts.Count >= 10 ? 10 : posts.Count;
  213. if (posts.Any())
  214. {
  215. <section class="wow margintop20 animated fadeIn">
  216. <h3>相关推荐:</h3>
  217. <table class="table table-condensed size16">
  218. @for (int i = 1; i < count; i += 2)
  219. {
  220. <tr>
  221. <td>@Html.ActionLink(posts[i - 1].Title, "Details", "Post", new { id = posts[i - 1].Id }, null)</td>
  222. <td>@Html.ActionLink(posts[i].Title, "Details", "Post", new { id = posts[i].Id }, null)</td>
  223. </tr>
  224. }
  225. </table>
  226. </section>
  227. }
  228. }
  229. <hr>
  230. <section class="wow row animated fadeIn">
  231. <div class="col-lg-12">
  232. <h3>评论区:</h3>
  233. <form class="form-horizontal animated pulse" id="comment" method="post">
  234. @Html.AntiForgeryToken()
  235. <input type="hidden" name="PostId" value="@Model.Id" />
  236. <input type="hidden" id="OperatingSystem" name="OperatingSystem" />
  237. <input type="hidden" name="Browser" id="Browser" />
  238. <input type="hidden" value="@user.NickName" class="form-control" name="NickName" id="name">
  239. <input type="hidden" value="@user.Email" class="form-control" name="Email" id="email">
  240. <input type="hidden" value="@user.QQorWechat" class="form-control" name="QQorWechat" id="chat">
  241. <div class="form-group overlay animated fadeInDown" style="margin-bottom: 0px !important;">
  242. <textarea class="layui-textarea" id="layedit" name="Content" style="height: 100px"></textarea>
  243. </div>
  244. <div class="form-group">
  245. <div class="col-xs-12">
  246. <button type="submit" class="btn btn-info btn-lg">提交</button>
  247. <a class="text-red">评论框可粘贴网络图片</a>
  248. </div>
  249. </div>
  250. </form>
  251. <ul class="wow media-list"></ul>
  252. @if (Model.Comment.Any(c => c.Status == Status.Pended))
  253. {
  254. <div class="row">
  255. <div class="col-md-12 text-center">
  256. <div id="pageToolbar"></div>
  257. </div>
  258. </div>
  259. }
  260. else
  261. {
  262. <h4>还没有评论哦,赶紧来写评论吧</h4>
  263. }
  264. </div>
  265. </section>
  266. </div>
  267. </div>
  268. </div>
  269. </div>
  270. <div style="position: absolute; left: -20000px; bottom: 0;">
  271. <div id="reply" class="container-fluid">
  272. <form class="form-horizontal" id="reply-form" method="post">
  273. @Html.AntiForgeryToken()
  274. <input type="hidden" name="PostId" id="postId" value="@Model.Id" />
  275. <input type="hidden" name="OperatingSystem" id="OperatingSystem2" />
  276. <input type="hidden" name="Browser" id="Browser2" />
  277. <input type="hidden" value="@user.NickName" class="form-control" name="NickName" id="name2">
  278. <input type="hidden" value="@user.Email" class="form-control" name="Email" id="email2">
  279. <input type="hidden" value="@user.QQorWechat" class="form-control" name="QQorWechat" id="chat2">
  280. <input type="hidden" value="" id="uid" name="ParentId" />
  281. <div class="form-group overlay animated fadeInDown">
  282. <textarea class="layui-textarea" id="layedit2" name="Content" style="height: 80px"></textarea>
  283. </div>
  284. <div class="form-group">
  285. <div class="col-xs-12">
  286. <div class="btn-group">
  287. <button type="submit" class="btn btn-info btn-lg">
  288. 提交回复
  289. </button>
  290. <button type="button" class="btn-cancel btn btn-danger btn-lg">
  291. 取消回复
  292. </button>
  293. </div>
  294. </div>
  295. </div>
  296. </form>
  297. </div>
  298. </div>
  299. <nav id="gooey-h" style="max-height: 100px;">
  300. <input type="checkbox" class="menu-open" name="menu-open2" id="menu-open2" />
  301. <label class="open-button" for="menu-open2">
  302. <span class="burger burger-1"></span>
  303. <span class="burger burger-2"></span>
  304. <span class="burger burger-3"></span>
  305. </label>
  306. <a class="gooey-menu-item" id="pin"> <i class="icon icon-pushpin"></i></a>
  307. @{
  308. if (Model.Status == Status.Pending)
  309. {
  310. <a class="gooey-menu-item" id="pass"> <i class="icon icon-checkmark"></i></a>
  311. }
  312. }
  313. <a asp-controller="Dashboard" asp-action="Index" asp-fragment="/post/[email protected]" class="gooey-menu-item" target="_blank"> <i class="icon icon-pencil"></i></a>
  314. <a class="gooey-menu-item" id="del"> <i class="icon icon-bin"></i></a>
  315. </nav>
  316. <script src="https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min.js"></script>
  317. <script src="~/Assets/UEditor/third-party/SyntaxHighlighter/scripts/shCore.min.js"></script>
  318. <script src="~/Assets/UEditor/third-party/SyntaxHighlighter/scripts/bundle.min.js"></script>
  319. <script src="~/Assets/jquery.tocify/jquery.tocify.js"></script>
  320. <script src="~/Scripts/global/article.js"></script>
  321. <script src="~/Assets/highlight/js/highlight.js"></script>
  322. <script>
  323. function getcomments() {
  324. $.post("/comment/getcomments", {
  325. id: $("#postId").val(),
  326. page: 1,
  327. size: 10,
  328. cid: @cid
  329. }, (data) => {
  330. data = data.Data;
  331. document.querySelector(".media-list").innerHTML = loadParentComments(data);
  332. bindReplyBtn();
  333. commentVoteBind(); //评论投票
  334. });
  335. }
  336. window.onload = function() {
  337. var keywords = @Html.Raw(ViewData["keywords"] ?? "[]");
  338. for (var i = 0; i < keywords.length; i++) {
  339. $("#article").highlight(keywords[i]);
  340. }
  341. loading();
  342. $('#pageToolbar').Paging({ //异步加载评论
  343. pagesize: 10,
  344. count: @Model.Comment.Count(c =>c.ParentId==0&& c.Status==Status.Pended),
  345. toolbar: true,
  346. callback: function(page, size, count) {
  347. $.post("/comment/getcomments", {
  348. id: @Model.Id,
  349. page: page,
  350. size: size
  351. }, (data) => {
  352. data = data.Data;
  353. if (data) {
  354. document.querySelector(".media-list").innerHTML = loadParentComments(data);
  355. bindReplyBtn();
  356. commentVoteBind(); //评论投票
  357. }
  358. });
  359. }
  360. });
  361. $("#gooey-h").gooeymenu({
  362. bgColor: "#681ddf",
  363. contentColor: "white",
  364. style: "circle",
  365. horizontal: {
  366. menuItemPosition: "glue"
  367. },
  368. vertical: {
  369. menuItemPosition: "spaced",
  370. direction: "up"
  371. },
  372. circle: {
  373. radius: 85
  374. },
  375. margin: "small",
  376. size: 80,
  377. bounce: true,
  378. bounceLength: "small",
  379. transitionStep: 100,
  380. hover: "#2d1d89"
  381. });
  382. $("#gooey-h").insertAfter($("body"));
  383. $("#del").on("click", function (e) {
  384. swal({
  385. title: "确认删除这篇文章吗?",
  386. text: '@Model.Title',
  387. showCancelButton: true,
  388. confirmButtonColor: "#DD6B55",
  389. confirmButtonText: "确定",
  390. cancelButtonText: "取消",
  391. showLoaderOnConfirm: true,
  392. animation: true,
  393. allowOutsideClick: false
  394. }).then(function () {
  395. $.post("/post/delete", {
  396. id: @Model.Id
  397. }, function (data) {
  398. window.notie.alert({
  399. type: 1,
  400. text: data.Message,
  401. time: 4
  402. });
  403. });
  404. }, function () {
  405. });
  406. });
  407. $("#pass").on("click", function (e) {
  408. $.post("/post/pass", { id:@Model.Id}, function (data) {
  409. window.notie.alert({
  410. type: 1,
  411. text: data.Message,
  412. time: 4
  413. });
  414. });
  415. });
  416. $("#pin").on("click", function (e) {
  417. $.post("/post/Fixtop", {
  418. id: @Model.Id
  419. }, function (data) {
  420. window.notie.alert({
  421. type: 1,
  422. text: data.Message,
  423. time: 4
  424. });
  425. });
  426. });
  427. loadingDone();
  428. };
  429. //递归加载评论
  430. //加载父楼层
  431. function loadParentComments(data) {
  432. loading();
  433. var html = '';
  434. if (data) {
  435. var rows = Enumerable.From(data.rows).Where(c => c.ParentId === 0).ToArray();
  436. var page = data.page;
  437. var size = data.size;
  438. var maxPage = Math.ceil(data.total / size);
  439. page = page > maxPage ? maxPage : page;
  440. page = page < 1 ? 1 : page;
  441. var startfloor = data.parentTotal - (page - 1) * size;
  442. for (let i = 0; i < rows.length; i++) {
  443. html += `<li class="msg-list media animated fadeInRight" id='${rows[i].Id}'>
  444. <div class="media-body">
  445. <article class="panel panel-info">
  446. <header class="panel-heading">${startfloor}# ${rows[i].IsMaster ? `<i class="icon icon-user"></i>` : ""}${rows[i].NickName}${rows[i].IsMaster ? `(管理员)` : ""}
  447. <span class="pull-right" style="font-size: 10px;">${rows[i].Status == 4 ? `<a class="label label-success" onclick="pass(${rows[i].Id})">通过</a> |` : ""} <a class="label label-danger" onclick="del(${rows[i].Id})">删除</a> | ${rows[i].CommentDate}<span class="hidden-sm hidden-xs"> | ${GetOperatingSystem(rows[i].OperatingSystem) + " | " + GetBrowser(rows[i].Browser)}</span></span>
  448. </header>
  449. <div class="panel-body">
  450. ${rows[i].Content}
  451. <span class="cmvote label label-info" data-id="${rows[i].Id}"><i class="icon-thumbsup"></i>(<span class="count">${rows[i].VoteCount}</span>)</span>
  452. <a class="label label-info" href="?uid=${rows[i].Id}"><i class="icon-comment"></i></a><div class="margin-top10"></div>
  453. <div class="pull-left">
  454. <span class="label label-success">${rows[i].IP}</span>
  455. <span class="label label-primary">${rows[i].Location}</span>
  456. </div>
  457. <div class="pull-right">
  458. <span class="label label-success">${rows[i].Email}</span>
  459. <span class="label label-warning">${rows[i].QQorWechat}</span>
  460. </div><br/>
  461. ${loadComments(data.rows, Enumerable.From(data.rows).Where(c => c.ParentId === rows[i].Id).OrderBy(c => c.CommentDate).ToArray(), startfloor--)}
  462. </div>
  463. </article>
  464. </div>
  465. </li>`;
  466. }
  467. }
  468. loadingDone();
  469. return html;
  470. }
  471. //加载子楼层
  472. function loadComments(data, comments, root, depth = 0) {
  473. var colors = ["info", "success", "primary", "warning", "danger"];
  474. var floor = 1;
  475. depth++;
  476. var html = '';
  477. Enumerable.From(comments).ForEach((item, index) => {
  478. var color = colors[depth%5];
  479. html += `<article id="${item.Id}" class="panel panel-${color}">
  480. <div class="panel-heading">
  481. ${depth}-${floor++}# ${item.IsMaster ?`<i class="icon icon-user"></i>`:""}${item.NickName}${item.IsMaster ?`(管理员)`:""}
  482. <span class="pull-right" style="font-size: 10px;">${item.Status == 4 ? `<a class="label label-success" onclick="pass(${item.Id})">通过</a> |`:""} <a class="label label-danger" onclick="del(${item.Id})">删除</a> | ${item.CommentDate}<span class="hidden-sm hidden-xs"> | ${GetOperatingSystem(item.OperatingSystem) + " | " + GetBrowser(item.Browser)}</span></span>
  483. </div>
  484. <div class="panel-body">
  485. ${item.Content}
  486. <span class="cmvote label label-${color}" data-id="${item.Id}"><i class="icon-thumbsup"></i>(<span class="count">${item.VoteCount}</span>)</span>
  487. <a class="label label-${color}" href="?uid=${item.Id}"><i class="icon-comment"></i></a>
  488. <div class="margin-top10"></div>
  489. <div class="pull-left">
  490. <span class="label label-success">${item.IP}</span>
  491. <span class="label label-primary">${item.Location}</span>
  492. </div>
  493. <div class="pull-right">
  494. <span class="label label-success">${item.Email}</span>
  495. <span class="label label-primary">${item.QQorWechat}</span>
  496. </div><br/>
  497. ${loadComments(data, Enumerable.From(data).Where(c => c.ParentId === item.Id).OrderBy(c => c.CommentDate), root, depth)}
  498. </div>
  499. </article>`;
  500. });
  501. return html;
  502. }
  503. function pass(id) {
  504. $.post("/comment/pass", { id: id }, function (res) {
  505. swal(res.Message, "", res.Success ? "success" : "error");
  506. getcomments();
  507. });
  508. }
  509. function del(id) {
  510. swal({
  511. title: '确定删除这条评论吗?',
  512. type: 'warning',
  513. showCancelButton: true,
  514. confirmButtonColor: '#3085d6',
  515. cancelButtonColor: '#d33',
  516. confirmButtonText: '确定',
  517. cancelButtonText: '取消',
  518. preConfirm: function() {
  519. return new Promise(function (resolve) {
  520. $.post("/comment/delete", {
  521. id: id
  522. }, function (res) {
  523. resolve(res);
  524. });
  525. });
  526. },
  527. allowOutsideClick: false
  528. }).then(function(res) {
  529. swal(res.Message, "", res.Success ? "success" : "error");
  530. getcomments();
  531. });
  532. }
  533. </script>