@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>
|