`;
}
showError(message) {
this.advisorBody.innerHTML = `
خطا: ${esc(message)}
لطفاً صفحه را دوباره بارگذاری کنید.
PRICES_URL: ${esc(buildUrlWithBust(SETTINGS.PRICES_URL))}
`;
}
async fetchPrices() {
const url = buildUrlWithBust(SETTINGS.PRICES_URL);
const response = await fetch(url, {
cache: "no-store",
credentials: "same-origin",
headers: { "Accept": "application/json" }
});
if (!response.ok) {
throw new Error(`خطا در دریافت قیمتها: HTTP ${response.status} | ${url}`);
}
let data;
try {
data = await response.json();
} catch (e) {
throw new Error(`فایل قیمتها JSON معتبر نیست | ${url}`);
}
if (!data || typeof data !== "object") {
throw new Error(`ساختار فایل قیمتها نامعتبر است | ${url}`);
}
return data;
}
renderStep() {
if (this.currentStep >= QUESTIONS.length) {
this.showResults();
return;
}
const question = QUESTIONS[this.currentStep];
const progressPercent = (this.currentStep / QUESTIONS.length) * 100;
const optionsHTML = question.options.map(opt => {
const isVisual = question.isVisual;
const btnClass = `option-btn ${isVisual ? 'visual' : ''}`;
const bgImage = isVisual ? `style="background-image: url(${opt.imageUrl})"` : '';
const iconHTML = !isVisual
? `
`
: '';
return `
${isVisual ? '
' : ''}
${iconHTML}
${esc(opt.label)}
`;
}).join('');
this.advisorBody.innerHTML = `
مرحله ${this.currentStep + 1} از ${QUESTIONS.length}
${esc(question.title)}
${esc(question.hint)}
${optionsHTML}
`;
document.querySelectorAll('.option-btn').forEach(btn =>
btn.addEventListener('click', (e) => {
document.querySelectorAll('.option-btn').forEach(b => b.classList.remove('selected'));
e.currentTarget.classList.add('selected');
setTimeout(() => this.handleOptionSelect(question.id, btn.dataset.id), 200);
})
);
const prevBtn = document.getElementById('prevBtn');
if (prevBtn) prevBtn.addEventListener('click', () => this.prevStep());
}
handleOptionSelect(questionId, optionId) {
const question = QUESTIONS.find(q => q.id === questionId);
const option = question?.options?.find(o => o.id === optionId);
// دفاع: اگر چیزی اشتباه بود، سقوط نکن
if (!question || !option) return;
this.answers[questionId] = option.value;
this.nextStep();
}
nextStep() {
this.currentStep++;
this.renderStep();
}
prevStep() {
if (this.currentStep > 0) {
this.currentStep--;
const questionId = QUESTIONS[this.currentStep].id;
delete this.answers[questionId];
this.renderStep();
}
}
calculateResults() {
const priority = this.answers.priority || 'price';
const scoredProducts = this.products.map(product => {
let score = 0;
let strictMatches = 0;
// 1) Strict Filters
for (const question of QUESTIONS.filter(q => q.type === 'strict_filter')) {
const answerValue = this.answers[question.id];
if (answerValue && answerValue !== 'any') {
if (question.filter(product, answerValue)) {
score += 100;
strictMatches++;
}
}
}
// 2) Scoring Filters
for (const question of QUESTIONS.filter(q => q.type === 'scoring')) {
const answerValue = this.answers[question.id];
if (answerValue) score += question.score(product, answerValue);
}
// 3) Priority Scoring
if (priority === 'power') {
if (product.specs.engine_cc > 180) score += 5;
if (product.tags.use_case.includes('sport')) score += 5;
}
if (priority === 'comfort') {
if (product.tags.features.includes('abs_brakes')) score += 3;
if (product.tags.features.includes('digital_display')) score += 2;
if (product.specs.category === 'scooter' || product.specs.category === 'cruiser') score += 3;
}
if (priority === 'maintenance') {
if (product.tags.features.includes('low_maintenance')) score += 10;
}
// اگر priority قیمت بود، کمی امتیاز به ارزانترها بده
if (priority === 'price') {
// قیمت کمتر => امتیاز بیشتر (نرمالسازی ساده)
const p = product.price;
if (p > 0) score += Math.max(0, 20 - p / 10);
}
return { product, score, strictMatches };
});
return scoredProducts.sort((a, b) => b.score - a.score);
}
showResults() {
const results = this.calculateResults();
const topResults = results.slice(0, SETTINGS.RECOMMENDATION_COUNT);
this.advisorBody.innerHTML = `
`;
let resultsHeader = `
بهترین پیشنهادها برای شما
`;
const totalStrictQuestionsAnswered = Object.keys(this.answers).filter(key => {
const q = QUESTIONS.find(q => q.id === key);
return q && q.type === 'strict_filter' && this.answers[key] !== 'any';
}).length;
if (topResults.length > 0 && topResults[0].strictMatches < totalStrictQuestionsAnswered) {
resultsHeader += `
نتیجه دقیقی یافت نشد. اینها نزدیکترین گزینهها بر اساس اولویتهای شما هستند.
`;
}
const resultsHTML = topResults.length
? topResults.map(item => this.getProductCardHTML(item.product)).join('')
: `
متاسفانه محصولی در حال حاضر موجود نیست. میتوانید دوباره امتحان کنید.
`;
this.advisorBody.innerHTML += `
${resultsHeader}
${resultsHTML}
`;
const restartBtn = document.getElementById('restartBtn');
if (restartBtn) {
restartBtn.addEventListener('click', () => {
this.currentStep = 0;
this.answers = {};
this.renderStep();
});
}
}
getProductCardHTML(product) {
const transmissionIcon = product.specs.transmission_type === 'automatic'
? `
`
: `
`;
const formatter = new Intl.NumberFormat('fa-IR');
const longestTerm = SETTINGS.LONGEST_TERM_MONTHS;
const minMonthlyPayment = ((product.price * SETTINGS.MONTHLY_INTEREST_RATE * longestTerm) + product.price) / longestTerm;
const formattedInstallment = formatter.format(Math.round(minMonthlyPayment * 100) / 100);
return `
${esc(product.name)}
${esc(product.brand)}
${transmissionIcon}
${product.specs.transmission_type === 'automatic' ? 'اتوماتیک' : 'دندهای'}
${formatter.format(product.specs.engine_cc)} سیسی
${formatter.format(product.price)} میلیون تومان
شروع اقساط از ماهانه ${formattedInstallment} میلیون تومان
`;
}
}
new AdvisorApp();