Add «آماده به کار» (talent) listing type — workers offering themselves
Adds a third listing kind alongside Shift/Job for healthcare staff who advertise their own availability (very common in Iranian medical channels, e.g. "دندانپزشک آماده همکاری… ۵۰٪ تسویه"). These have no facility; the contact phone is the key field. - Model: TalentListing (role, person name, years, licensed, city/district, area note, availability, gender, comp, phone) + ListingKind.Talent + RawListing.LinkedTalentId + DbSet/relations/indexes + EF migration. - Parser: detect آمادهبهکار/جویای کار → Kind=Talent; extract person name, years of experience, licensed flag, area («منطقه ۱»), phone. Facility name extraction now skipped for talent. - Validator: talent path scores role + phone + medical (no facility/pay required). - Ingestion auto-publish: creates a TalentListing for talent kind. - Review (manual publish): Talent option + talent fields; publishes a TalentListing without a facility. Shift/Job facility now falls back to a shared «نامشخص / ثبت نشده» record when the ad names none — publishing never fails on a missing facility. - Browse /Talent (indexable, filters: city/district/role/gender), details /Talent/Details (noindex — personal contact, tel: call button), _TalentCard, badge-talent, nav link, home section. - Sitemap includes /Talent; robots disallows /Talent/Details. Archiver expires stale talent listings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,7 @@
|
||||
<a asp-page="/Index" class="@(path == "/" ? "active" : null)">خانه</a>
|
||||
<a asp-page="/Shifts/Index" data-tour="shifts" class="@(path.StartsWith("/Shifts") ? "active" : null)">شیفتها</a>
|
||||
<a asp-page="/Jobs/Index" data-tour="jobs" class="@(path.StartsWith("/Jobs") ? "active" : null)">استخدام</a>
|
||||
<a asp-page="/Talent/Index" class="@(path.StartsWith("/Talent") ? "active" : null)">آماده به کار</a>
|
||||
<a asp-page="/Facilities/Index" class="@(path.StartsWith("/Facilities") ? "active" : null)">مراکز درمانی</a>
|
||||
<a asp-page="/Calendar/Index" class="@(path.StartsWith("/Calendar") ? "active" : null)">تقویم هفتگی</a>
|
||||
</nav>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
@model JobsMedical.Web.Models.TalentListing
|
||||
@{
|
||||
string comp;
|
||||
if (Model.PayType == JobsMedical.Web.Models.PayType.Percentage && Model.SharePercent is int sp)
|
||||
comp = $"{JalaliDate.ToPersianDigits(sp.ToString())}٪ سهم درآمد";
|
||||
else if (Model.PayAmount is long pa && pa > 0)
|
||||
comp = JalaliDate.Toman(pa) + " مدنظر";
|
||||
else
|
||||
comp = "توافقی";
|
||||
|
||||
var heading = string.IsNullOrWhiteSpace(Model.PersonName)
|
||||
? (Model.Role?.Name ?? "آماده به کار")
|
||||
: Model.PersonName!;
|
||||
var area = Model.District?.Name ?? Model.AreaNote;
|
||||
}
|
||||
<a class="card card-pad shift-card" asp-page="/Talent/Details" asp-route-id="@Model.Id">
|
||||
<div class="row" style="justify-content: space-between;">
|
||||
<span class="facility">@heading</span>
|
||||
<span class="badge badge-talent">آماده به کار</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
@if (Model.Role is not null)
|
||||
{
|
||||
<span class="badge badge-type">@Model.Role.Name</span>
|
||||
}
|
||||
@if (Model.YearsExperience is int yrs && yrs > 0)
|
||||
{
|
||||
<span class="badge badge-day">@JalaliDate.ToPersianDigits(yrs.ToString()) سال سابقه</span>
|
||||
}
|
||||
@if (Model.IsLicensed)
|
||||
{
|
||||
<span class="badge badge-verified">پروانهدار</span>
|
||||
}
|
||||
@if (Model.Gender != JobsMedical.Web.Models.Gender.Any)
|
||||
{
|
||||
<span class="badge badge-gender">@JalaliDate.GenderLabel(Model.Gender)</span>
|
||||
}
|
||||
</div>
|
||||
<div class="row">📍 @Model.City?.Name@(area is not null ? "، " + area : "")</div>
|
||||
<div class="foot">
|
||||
<span class="pay">@comp</span>
|
||||
<span class="btn btn-outline" style="padding: 6px 14px;">مشاهده و تماس</span>
|
||||
</div>
|
||||
</a>
|
||||
Reference in New Issue
Block a user