Files
nobat724_front/lib/listingIntro.js
T
hamed b494473e40 feat: رفع لینک /doctor/undefined و متمایزسازی صفحهٔ اصلی شهرها
- ایجاد پرامپت برای رفع خطای 404 ناشی از لینک `/doctor/undefined` در سایت‌های بهبهان و یاسوج.
- افزودن کامپوننت `CityHighlights` برای نمایش محتوای یکتا و آمار پزشکان و تخصص‌های پرمراجعه در صفحهٔ اصلی هر شهر.
- به‌روزرسانی تست‌های مربوط به کامپوننت‌های `ItemDoctor` و `CityHighlights` برای اطمینان از عدم وجود لینک‌های نامعتبر و نمایش صحیح اطلاعات.
- ایجاد سند جدید برای مستندسازی خطاهای Search Console که باگ نیستند و نیاز به رفع ندارند.
- افزودن تست‌های واحد برای توابع `buildCityIntro` و دیگر توابع مرتبط با تولید متن یکتا برای صفحات لیست.
2026-08-08 19:14:50 +03:30

92 lines
21 KiB
JavaScript

// متن مقدمهٔ یکتای صفحات لیست (/doctors و /clinics).
// canonical درست، محتوای یکسان را غیرتکراری نمی‌کند — این متن همان نقش مکمل را دارد.
// مثل صفحات تخصص، ساختار جمله‌بندی هر شهر با هش نام شهر انتخاب می‌شود تا ۳۵ دامنه
// ۳۵ متن با ساختار متفاوت داشته باشند، نه یک قالب با نام جای‌گذاری‌شده.
function hash(value) {
let out = 0;
for (let i = 0; i < value.length; i++) out = (out * 31 + value.charCodeAt(i)) >>> 0;
return out;
}
// seed همیشه unsigned — با >> علامت‌دار، هش‌های بزرگ ایندکس منفی می‌ساختند.
const pick = (variants, seed) => variants[(seed >>> 0) % variants.length];
const DOCTOR_INTROS = (city) => [
`فهرست پزشکان ${city} در این صفحه گردآوری شده است؛ از پزشک عمومی تا فوق‌تخصص‌های حوزه‌های مختلف. هر پروفایل شامل تخصص، کد نظام پزشکی، محل مطب و بازخورد بیماران پیشین است. با فیلترهای بالای صفحه می‌توانید نتایج را بر اساس تخصص، جنسیت پزشک یا درجهٔ تخصصی محدود کنید تا سریع‌تر به گزینهٔ مناسب برسید. پس از انتخاب پزشک، تقویم نوبت‌های خالی نمایش داده می‌شود و رزرو در همان لحظه قطعی می‌گردد؛ نیازی به تماس تلفنی یا مراجعهٔ حضوری برای گرفتن نوبت نیست. اطلاعات هر پزشک به‌صورت دوره‌ای بازبینی می‌شود تا ساعات کاری و محل پذیرش با وضعیت واقعی مطب هم‌خوان بماند. اگر ترجیح می‌دهید جست‌وجو را از یک حوزهٔ درمانی مشخص شروع کنید، صفحهٔ تخصص‌ها فهرست کامل رشته‌ها را در ${city} نشان می‌دهد و از هر رشته مستقیم به پزشکان همان حوزه می‌رسید. هزینهٔ هر خدمت نیز پیش از تأیید نهایی نمایش داده می‌شود.`,
`اینجا می‌توانید متخصصان فعال ${city} را با هم مقایسه کنید. اطلاعات هر پزشک — رشتهٔ تخصصی، سابقهٔ فعالیت، نشانی محل پذیرش و امتیاز مراجعان — به‌شکل یکسان نمایش داده می‌شود تا مقایسه منصفانه باشد. امتیازها از بیماران واقعی همان پزشک جمع‌آوری شده‌اند و نه از منابع عمومی، بنابراین تصویر دقیق‌تری از کیفیت خدمات به دست می‌دهند. برخی پزشکان بیش از یک محل پذیرش دارند و ساعات کاری هر محل جداگانه اعلام شده است؛ هنگام رزرو، محل مراجعه را خودتان انتخاب می‌کنید تا نوبت با برنامهٔ روزانه‌تان هماهنگ باشد. رزرو به‌صورت شبانه‌روزی انجام می‌شود و تأییدیه بلافاصله پیامک می‌گردد. در صورت تغییر برنامه، لغو نوبت از بخش نوبت‌های من امکان‌پذیر است و آن بازهٔ زمانی برای بیمار دیگری آزاد می‌شود.`,
`دسترسی به پزشک مناسب در ${city} با این فهرست ساده‌تر می‌شود. به‌جای جست‌وجو میان منابع پراکنده، همهٔ متخصصان شهر را با اطلاعات ساختاریافته یک‌جا می‌بینید و می‌توانید بر اساس تخصص یا نزدیکی محل مطب انتخاب کنید. رزرو نوبت به‌صورت آنلاین و شبانه‌روزی انجام می‌شود: تاریخ و ساعت خالی را انتخاب می‌کنید، تأیید می‌گیرید و پیامک تأییدیه دریافت می‌کنید. در صورت تغییر برنامه نیز لغو نوبت از حساب کاربری‌تان ممکن است. سابقهٔ نوبت‌های شما در همان حساب باقی می‌ماند و مراجعهٔ بعدی به همان پزشک سریع‌تر انجام می‌شود. مراکز درمانی و کلینیک‌های ${city} هم صفحهٔ اختصاصی خود را دارند؛ اگر ترجیح می‌دهید ابتدا مرکز درمانی را انتخاب کنید، از آن مسیر هم می‌توانید به همین پزشکان برسید.`,
`پزشکان ${city} در این صفحه بر اساس تخصص، جنسیت و درجهٔ علمی قابل فیلتر شدن‌اند. هر کارت نام پزشک، حوزهٔ فعالیت، امتیاز بیماران و اولین نوبت آزاد را نشان می‌دهد تا بدون باز کردن چند صفحه بتوانید مقایسه کنید. اطلاعات هر پروفایل به‌صورت دوره‌ای بازبینی می‌شود تا ساعات کاری و محل پذیرش با وضعیت واقعی مطب هم‌خوان بماند. امتیازها از بیماران واقعی همان پزشک جمع‌آوری شده‌اند، نه از منابع عمومی، بنابراین تصویر دقیق‌تری از کیفیت خدمات می‌دهند. هزینهٔ هر خدمت هم پیش از تأیید نهایی نمایش داده می‌شود تا انتخابتان با اطلاع کامل انجام شود. با انتخاب هر پزشک، محل‌های پذیرش و ساعات کاری هر محل را می‌بینید و نوبت را برای همان محل رزرو می‌کنید. اگر نمی‌دانید به کدام تخصص مراجعه کنید، فهرست تخصص‌ها نقطهٔ شروع بهتری است.`,
`جست‌وجوی پزشک در ${city} از همین‌جا شروع می‌شود. می‌توانید نام پزشک یا نام تخصص را تایپ کنید؛ هر دو در نتایج لحاظ می‌شوند. کارت هر پزشک شامل تخصص‌ها، محل مطب و وضعیت نوبت‌دهی است و پزشکانی که هم‌اکنون نوبت آزاد دارند بالاتر نمایش داده می‌شوند. رزرو نهایی در همان لحظه انجام می‌شود و تأییدیه پیامک می‌گردد؛ نیازی به تماس با منشی مطب نیست. سابقهٔ نوبت‌های شما در همان حساب کاربری باقی می‌ماند و مراجعهٔ بعدی به همان پزشک سریع‌تر انجام می‌شود. اگر پزشک بیش از یک محل پذیرش داشته باشد، ساعات کاری هر محل جداگانه اعلام شده است و هنگام رزرو خودتان محل مراجعه را انتخاب می‌کنید. در صورت تغییر برنامه، لغو نوبت از بخش نوبت‌های من ممکن است و آن بازه برای بیمار دیگری آزاد می‌شود.`,
`فهرست کامل پزشکان ${city} را اینجا می‌بینید، از پزشک عمومی تا فوق‌تخصص. برای هر پزشک، کد نظام پزشکی و نشانی محل پذیرش درج شده تا از هویت حرفه‌ای مطمئن شوید. نوبت‌ها به‌صورت آنلاین و شبانه‌روزی رزرو می‌شوند و در صورت نیاز، لغو نوبت هم از همان حساب کاربری ممکن است. برای دیدن مراکز درمانی به‌جای پزشکان، صفحهٔ کلینیک‌های ${city} فهرست جداگانه‌ای دارد. هر مرکز درمانی صفحهٔ اختصاصی خود را دارد که پزشکان همکار، تخصص‌های موجود و بیمه‌های طرف قرارداد را نشان می‌دهد. اگر ترجیح می‌دهید ابتدا مرکز را انتخاب کنید و بعد پزشک را، آن مسیر هم به همین فهرست می‌رسد. رزرو در هر دو مسیر یکسان است: انتخاب بازهٔ خالی، تأیید، و دریافت پیامک تأییدیه در همان لحظه.`,
];
const CLINIC_INTROS = (city) => [
`کلینیک‌ها و مراکز درمانی ${city} در این صفحه فهرست شده‌اند. برای هر مرکز، تخصص‌های ارائه‌شده، پزشکان همکار، نشانی و اطلاعات تماس نمایش داده می‌شود. اگر ترجیح می‌دهید به‌جای انتخاب پزشک، ابتدا مرکز درمانی را انتخاب کنید، این فهرست نقطهٔ شروع مناسبی است. از صفحهٔ هر کلینیک می‌توانید پزشکان همان مرکز را ببینید و مستقیم برایشان نوبت بگیرید؛ همهٔ مراحل آنلاین و بدون تماس تلفنی انجام می‌شود. صفحهٔ هر مرکز موقعیت روی نقشه و ساعات کاری را هم نشان می‌دهد تا پیش از مراجعه، مسیر و زمان را بدانید. مراکزی که به‌صورت شبانه‌روزی پذیرش دارند نیز مشخص شده‌اند. برای مقایسهٔ مستقیم پزشکان به‌جای مراکز، فهرست پزشکان ${city} گزینهٔ دیگری در اختیارتان می‌گذارد.`,
`این صفحه مراکز درمانی فعال ${city} را معرفی می‌کند — از کلینیک‌های تخصصی تا درمانگاه‌های چندتخصصی. هر مرکز صفحهٔ اختصاصی خود را دارد که در آن خدمات، بیمه‌های طرف قرارداد، تخصص‌های موجود و فهرست پزشکان همکار آمده است. جست‌وجو را می‌توانید با فیلتر تخصص محدود کنید تا فقط مراکزی را ببینید که خدمت موردنظرتان را ارائه می‌دهند. رزرو نوبت از همان صفحهٔ مرکز و به‌صورت آنلاین انجام می‌شود و تأییدیه بلافاصله پیامک می‌گردد. اطلاعات تماس و نشانی هر مرکز به‌صورت دوره‌ای بازبینی می‌شود. اگر مرکزی بیش از یک شعبه دارد، هر شعبه رکورد جداگانهٔ خود را با ساعات کاری مستقل دارد تا انتخاب دقیق‌تری داشته باشید.`,
`برای یافتن مرکز درمانی مناسب در ${city}، فهرست زیر گزینه‌های موجود را با اطلاعات یکسان کنار هم می‌گذارد. تفاوت این فهرست با جست‌وجوی ساده در آن است که هر رکورد به یک صفحهٔ کامل وصل است: موقعیت روی نقشه، ساعات کاری، تخصص‌ها و پزشکانی که در آن مرکز پذیرش دارند. پس از انتخاب مرکز و پزشک، نوبت‌های خالی را می‌بینید و رزرو در همان لحظه نهایی می‌شود. هزینهٔ هر خدمت پیش از تأیید نمایش داده می‌شود تا انتخابتان با اطلاع کامل انجام شود. در صورت تغییر برنامه، لغو نوبت از بخش نوبت‌های من در حساب کاربری ممکن است و بازهٔ آزادشده بلافاصله در اختیار بیمار دیگری قرار می‌گیرد.`,
`درمانگاه‌ها، کلینیک‌های تخصصی و مراکز تصویربرداری ${city} در این فهرست کنار هم آمده‌اند. برای هر مرکز می‌بینید چه تخصص‌هایی ارائه می‌شود، کدام پزشکان آنجا پذیرش دارند و ساعات کاری هر روز چگونه است. انتخاب مرکز پیش از انتخاب پزشک وقتی مفید است که به خدمتی نیاز دارید که در یک مرکز مشخص متمرکز است. نوبت‌گیری از صفحهٔ همان مرکز انجام می‌شود و نیازی به تماس تلفنی نیست. برای مراکزی که چند تخصص را زیر یک سقف جمع کرده‌اند، می‌توانید در همان مراجعه چند خدمت را پیگیری کنید. فهرست پزشکان هر مرکز با تخصص و اولین نوبت آزادشان نمایش داده می‌شود تا انتخاب سریع‌تر باشد. هزینهٔ هر خدمت پیش از تأیید نهایی اعلام می‌شود و در صورت تغییر برنامه، لغو نوبت از حساب کاربری‌تان امکان‌پذیر است.`,
`مراکز درمانی ${city} را از این صفحه پیدا کنید و مستقیم نوبت بگیرید. هر مرکز نشانی، شمارهٔ تماس، موقعیت روی نقشه و فهرست پزشکان همکارش را در صفحهٔ اختصاصی خود نشان می‌دهد. اگر بیمهٔ خاصی دارید، بیمه‌های طرف قرارداد هر مرکز هم همان‌جا اعلام شده است. پس از انتخاب پزشک، نوبت‌های خالی همان هفته نمایش داده می‌شود و تأیید رزرو بلافاصله پیامک می‌گردد. مراکزی که به‌صورت شبانه‌روزی پذیرش دارند جداگانه مشخص شده‌اند تا در شرایط اضطراری سریع‌تر تصمیم بگیرید. اطلاعات تماس و نشانی هر مرکز به‌صورت دوره‌ای بازبینی می‌شود. اگر به‌جای مرکز درمانی دنبال یک پزشک مشخص هستید، فهرست پزشکان همان شهر مسیر مستقیم‌تری در اختیارتان می‌گذارد.`,
`این فهرست مراکز درمانی فعال ${city} را با ساختار یکسان کنار هم می‌گذارد تا مقایسه ساده باشد. برخی مراکز چند شعبه دارند و هر شعبه رکورد جداگانه با ساعات کاری مستقل خود را دارد؛ پیش از مراجعه، شعبهٔ درست را از روی نشانی و نقشه انتخاب کنید. رزرو، تغییر و لغو نوبت همگی آنلاین و از حساب کاربری‌تان انجام می‌شود و بازهٔ لغوشده بلافاصله در اختیار بیمار دیگری قرار می‌گیرد. صفحهٔ هر مرکز موقعیت روی نقشه را هم نشان می‌دهد تا پیش از مراجعه مسیر و زمان رسیدن را بدانید. تخصص‌های ارائه‌شده و پزشکان همکار هر مرکز در همان صفحه فهرست شده‌اند و از آنجا می‌توانید مستقیم نوبت بگیرید، بدون اینکه لازم باشد جداگانه دنبال پزشک بگردید.`,
];
// مقدمهٔ صفحهٔ اصلی هر دامنهٔ شهری.
//
// صفحهٔ اصلی تا پیش از این فقط `site_name` و `slogan` را از city.json شهری می‌کرد و
// بقیهٔ صفحه — بنر، کادر جستجو، جستجوهای پرتکرار، فوتر — روی همهٔ دامنه‌ها یکسان بود.
// اندازه‌گیری: شباهت متن رندرشدهٔ بهبهان و یاسوج ۹۹٫۰٪. گوگل canonicalِ درستِ ما را رد
// می‌کرد و صفحهٔ اصلی شهر را با دامنهٔ دیگری تجمیع می‌کرد
// (Duplicate, Google chose different canonical than user).
//
// عدد پزشک و تخصص داخل متن می‌آید تا تمایز فقط لفظی نباشد؛ هر شهر آمار خودش را دارد.
const CITY_INTROS = (city, doctorCount, topSpecialty) => [
`${city} در حال حاضر ${doctorCount} پزشک فعال روی این سامانه دارد و بیشترین مراجعه به حوزهٔ ${topSpecialty} است. برای هر پزشک، تخصص، محل مطب، ساعات کاری و نوبت‌های خالی همین‌جا نمایش داده می‌شود و رزرو در همان لحظه قطعی می‌گردد. اگر نمی‌دانید به کدام تخصص مراجعه کنید، از فهرست تخصص‌های همین صفحه شروع کنید؛ هر رشته مستقیم به پزشکان همان حوزه در ${city} می‌رسد.`,
`دسترسی به پزشک در ${city} از همین صفحه شروع می‌شود: ${doctorCount} پزشک فعال، با پرمراجعه‌ترین حوزهٔ ${topSpecialty}. نام پزشک یا نام تخصص را در کادر بالا جست‌وجو کنید، یا از میان تخصص‌های پرمراجعهٔ همین شهر انتخاب کنید. نوبت‌گیری شبانه‌روزی است و تأییدیه بلافاصله پیامک می‌شود؛ برای گرفتن نوبت نیازی به تماس تلفنی با مطب نیست.`,
`این صفحه نقطهٔ ورود به پزشکان و مراکز درمانی ${city} است. ${doctorCount} پزشک در رشته‌های مختلف پذیرش دارند و ${topSpecialty} بیشترین سهم مراجعه را در این شهر دارد. هر پروفایل شامل سابقهٔ فعالیت، نشانی محل پذیرش و بازخورد بیماران پیشین است تا انتخاب با اطلاع کامل انجام شود. رزرو، تغییر و لغو نوبت همگی آنلاین و از حساب کاربری خودتان انجام می‌شود.`,
`نوبت پزشکان ${city} را می‌توانید بدون تماس تلفنی و در هر ساعت شبانه‌روز رزرو کنید. هم‌اکنون ${doctorCount} پزشک روی این سامانه در دسترس‌اند و پرمراجعه‌ترین حوزه در این شهر ${topSpecialty} است. برای هر پزشک، محل پذیرش و ساعت‌های خالیِ همان هفته نمایش داده می‌شود؛ کافی است بازهٔ دلخواهتان را انتخاب کنید تا تأییدیه بلافاصله پیامک شود. مقایسهٔ پزشکان بر اساس تخصص و امتیاز بیماران هم از همین صفحه ممکن است.`,
`اگر دنبال پزشک در ${city} هستید، از همین‌جا شروع کنید. ${doctorCount} پزشک فعال در این شهر ثبت شده‌اند و ${topSpecialty} بیشترین مراجعه را به خود اختصاص داده است. جست‌وجو را می‌توانید با نام پزشک یا با نام تخصص انجام دهید؛ نتایج شامل نشانی مطب، ساعات کاری و اولین نوبت آزاد هر پزشک است. برای مراکز درمانی چندتخصصی نیز فهرست جداگانه‌ای در دسترس است که پزشکان هر مرکز را کنار هم نشان می‌دهد.`,
`فهرست پزشکان ${city} با ${doctorCount} پروفایل فعال در این سامانه نگهداری می‌شود و ${topSpecialty} پرمراجعه‌ترین حوزهٔ درمانی این شهر است. اطلاعات هر پزشک — تخصص، محل پذیرش و ساعات کاری — به‌صورت دوره‌ای بازبینی می‌شود تا با وضعیت واقعی مطب هم‌خوان بماند. نوبت‌گیری در همان لحظه قطعی می‌شود و در صورت تغییر برنامه، لغو آن از حساب کاربری‌تان امکان‌پذیر است.`,
];
/**
* مقدمهٔ یکتای صفحهٔ اصلی یک شهر.
*
* seed از نام شهر می‌آید، نه تصادفی: متن باید بین شهرها واگرا شود ولی برای یک شهر
* در هر rebuild ثابت بماند، وگرنه محتوای صفحهٔ اصلی مدام عوض می‌شد.
*/
export function buildCityIntro(cityName, doctorCount = 0, topSpecialty = "") {
const count = Number(doctorCount) > 0 ? Number(doctorCount) : 0;
const specialty = topSpecialty || "پزشکی عمومی";
return pick(CITY_INTROS(cityName, count, specialty), hash(cityName) >>> 5);
}
/**
* جملهٔ آماری که به انتهای متن می‌چسبد.
*
* انتخاب variant با هش انجام می‌شود و با ۶ حالت و ۳۵ شهر، حدود ۱۵٪ جفت‌ها هم‌variant
* می‌شوند. برای آن جفت‌ها متن تقریباً یکسان می‌شد و دو صفحه دوباره شبیه هم — سنجیده
* شد: بهبهان و یاسوج روی /clinics از ۶۸٫۹٪ به ۸۴٫۷٪ شباهت رفتند.
*
* عدد واقعیِ هر شهر این را می‌شکند، چون هیچ دو شهری آمار یکسان ندارند. همان الگویی
* که در متن صفحهٔ اصلی جواب داد.
*/
const countSentence = (count, cityName, noun) =>
Number(count) > 0
? ` هم‌اکنون ${Number(count)} ${noun} در ${cityName} روی این سامانه ثبت شده‌اند.`
: "";
export function buildDoctorsIntro(cityName, doctorCount = 0) {
return (
pick(DOCTOR_INTROS(cityName), hash(cityName)) +
countSentence(doctorCount, cityName, "پزشک")
);
}
export function buildClinicsIntro(cityName, clinicCount = 0) {
return (
pick(CLINIC_INTROS(cityName), hash(cityName) >>> 2) +
countSentence(clinicCount, cityName, "مرکز درمانی")
);
}