更新说明文档
大石头 authored at 2022-04-16 15:30:05
3.46 KiB
YuQue
@model NewLife.YuqueWeb.Models.BookIndexModel
@using NewLife.YuqueWeb.Entity
@using NewLife.YuqueWeb.Models
@using System.Text.RegularExpressions
@using PageModel=NewLife.YuqueWeb.Models.PageModel;
@{
    Layout = "~/Views/Shared/_Layout_yq.cshtml";

    // ViewBag 为 dynamic,必须显式类型化,否则后续 Regex 重载解析会按动态调度导致 lambda 无法绑定
    String key = ViewBag.Key + "";
    var cat = Model.Book;
    var infos = Model.Documents;

    // 分页 URL:全局 /search-{key}-pageIndex,分类内 /{code}-{key}-pageIndex
    var pageUrl = cat == null ? "/search-" + key + "-pageIndex" : "/" + cat.Code + "-" + key + "-pageIndex";
    var page = new PageModel { Page = Model.Page, Url = pageUrl };

    // 关键词高亮:空格拆为多词逐词高亮,各词转义后以 | 联合成单一正则一次替换(避免嵌套 <mark>);兼容全角空格
    // 先 HTML 编码再正则替换,避免 XSS(WebUtility 静态方法避免 Razor 动态调用问题)
    var _sb = new System.Text.StringBuilder();
    foreach (var _w in key.Replace('\u3000', ' ').Split(' ', StringSplitOptions.RemoveEmptyEntries))
    {
        if (_sb.Length > 0) _sb.Append('|');
        _sb.Append(Regex.Escape(_w));
    }
    String pattern = _sb.ToString();
    String Highlight(String text)
    {
        if (pattern.IsNullOrEmpty() || text.IsNullOrEmpty()) return text;
        var encoded = System.Net.WebUtility.HtmlEncode(text);
        return Regex.Replace(encoded, pattern, m => "<mark>" + m.Value + "</mark>", RegexOptions.IgnoreCase);
    }
}
@* ===== 搜索区 ===== *@
<section class="search-hero">
    <div class="container">
        @* data-action 让 site.js 拼 /search-{key} 或 /{code}-{key} 路由 *@
        <form class="search-box-lg" data-action="@(cat == null ? "/search-" : "/" + cat.Code + "-")">
            <span class="icon">
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
            </span>
            <input type="text" name="key" value="@key" placeholder="搜索文章标题、摘要与正文…" aria-label="搜索">
            <button class="btn btn-primary" type="submit">搜索</button>
        </form>
    </div>
</section>

@* ===== 搜索结果 ===== *@
<div class="container">
    <div class="search-result">
        <div class="search-result-count">共找到 <strong>@Model.Page.TotalCount</strong> 条关于 "<strong>@key</strong>" 的结果</div>

        @if (infos.Count == 0)
        {
            <div class="search-empty">
                <div class="se-icon">🔍</div>
                <h3>未找到相关内容</h3>
                <p>没有找到与"<strong>@key</strong>"相关的文章,建议更换关键词,或尝试更短的关键词。</p>
            </div>
        }
        else
        {
            @foreach (var doc in infos)
            {
                <div class="search-result-item">
                    <a href="/@doc.BookCode/@doc.Code"><div class="sr-title">@Html.Raw(Highlight(doc.Title))</div></a>
                    <div class="sr-desc">@Html.Raw(Highlight(doc.Summary))</div>
                    <div class="sr-meta">@doc.BookName · @(doc.PublishTime.Year > 2000 ? doc.PublishTime.ToString("yyyy-MM-dd") : "") · 浏览 @doc.TotalHits.ToString("n0")</div>
                </div>
            }

            @await Html.PartialAsync("_Pager", page)
        }
    </div>
</div>