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:
@@ -46,9 +46,10 @@
|
||||
<select name="Kind" id="kindSelect">
|
||||
<option value="0" selected="@(Model.Kind == JobsMedical.Web.Models.ListingKind.Shift)">شیفت</option>
|
||||
<option value="1" selected="@(Model.Kind == JobsMedical.Web.Models.ListingKind.Job)">استخدام</option>
|
||||
<option value="2" selected="@(Model.Kind == JobsMedical.Web.Models.ListingKind.Talent)">آماده به کار (معرفی نیرو)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<div class="filter-group" id="facilityGroup">
|
||||
<label>مرکز درمانی</label>
|
||||
<select name="FacilityId">
|
||||
<option value="0" selected="@(Model.FacilityId == 0)">— انتخاب نشده —</option>
|
||||
@@ -123,6 +124,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="talentFields" style="display:none;">
|
||||
<div class="filter-group">
|
||||
<label>نام فرد (اختیاری)</label>
|
||||
<input type="text" name="PersonName" value="@Model.PersonName" placeholder="مثلاً دکتر سپیده علیزاده" />
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label>شهر</label>
|
||||
<select name="TalentCityId">
|
||||
@foreach (var c in Model.Cities)
|
||||
{
|
||||
<option value="@c.Id" selected="@(Model.TalentCityId == c.Id)">@c.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-group" style="display:flex; gap:8px;">
|
||||
<div style="flex:1;"><label>سابقه (سال)</label><input type="number" name="YearsExperience" value="@Model.YearsExperience" min="0" max="60" dir="ltr" /></div>
|
||||
<div style="flex:1;"><label>محدوده کاری</label><input type="text" name="AreaNote" value="@Model.AreaNote" placeholder="مثلاً فقط منطقه ۱" /></div>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label>شماره تماس</label>
|
||||
<input type="text" name="Phone" value="@Model.Phone" placeholder="۰۹۱۲…" dir="ltr" />
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label style="display:flex; align-items:center; gap:8px; font-weight:600;">
|
||||
<input type="checkbox" name="IsLicensed" value="true" style="width:auto;" checked="@Model.IsLicensed" /> پروانهدار
|
||||
</label>
|
||||
</div>
|
||||
<div class="filter-group" style="display:flex; gap:8px;">
|
||||
<div style="flex:1;"><label>دستمزد مدنظر (تومان)</label><input type="number" name="PayAmount" value="@Model.PayAmount" dir="ltr" /></div>
|
||||
<div style="flex:1;"><label>یا سهم درآمد (٪)</label><input type="number" name="SharePercent" value="@Model.SharePercent" min="1" max="100" dir="ltr" /></div>
|
||||
</div>
|
||||
<p class="muted" style="font-size:11px; margin:4px 0 0;">برای «آماده به کار» نیازی به مرکز نیست؛ شماره تماس مهمترین فیلد است.</p>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label style="display:flex; align-items:center; gap:8px; font-weight:600;">
|
||||
<input type="checkbox" name="Negotiable" value="true" style="width:auto;" checked="@Model.Negotiable" /> توافقی
|
||||
@@ -143,10 +178,20 @@
|
||||
@section Scripts {
|
||||
<script>
|
||||
var kind = document.getElementById('kindSelect');
|
||||
var facilityGroup = document.getElementById('facilityGroup');
|
||||
// Show one section and DISABLE the hidden ones so duplicate-named inputs
|
||||
// (PayAmount/SharePercent appear in both shift and talent) aren't submitted.
|
||||
function setSection(el, on) {
|
||||
if (!el) return;
|
||||
el.style.display = on ? 'block' : 'none';
|
||||
el.querySelectorAll('input,select,textarea').forEach(function (i) { i.disabled = !on; });
|
||||
}
|
||||
function toggleKind() {
|
||||
var isJob = kind.value === '1';
|
||||
document.getElementById('jobFields').style.display = isJob ? 'block' : 'none';
|
||||
document.getElementById('shiftFields').style.display = isJob ? 'none' : 'block';
|
||||
var v = kind.value;
|
||||
setSection(document.getElementById('shiftFields'), v === '0');
|
||||
setSection(document.getElementById('jobFields'), v === '1');
|
||||
setSection(document.getElementById('talentFields'), v === '2');
|
||||
setSection(facilityGroup, v !== '2'); // facility only for shift/job
|
||||
}
|
||||
kind.addEventListener('change', toggleKind);
|
||||
toggleKind();
|
||||
|
||||
Reference in New Issue
Block a user