/**
* 問卷和偏好探索功能
* 處理註冊後的問卷填寫和偏好探索流程
*/
class QuestionnaireManager {
constructor() {
this.questionnaireData = {};
this.preferenceData = [];
this.currentRound = 1;
this.totalRounds = 16;
this.questions = [];
this.dogImages = [];
this.comparisonPairs = [];
this.dogLetterMap = {}; // 狗狗ID到字母的映射
this.nextLetter = 0; // 下一個要分配的字母索引
this.preloadedImages = new Map(); // 預載的圖片快取
this.init();
}
init() {
this.bindEvents();
this.loadQuestions();
}
async loadQuestions() {
try {
const response = await fetch('/api/questionnaire/questions');
const result = await response.json();
if (result.success && result.data) {
this.questions = result.data;
this.renderQuestions();
} else {
console.error('載入問卷問題失敗:', result.message);
this.showError('載入問卷失敗,請重新整理頁面');
}
} catch (error) {
console.error('載入問卷問題時發生錯誤:', error);
this.showError('載入問卷時發生錯誤,請檢查網路連線');
}
}
renderQuestions() {
const contentDiv = document.getElementById('questionnaireContent');
if (!contentDiv) {
console.error('找不到問卷內容容器');
return;
}
if (this.questions.length === 0) {
contentDiv.innerHTML = `
`;
return;
}
let html = '';
this.questions.forEach((question, index) => {
const questionNumber = index + 1;
html += `
${questionNumber}. ${question.text}
${question.description ? `
${question.description}
` : ''}
${this.renderQuestionOptions(question, questionNumber)}
`;
});
contentDiv.innerHTML = html;
// 重新綁定事件
this.bindQuestionEvents();
this.checkFormCompletion();
}
renderQuestionOptions(question, questionNumber) {
let html = '';
question.options.forEach((option, optionIndex) => {
const optionId = `q${questionNumber}_${optionIndex}`;
// 使用 A, B, C, D... 作為選項標籤
const optionLabel = String.fromCharCode(65 + optionIndex); // A, B, C, D...
// 使用選項的 ID 或索引作為表單值
const optionValue = option.id || optionLabel;
html += `
`;
});
return html;
}
bindQuestionEvents() {
// 綁定單選按鈕變化事件
const radioInputs = document.querySelectorAll('#questionnaireForm input[type="radio"]');
radioInputs.forEach(input => {
input.addEventListener('change', () => {
this.checkFormCompletion();
});
});
}
showError(message) {
const contentDiv = document.getElementById('questionnaireContent');
if (contentDiv) {
contentDiv.innerHTML = `
${message}
`;
}
}
bindEvents() {
// 問卷表單事件
if (typeof $ !== 'undefined') {
$('#questionnaireForm input[type="radio"]').on('change', () => {
this.checkFormCompletion();
});
// 提交問卷
$('#submitQuestionnaireBtn').on('click', () => {
this.submitQuestionnaire();
});
// 關閉問卷按鈕 - 允許關閉
$('#closeQuestionnaireBtn').on('click', () => {
const questionnaireModal = document.getElementById('questionnaireModal');
if (questionnaireModal) {
const bsModal = bootstrap.Modal.getInstance(questionnaireModal);
if (bsModal) {
bsModal.hide();
}
}
});
// 關閉2選1按鈕 - 允許關閉
$('#closePreferenceBtn').on('click', () => {
const preferenceModal = document.getElementById('preferenceModal');
if (preferenceModal) {
const bsModal = bootstrap.Modal.getInstance(preferenceModal);
if (bsModal) {
bsModal.hide();
}
}
});
// 偏好探索事件
$(document).on('click', '.dog-frame-container', (e) => {
const dogId = String($(e.currentTarget).data('dog-id'));
this.selectPreference(dogId);
});
// 完成頁面事件
$('#viewRecommendations').on('click', () => {
this.viewRecommendations();
});
$('#restartProcess').on('click', () => {
this.restartProcess();
});
} else {
// 使用原生JavaScript
const form = document.getElementById('questionnaireForm');
if (form) {
form.addEventListener('change', (e) => {
if (e.target.type === 'radio') {
this.checkFormCompletion();
}
});
}
const submitBtn = document.getElementById('submitQuestionnaireBtn');
if (submitBtn) {
submitBtn.addEventListener('click', () => {
this.submitQuestionnaire();
});
}
const closeQuestionnaireBtn = document.getElementById('closeQuestionnaireBtn');
if (closeQuestionnaireBtn) {
closeQuestionnaireBtn.addEventListener('click', () => {
const questionnaireModal = document.getElementById('questionnaireModal');
if (questionnaireModal) {
const bsModal = bootstrap.Modal.getInstance(questionnaireModal);
if (bsModal) {
bsModal.hide();
}
}
});
}
const closePreferenceBtn = document.getElementById('closePreferenceBtn');
if (closePreferenceBtn) {
closePreferenceBtn.addEventListener('click', () => {
// 確認是否要關閉
if (this.preferenceData.length > 0) {
const confirmed = confirm('偏好探索尚未完成,確定要關閉嗎?');
if (!confirmed) {
return;
}
}
this.closePreferenceExploration();
});
}
document.addEventListener('click', (e) => {
if (e.target.closest('.dog-frame-container')) {
const dogId = String(e.target.closest('.dog-frame-container').dataset.dogId);
this.selectPreference(dogId);
}
});
const confirmBtn = document.getElementById('confirmComplete');
if (confirmBtn) {
confirmBtn.addEventListener('click', () => {
this.confirmComplete();
});
}
}
}
checkFormCompletion() {
// 如果問題尚未載入,直接返回
if (!this.questions || this.questions.length === 0) {
return;
}
const requiredQuestions = this.questions.length;
let answeredQuestions = 0;
for (let i = 1; i <= requiredQuestions; i++) {
const checked = document.querySelector(`input[name="question_${i}"]:checked`);
if (checked) {
answeredQuestions++;
}
}
const submitBtn = document.getElementById('submitQuestionnaireBtn');
if (submitBtn) {
if (answeredQuestions === requiredQuestions && requiredQuestions > 0) {
submitBtn.disabled = false;
submitBtn.classList.remove('btn-secondary');
submitBtn.classList.add('btn-primary');
} else {
submitBtn.disabled = true;
submitBtn.classList.remove('btn-primary');
submitBtn.classList.add('btn-secondary');
}
}
}
async submitQuestionnaire() {
// 收集問卷數據
this.questionnaireData = {};
const answeredLog = [];
for (let i = 1; i <= this.questions.length; i++) {
const selected = document.querySelector(`input[name="question_${i}"]:checked`);
if (selected) {
this.questionnaireData[`question_${i}`] = selected.value;
// 找到對應題目與選項
const q = this.questions[i-1];
const opt = (q && q.options || []).find(o => String(o.id) === String(selected.value));
answeredLog.push({
questionText: q ? q.text : '',
optionText: opt ? opt.label : '',
traits: opt && opt.traits ? opt.traits : [],
});
}
}
// 先儲存問券填寫結果,等待完成
let saveSuccess = false;
try {
const saveResponse = await fetch('/front_header_footer/survey_history', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
survey_type: 'questionnaire',
content: answeredLog
})
});
const saveResult = await saveResponse.json();
if (saveResult.success) {
saveSuccess = true;
} else {
console.error('問卷儲存失敗:', saveResult.message);
alert('問卷儲存失敗,請稍後再試');
return;
}
} catch(e) {
console.error('問卷儲存時發生錯誤:', e);
alert('問卷儲存時發生錯誤,請稍後再試');
return;
}
// 只有在儲存成功後才關閉問卷模態框
if (saveSuccess) {
const questionnaireModal = document.getElementById('questionnaireModal');
if (questionnaireModal) {
const bsModal = bootstrap.Modal.getInstance(questionnaireModal);
if (bsModal) {
bsModal.hide();
}
}
}
// 清除註冊後自動開啟偏好探索的標記(如果有的話)
try {
if (localStorage.getItem('autoStartPreferenceAfterQuestionnaire') === 'true') {
localStorage.removeItem('autoStartPreferenceAfterQuestionnaire');
}
} catch(e) {}
// 問卷完成後,顯示完成提示並跳轉到首頁
showCompletionModal('已完成問卷填寫,感謝您的回覆!');
// 為確認按鈕綁定跳轉到首頁的邏輯
setTimeout(() => {
const completionModal = document.getElementById('completionModal');
if (completionModal) {
const confirmBtn = completionModal.querySelector('#confirmComplete');
if (confirmBtn) {
const newConfirmHandler = () => {
const instance = bootstrap.Modal.getInstance(completionModal);
if (instance) instance.hide();
// 跳轉到首頁
window.location.href = '/';
};
confirmBtn.onclick = newConfirmHandler;
}
}
}, 100);
}
closeQuestionnaire() {
// 關閉問卷模態框
const questionnaireModal = document.getElementById('questionnaireModal');
if (questionnaireModal) {
const bsModal = bootstrap.Modal.getInstance(questionnaireModal);
if (bsModal) {
bsModal.hide();
} else {
// 如果 modal 實例不存在,創建新的實例並隱藏
const newBsModal = new bootstrap.Modal(questionnaireModal);
newBsModal.hide();
}
}
}
closePreferenceExploration() {
// 關閉偏好探索模態框
const preferenceModal = document.getElementById('preferenceModal');
if (preferenceModal) {
const bsModal = bootstrap.Modal.getInstance(preferenceModal);
if (bsModal) {
bsModal.hide();
} else {
// 如果 modal 實例不存在,創建新的實例並隱藏
const newBsModal = new bootstrap.Modal(preferenceModal);
newBsModal.hide();
}
}
}
// 二選一圖片載入
async fetchDogExploreItems() {
try {
const response = await fetch('/dog_explore/items');
const result = await response.json();
if (result.success && result.data) {
// 只保留title、image_filename與id
this.dogImages = result.data.filter(i => i.is_visible).map(i => {
const originalImage = '/static/uploads/dog_explore/' + (i.image_filename || 'default.jpg');
// 使用縮圖(400px 寬度適合二選一展示)
const thumbnailImage = typeof getThumbnailUrl === 'function'
? getThumbnailUrl(originalImage, { width: 400 })
: originalImage;
return {
id: i.id,
name: i.title,
image: thumbnailImage
};
});
} else {
this.dogImages = [];
}
} catch (err) {
this.dogImages = [];
}
}
// 獲取或分配狗狗的字母標籤
getDogLetter(dogId) {
// 統一轉為字符串作為鍵
const dogIdStr = String(dogId);
if (!this.dogLetterMap[dogIdStr]) {
// 如果這隻狗還沒有分配字母,分配一個新的
this.dogLetterMap[dogIdStr] = String.fromCharCode(65 + this.nextLetter); // 65 是 'A' 的 ASCII 碼
this.nextLetter++;
}
return this.dogLetterMap[dogIdStr];
}
// 生成二選一淘汰賽邏輯
initiateEliminationTournament() {
// 初始待選陣列為所有項目
this.eliminationRounds = [ [...this.dogImages] ];
this.currentEliminationRound = 0;
this.currentPairs = [];
this.dogLetterMap = {}; // 重置字母映射
this.nextLetter = 0; // 重置字母索引
this._generateNextPairs();
this.champWinner = null;
}
_generateNextPairs() {
// 本輪內容配對(偶數才夠一次對兩兩)
const round = this.eliminationRounds[this.currentEliminationRound];
// 去重檢查:確保本輪沒有重複的項目
const seenIds = new Set();
const uniqueRound = [];
for (const item of round) {
const itemId = String(item.id);
if (!seenIds.has(itemId)) {
seenIds.add(itemId);
uniqueRound.push(item);
} else {
console.warn('偏好探索配對:跳過重複的項目', item.name, '(ID:', itemId + ')');
}
}
// 使用去重後的陣列進行配對
this.currentPairs = [];
for(let i=0;i {
const originalImage = '/static/uploads/dog_explore/' + (i.image_filename || 'default.jpg');
// 使用縮圖(400px 寬度適合二選一展示)
const thumbnailImage = typeof getThumbnailUrl === 'function'
? getThumbnailUrl(originalImage, { width: 400 })
: originalImage;
// 確保 traits 是有效的陣列
const traits = Array.isArray(i.traits) ? i.traits : [];
// 驗證 traits 資料的完整性
const validTraits = traits.filter(t => {
if (!t || typeof t !== 'object') return false;
if (!t.category_id || !t.score) {
console.warn(`⚠️ 項目 ${i.title} (ID: ${i.id}) 的 trait 資料不完整:`, t);
return false;
}
return true;
});
if (validTraits.length !== traits.length) {
console.warn(`⚠️ 項目 ${i.title} 有 ${traits.length - validTraits.length} 個無效的 trait 被過濾掉`);
}
return {
id: i.id,
name: i.title,
image: thumbnailImage,
image_filename: i.image_filename,
traits: validTraits
};
});
// 去重:使用 Map 來確保不會有重複的項目(基於 id)
const uniqueItemsMap = new Map();
for (const item of mappedItems) {
// 使用字符串 id 作為鍵,確保不會有重複的項目
const itemId = String(item.id);
if (!uniqueItemsMap.has(itemId)) {
uniqueItemsMap.set(itemId, item);
} else {
console.warn('偏好探索:跳過重複的項目 ID', itemId);
}
}
// 進一步去重:檢查是否有相同的圖片檔案名稱
// 標準化檔案名稱:移除副檔名並轉小寫,因為縮圖 API 會自動嘗試多種副檔名
const normalizeFilename = (filename) => {
if (!filename) return null;
// 移除副檔名和路徑,只保留檔案名稱本身
const nameWithoutPath = filename.split('/').pop().split('\\').pop();
const nameWithoutExt = nameWithoutPath.split('.')[0];
return nameWithoutExt.toLowerCase();
};
const imageFilenameSet = new Set();
this.dogImages = [];
for (const item of uniqueItemsMap.values()) {
const normalized = normalizeFilename(item.image_filename);
if (normalized && !imageFilenameSet.has(normalized)) {
imageFilenameSet.add(normalized);
// 移除 image_filename 屬性(不需要在最終數據中)
const { image_filename, ...itemWithoutFilename } = item;
this.dogImages.push(itemWithoutFilename);
} else {
console.warn('偏好探索:跳過重複的圖片', item.image_filename, '(標準化為', normalized + ')');
}
}
// 檢查去重後是否還有足夠的項目
if (this.dogImages.length < 2) {
alert('偏好探索項目不足(去重後少於 2 個),請聯絡管理員檢查探索圖片!');
return;
}
// 最終驗證:確保有足夠且無重複的項目
this.preferenceData = [];
this.champWinner = null;
this.eliminationRounds = [ [...this.dogImages] ];
this.currentEliminationRound = 0;
this.currentPairs = [];
this._generateNextPairs();
// 計算輪數(n個項目需要 n-1 場比賽)
this.totalRounds = this.dogImages.length - 1;
// 預載所有圖片以加速顯示
await this.preloadImages();
this.showCurrentRound();
}
// 預載圖片方法
async preloadImages() {
let successCount = 0;
let failCount = 0;
const preloadPromises = this.dogImages.map(dog => {
return new Promise((resolve) => {
if (this.preloadedImages.has(dog.image)) {
successCount++;
resolve();
return;
}
const img = new Image();
img.onload = () => {
this.preloadedImages.set(dog.image, img);
successCount++;
resolve();
};
img.onerror = () => {
console.warn(`✗ 圖片載入失敗: ${dog.name} (${dog.image})`);
failCount++;
// 即使失敗也繼續,使用預設圖片
resolve();
};
img.src = dog.image;
// 設置超時(5秒)
setTimeout(() => {
if (!this.preloadedImages.has(dog.image)) {
console.warn(`⏱️ 圖片載入超時: ${dog.name}`);
failCount++;
resolve();
}
}, 5000);
});
});
await Promise.all(preloadPromises);
}
// 取代原有showCurrentRound,只顯示一對
showCurrentRound() {
// 若單一冠軍產生
if(this.champWinner){
this.completePreferenceExploration();
return;
}
if(!this.currentPairs.length && !this.byeItem){
this.completePreferenceExploration();
return;
}
const pair = this.currentPairs[this.currentPairIndex];
if(!pair){
let winners = this.preferenceData.filter(x=>x.roundIndex===this.currentEliminationRound).map(x=>x.selected);
if(this.byeItem) winners.push(this.byeItem);
// 去重:確保 winners 中沒有重複的項目(基於 id)
const uniqueWinners = [];
const seenIds = new Set();
for (const winner of winners) {
const winnerId = String(winner.id); // 統一轉為字符串比較
if (!seenIds.has(winnerId)) {
seenIds.add(winnerId);
uniqueWinners.push(winner);
} else {
console.warn('偏好探索:跳過重複的勝者', winner.name, '(ID:', winnerId + ')');
}
}
winners = uniqueWinners;
if(winners.length===1){
this.champWinner = winners[0];
this.completePreferenceExploration();
return;
}
this.eliminationRounds.push([...winners]);
this.currentEliminationRound++;
this._generateNextPairs();
this.showCurrentRound();
return;
}
// 渲染配對
const imageComparison = document.getElementById('imageComparison');
if(imageComparison) {
// 確保配對中的兩個項目都存在且有效
if (!pair[0] || !pair[1]) {
console.error('偏好探索:配對資料不完整', pair);
this.completePreferenceExploration();
return;
}
// 再次確認兩個項目不相同
if (String(pair[0].id) === String(pair[1].id)) {
console.error('偏好探索:配對中的兩個項目相同!跳過此配對');
this.currentPairIndex++;
this.showCurrentRound();
return;
}
const letter1 = this.getDogLetter(pair[0].id);
const letter2 = this.getDogLetter(pair[1].id);
// 優化:只使用一次圖片載入(移除 background-image),並添加 loading 屬性
imageComparison.innerHTML = `
`;
}
// 依已完成選擇數更新輪數與進度
const finishedSelections = this.preferenceData.filter(p => p.selected).length;
const currentRoundNumber = Math.min(finishedSelections + 1, this.totalRounds);
const currentRoundEl = document.getElementById('currentRound');
const totalRoundsEl = document.getElementById('totalRounds');
if(currentRoundEl) currentRoundEl.textContent = this.totalRounds > 0 ? currentRoundNumber : 0;
if(totalRoundsEl) totalRoundsEl.textContent = this.totalRounds;
const progressBar = document.getElementById('progressBar');
if(progressBar){
const percent = this.totalRounds > 0 ? (finishedSelections / this.totalRounds) * 100 : 0;
progressBar.style.width = `${percent}%`;
}
}
// 取代selectPreference,修正記錄方式,勝方晉級
selectPreference(dogId) {
const pair = this.currentPairs[this.currentPairIndex];
if (!pair) {
console.error('偏好探索:當前沒有配對可選擇');
return;
}
// 統一轉為字符串比較,避免類型不一致
const dogIdStr = String(dogId);
const selectedDog = pair.find(x => String(x.id) === dogIdStr);
if (!selectedDog) {
console.error('偏好探索:找不到選中的項目', dogId, '配對:', pair);
return;
}
// 記錄當前輪晉級者,包含配對資訊
this.preferenceData.push({
roundIndex: this.currentEliminationRound,
pairIndex: this.currentPairIndex,
orderIds: pair.map(x => String(x.id)),
orderNames: pair.map(x => x.name),
selected: selectedDog,
selectedTraits: selectedDog.traits || [],
timestamp: new Date()
});
// 動畫
const selectedCard = document.querySelector(`.dog-frame-container[data-dog-id="${dogIdStr}"]`);
if (selectedCard) selectedCard.classList.add('selected');
setTimeout(() => {
this.currentPairIndex++;
this.showCurrentRound();
}, 800);
}
// 跳過當前配對(淘汰賽邏輯)
skipRound() {
const pair = this.currentPairs[this.currentPairIndex];
if (!pair) {
console.warn('偏好探索:當前沒有配對可跳過');
return;
}
// 隨機選擇一個作為勝者(因為用戶跳過)
const randomIndex = Math.floor(Math.random() * 2);
const selectedDog = pair[randomIndex];
// 記錄跳過但仍需晉級者
this.preferenceData.push({
roundIndex: this.currentEliminationRound,
pairIndex: this.currentPairIndex,
orderIds: pair.map(x => String(x.id)),
orderNames: pair.map(x => x.name),
selected: selectedDog,
selectedTraits: selectedDog.traits || [],
skipped: true, // 標記為跳過
timestamp: new Date()
});
setTimeout(() => {
this.currentPairIndex++;
this.showCurrentRound();
}, 300);
}
// 此函數已不再使用(保留以避免破壞現有引用)
nextRound() {
console.warn('nextRound() 已棄用,請使用淘汰賽邏輯');
this.showCurrentRound();
}
// 處理偏好探索完成後的導向邏輯
handlePreferenceExplorationCompletion() {
const isOnMatchingPage = window.location.pathname.includes('/start_match');
// 顯示完成提示
showCompletionModal('已完成 偏好探索!');
// 為確認按鈕綁定額外邏輯
setTimeout(() => {
const completionModal = document.getElementById('completionModal');
if (completionModal) {
const confirmBtn = completionModal.querySelector('#confirmComplete');
if (confirmBtn) {
const newConfirmHandler = () => {
const instance = bootstrap.Modal.getInstance(completionModal);
if (instance) instance.hide();
if (isOnMatchingPage) {
// 如果在配對頁面,重新整理以更新配對狀態
window.location.reload();
} else {
// 如果不在配對頁面,導向到開始配對頁面
window.location.href = '/start_match';
}
};
confirmBtn.onclick = newConfirmHandler;
}
}
}, 100);
}
// 取代completePreferenceExploration,使最後champWinner成為冠軍
completePreferenceExploration() {
// 詳細紀錄:每輪的順序與選擇及特質
const selectedCount = this.preferenceData.filter(p => p.selected).length;
const skippedCount = this.preferenceData.filter(p => p.skipped).length;
const resultHtml = `
偏好分析
您完成了 ${selectedCount} 輪偏好選擇
${skippedCount > 0 ? `
跳過了 ${skippedCount} 輪
` : ''}
問卷和偏好探索已完成,系統將根據您的選擇進行配對分析
`;
const preferenceResults = document.getElementById('preferenceResults');
if(preferenceResults) preferenceResults.innerHTML = resultHtml;
// modal 控制
const preferenceModal = document.getElementById('preferenceModal');
if (preferenceModal) {
const bsModal = bootstrap.Modal.getInstance(preferenceModal);
if(bsModal) bsModal.hide();
}
setTimeout(() => {
// 儲存偏好探索填寫結果
try {
const cleaned = this.preferenceData.map(x => ({
round: x.roundIndex + 1,
pairIndex: x.pairIndex !== undefined ? x.pairIndex + 1 : null,
orderIds: x.orderIds || [],
orderNames: x.orderNames || [],
chosenId: x.selected ? String(x.selected.id) : null,
chosenName: x.selected ? x.selected.name : null,
skipped: x.skipped || false,
traits: (x.selectedTraits || []).map(t => ({
category_id: t.category_id,
category_code: t.category_code,
category_group: t.category_group,
category_name: t.category_name,
score: t.score
}))
}));
fetch('/front_header_footer/survey_history', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
survey_type: 'pairwise',
content: cleaned
})
}).then(response => response.json())
.then(result => {
// 偏好探索完成後,處理導向邏輯
this.handlePreferenceExplorationCompletion();
}).catch(err => {
console.error('✗ 偏好探索資料儲存錯誤:', err);
// 即使儲存失敗,也處理導向邏輯
this.handlePreferenceExplorationCompletion();
});
} catch(e) {
console.error('✗ 偏好探索資料處理錯誤:', e);
// 如果發生錯誤,也處理導向邏輯
this.handlePreferenceExplorationCompletion();
}
}, 300);
}
showResults() {
// 簡單的結果展示
const selectedCount = this.preferenceData.filter(p => p.selected).length;
const resultsHtml = `
偏好分析
您完成了 ${selectedCount} 輪偏好選擇
問卷和偏好探索已完成,系統將根據您的選擇進行配對分析
`;
const preferenceResults = document.getElementById('preferenceResults');
if (preferenceResults) {
preferenceResults.innerHTML = resultsHtml;
}
}
confirmComplete() {
// 關閉完成模態框
const completionModal = document.getElementById('completionModal');
if (completionModal) {
const bsModal = bootstrap.Modal.getInstance(completionModal);
if (bsModal) {
bsModal.hide();
}
}
}
}
// 初始化函數
function initQuestionnaire() {
// 初始化問卷管理器
window.questionnaireManager = new QuestionnaireManager();
// 檢查是否需要顯示問卷(例如:新註冊用戶)
const shouldShowQuestionnaire = localStorage.getItem('showQuestionnaire') === 'true';
if (shouldShowQuestionnaire) {
// 清除標記
localStorage.removeItem('showQuestionnaire');
// 顯示問卷
setTimeout(() => {
if (typeof $ !== 'undefined') {
$('#questionnaireModal').modal('show');
} else {
// 如果jQuery未載入,使用原生JavaScript
const modal = document.getElementById('questionnaireModal');
if (modal) {
const bsModal = new bootstrap.Modal(modal);
bsModal.show();
}
}
}, 1000);
}
}
// 當頁面載入完成時初始化
if (typeof $ !== 'undefined') {
$(document).ready(initQuestionnaire);
} else {
// 如果jQuery未載入,等待DOM載入完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initQuestionnaire);
} else {
initQuestionnaire();
}
}
// 模擬註冊完成後觸發問卷
function triggerQuestionnaire() {
localStorage.setItem('showQuestionnaire', 'true');
location.reload();
}
// 註冊完成後觸發問卷的函數
function showQuestionnaireAfterRegistration() {
$('#questionnaireModal').modal('show');
}
// 添加CSS樣式
const style = document.createElement('style');
style.textContent = `
.dog-frame-container {
position: relative;
cursor: pointer;
transition: all 0.3s ease;
}
.dog-frame-container:hover {
transform: translateY(-5px);
}
.dog-photo-frame {
background: linear-gradient(145deg, #f0f0f0, #ffffff);
padding: 20px;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
}
.dog-frame-container:hover .dog-photo-frame {
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.25);
}
.frame-inner {
position: relative;
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
border-radius: 4px;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
height: 310px;
display: flex;
align-items: center;
justify-content: center;
}
.frame-image {
position: relative;
max-width: 100%;
max-height: 100%;
height: auto;
object-fit: contain;
display: block;
border-radius: 2px;
z-index: 2;
transition: opacity 0.3s ease;
}
/* 圖片載入動畫 */
.frame-image[src=""] {
opacity: 0;
}
.frame-inner::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin: -20px 0 0 -20px;
border: 4px solid rgba(0, 71, 103, 0.2);
border-top-color: #004767;
border-radius: 50%;
animation: spin 1s linear infinite;
z-index: 1;
}
.frame-image[src]:not([src=""]) ~ .frame-inner::after {
display: none;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.dog-label {
position: absolute;
bottom: -30px;
left: 50%;
transform: translateX(-50%);
background: #2c2c2c;
color: white;
width: 50px;
height: 50px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: bold;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.dog-frame-container.selected .dog-photo-frame {
box-shadow: 0 0 0 4px #28a745, 0 15px 40px rgba(40, 167, 69, 0.3);
}
.dog-frame-container.selected {
transform: scale(1.05);
}
.vs-badge {
background: linear-gradient(135deg, #ff9800, #ff6b00);
color: white;
width: 80px;
height: 80px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
font-weight: bold;
box-shadow: 0 6px 20px rgba(255, 107, 0, 0.4);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}
.cursor-pointer {
cursor: pointer;
}
.traits .badge {
font-size: 0.8rem;
}
`;
document.head.appendChild(style);
// 以完成頁面樣式呈現簡訊息
function showCompletionModal(message) {
try {
const completionModal = document.getElementById('completionModal');
if (!completionModal) return;
// 更新文字
const body = completionModal.querySelector('.modal-body');
if (body) {
body.innerHTML = `
`;
}
const bsModal = new bootstrap.Modal(completionModal);
bsModal.show();
// 綁定關閉
const confirmBtn = completionModal.querySelector('#confirmComplete');
if (confirmBtn) {
confirmBtn.onclick = () => {
const instance = bootstrap.Modal.getInstance(completionModal);
if (instance) instance.hide();
};
}
} catch (e) {}
}
// window上掛reopenPreferenceExploration以及reopenQuestionnaire
window.reopenPreferenceExploration = function() {
if(window.questionnaireManager){
questionnaireManager.preferenceData = [];
questionnaireManager.champWinner = null;
questionnaireManager.eliminationRounds = [];
questionnaireManager.currentEliminationRound = 0;
questionnaireManager.currentPairs = [];
questionnaireManager.currentPairIndex = 0;
const preferenceModal = document.getElementById('preferenceModal');
if(preferenceModal) {
const bsModal = new bootstrap.Modal(preferenceModal);
bsModal.show();
}
questionnaireManager.startPreferenceExploration();
}
};
window.reopenQuestionnaire = function() {
if(window.questionnaireManager){
questionnaireManager.questionnaireData={};
questionnaireManager.preferenceData=[];
questionnaireManager.currentRound=1;
// 強制刷新問題
questionnaireManager.loadQuestions();
const questionnaireModal = document.getElementById('questionnaireModal');
if(questionnaireModal){
const bsModal = new bootstrap.Modal(questionnaireModal);
bsModal.show();
}
}
};