[Ingest] Full results page (all statuses) + inline quick-reject in queue
New /Admin/Ingested page lists every crawled item with its outcome, filterable by status (همه/در صف/پرچمخورده/منتشرشده/ردشده) with per-status counts and a link to the published shift or the review page. Linked from the run-history header and the admin panel nav. Plus an inline ✕رد (quick-discard) button on each queue/flagged row so admins can audit without opening the review page; full accept/reject stays on /Admin/Review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
@page
|
||||
@model JobsMedical.Web.Pages.Admin.IngestedModel
|
||||
@{
|
||||
ViewData["Title"] = "نتایج جمعآوری";
|
||||
string P(int n) => JalaliDate.ToPersianDigits(n.ToString());
|
||||
int C(JobsMedical.Web.Models.RawListingStatus s) => Model.Counts.GetValueOrDefault(s);
|
||||
string Pill(string key, string label, int count) =>
|
||||
$"<a class=\"ing-pill {(Model.Status == key || (Model.Status is null && key == "all") ? "active" : "")}\" href=\"?status={key}\">{label} ({P(count)})</a>";
|
||||
}
|
||||
|
||||
<partial name="_PanelNav" />
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>نتایج جمعآوری</h1>
|
||||
<p class="muted"><a asp-page="/Admin/Index">← صف بررسی</a> — همهی آگهیهای جمعآوریشده و وضعیت هرکدام.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container section">
|
||||
<div class="ing-filters">
|
||||
@Html.Raw(Pill("all", "همه", Model.Counts.Values.Sum()))
|
||||
@Html.Raw(Pill("new", "در صف", C(JobsMedical.Web.Models.RawListingStatus.New)))
|
||||
@Html.Raw(Pill("flagged", "پرچمخورده", C(JobsMedical.Web.Models.RawListingStatus.Flagged)))
|
||||
@Html.Raw(Pill("published", "منتشرشده", C(JobsMedical.Web.Models.RawListingStatus.Normalized)))
|
||||
@Html.Raw(Pill("discarded", "ردشده/اسپم", C(JobsMedical.Web.Models.RawListingStatus.Discarded)))
|
||||
</div>
|
||||
|
||||
<p class="muted" style="font-size:13px;">@P(Model.Total) نتیجه (نمایش حداکثر ۲۰۰ مورد اخیر).</p>
|
||||
|
||||
@if (Model.Items.Count == 0)
|
||||
{
|
||||
<div class="card empty-state">موردی با این فیلتر نیست.</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var r in Model.Items)
|
||||
{
|
||||
var (cls, label) = r.Status switch
|
||||
{
|
||||
JobsMedical.Web.Models.RawListingStatus.New => ("badge-day", "در صف"),
|
||||
JobsMedical.Web.Models.RawListingStatus.Flagged => ("badge-type", "پرچمخورده"),
|
||||
JobsMedical.Web.Models.RawListingStatus.Normalized => ("badge-verified", "منتشر شد"),
|
||||
_ => ("badge-gender", "رد شد"),
|
||||
};
|
||||
<div class="card card-pad" style="margin-bottom:10px;">
|
||||
<div class="row" style="display:flex; justify-content:space-between; align-items:center; gap:8px; flex-wrap:wrap;">
|
||||
<strong>@r.SourceChannel</strong>
|
||||
<span style="display:flex; gap:6px; align-items:center;">
|
||||
<span class="badge @cls">@label</span>
|
||||
<span class="badge badge-type">اطمینان @P(r.Confidence)٪</span>
|
||||
<span class="muted" style="font-size:12px;">@JalaliDate.ToLongDate(DateOnly.FromDateTime(r.FetchedAt))</span>
|
||||
</span>
|
||||
</div>
|
||||
<p style="margin:8px 0; white-space:pre-wrap; font-size:13.5px;">@(r.RawText.Length > 320 ? r.RawText.Substring(0,320) + "…" : r.RawText)</p>
|
||||
@if (!string.IsNullOrEmpty(r.ValidationNotes)) { <p class="muted" style="font-size:12px; margin:0 0 6px;">⚠ @r.ValidationNotes</p> }
|
||||
@if (r.Status == JobsMedical.Web.Models.RawListingStatus.New || r.Status == JobsMedical.Web.Models.RawListingStatus.Flagged)
|
||||
{
|
||||
<a class="btn btn-outline" style="padding:4px 12px; font-size:13px;" asp-page="/Admin/Review" asp-route-id="@r.Id">بررسی و انتشار ←</a>
|
||||
}
|
||||
else if (r.LinkedShiftId is int sid)
|
||||
{
|
||||
<a class="btn btn-outline" style="padding:4px 12px; font-size:13px;" asp-page="/Shifts/Details" asp-route-id="@sid" target="_blank">مشاهده آگهی منتشرشده</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
Reference in New Issue
Block a user