Applicants: auto-tags + deep search w/ highlight; never delete (archive instead)
- Tags: parser extracts cert/skill keywords (mmt, ICU/CCU, دیالیز, اتاق عمل, اورژانس, مسئول فنی, پروانهدار…) + role + city into TalentListing.Tags (+ migration); shown as chips on cards. - Deep search on /Talent: «جستجوی عمیق» box does Postgres ILIKE across tags, description, person, area, role, city (every term must match); matches are highlighted with <mark> via SearchHighlight. - Never delete: ShiftStatus.Archived + the admin «بایگانی گروهی» action now ARCHIVES aggregated posts (hidden from site, kept in DB) and leaves the raw crawl rows intact — a permanent archive for future analytics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
|
||||
namespace JobsMedical.Web.Services;
|
||||
|
||||
/// <summary>Wraps query terms in <mark> for result highlighting (HTML-safe).</summary>
|
||||
public static class SearchHighlight
|
||||
{
|
||||
public static HtmlString Mark(string? text, string? query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return HtmlString.Empty;
|
||||
var encoded = WebUtility.HtmlEncode(text);
|
||||
if (string.IsNullOrWhiteSpace(query)) return new HtmlString(encoded);
|
||||
|
||||
var terms = query.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Where(t => t.Length >= 2)
|
||||
.Select(t => Regex.Escape(WebUtility.HtmlEncode(t)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
if (terms.Count == 0) return new HtmlString(encoded);
|
||||
|
||||
var pattern = string.Join("|", terms);
|
||||
var marked = Regex.Replace(encoded, pattern, m => $"<mark>{m.Value}</mark>", RegexOptions.IgnoreCase);
|
||||
return new HtmlString(marked);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user