Initial commit: Flutter 无书应用项目

This commit is contained in:
Developer
2026-03-30 02:35:31 +08:00
commit 9175ff9905
566 changed files with 103261 additions and 0 deletions

344
ht/p1/api.js Normal file
View File

@@ -0,0 +1,344 @@
(function() {
'use strict';
var state = {
currentId: 1,
correctCount: 0,
totalCount: 0,
selectedOption: null,
isLoading: false,
answered: false,
currentKey: window.INITIAL_KEY || null
};
var elements = {
questionCard: document.getElementById('questionCard'),
navigation: document.getElementById('navigation'),
details: document.getElementById('details'),
loading: document.getElementById('loading'),
correctCount: document.getElementById('correctCount'),
totalCount: document.getElementById('totalCount'),
feedback: document.getElementById('feedback'),
feedbackIcon: document.getElementById('feedbackIcon'),
feedbackText: document.getElementById('feedbackText'),
overlay: document.getElementById('overlay'),
detailAuthor: document.getElementById('detailAuthor'),
detailDynasty: document.getElementById('detailDynasty'),
detailType: document.getElementById('detailType'),
detailGrade: document.getElementById('detailGrade')
};
function getUrlParam(name) {
var urlParams = new URLSearchParams(window.location.search);
return urlParams.get(name);
}
function setUrlParam(name, value) {
var url = new URL(window.location.href);
url.searchParams.set(name, value);
window.history.replaceState({}, '', url);
}
function fetchData(url, callback, errorCallback) {
if (!state.currentKey) {
errorCallback('未初始化 Key');
return;
}
var separator = url.indexOf('?') !== -1 ? '&' : '?';
var fullUrl = url + separator + 'key=' + encodeURIComponent(state.currentKey);
var xhr = new XMLHttpRequest();
xhr.open('GET', fullUrl, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.new_key) {
state.currentKey = response.new_key;
}
callback(response);
} catch (e) {
errorCallback('解析响应失败');
}
} else if (xhr.status === 429) {
errorCallback('请求过于频繁,请稍后再试');
} else {
errorCallback('请求失败,状态码: ' + xhr.status);
}
}
};
xhr.onerror = function() {
errorCallback('网络错误');
};
xhr.send();
}
function fetchQuestion(id) {
if (state.isLoading) return;
state.isLoading = true;
state.answered = false;
state.selectedOption = null;
showLoading();
fetchData('api.php?id=' + id, function(response) {
state.isLoading = false;
if (response.success) {
renderQuestion(response.data);
updateNavigation(id);
updateDetails(response.data);
} else {
showError(response.message || '获取题目失败');
}
}, function(error) {
state.isLoading = false;
showError(error);
});
}
function submitAnswer(id, answer) {
if (state.isLoading || state.answered) return;
state.isLoading = true;
fetchData('api.php?id=' + id + '&msg=' + answer, function(response) {
state.isLoading = false;
if (response.success) {
state.totalCount++;
updateStats();
if (response.type === 'correct') {
state.correctCount++;
updateStats();
showFeedback('correct', '🎉 ' + response.message);
markOption(answer, 'correct');
setTimeout(function() {
hideFeedback();
if (response.next_question) {
state.currentId++;
setUrlParam('id', state.currentId);
renderQuestion(response.next_question);
updateNavigation(state.currentId);
updateDetails(response.next_question);
} else {
state.currentId++;
setUrlParam('id', state.currentId);
fetchQuestion(state.currentId);
}
}, 1500);
} else if (response.type === 'wrong') {
showFeedback('wrong', '😢 ' + response.message);
markOption(answer, 'wrong');
setTimeout(function() {
hideFeedback();
clearOptionMark(answer);
}, 2000);
} else if (response.type === 'hint') {
showHintMessage(response.message);
}
} else {
showFeedback('wrong', response.message || '提交失败');
setTimeout(hideFeedback, 2000);
}
}, function(error) {
state.isLoading = false;
showFeedback('wrong', error);
setTimeout(hideFeedback, 2000);
});
}
function getHint(id) {
if (state.isLoading) return;
state.isLoading = true;
fetchData('api.php?id=' + id + '&msg=提示', function(response) {
state.isLoading = false;
if (response.success && response.type === 'hint') {
showHintMessage(response.message);
} else {
showFeedback('wrong', response.message || '获取提示失败');
setTimeout(hideFeedback, 2000);
}
}, function(error) {
state.isLoading = false;
showFeedback('wrong', error);
setTimeout(hideFeedback, 2000);
});
}
function showLoading() {
elements.questionCard.innerHTML = '<div class="loading">加载中</div>';
elements.details.style.display = 'none';
}
function showError(message) {
elements.questionCard.innerHTML =
'<div class="error-message">' +
'<p>❌ ' + message + '</p>' +
'<button class="retry-btn" onclick="PoetryQuiz.retry()">🔄 重试</button>' +
'</div>';
elements.details.style.display = 'none';
}
function renderQuestion(data) {
var html = '<span class="question-number">第 ' + data.id + ' 题</span>';
html += '<div class="question">' + escapeHtml(data.question) + '</div>';
html += '<div class="options">';
data.options.forEach(function(option) {
html += '<button class="option-btn" data-num="' + option.num + '" onclick="PoetryQuiz.selectOption(' + option.num + ')">';
html += '<span class="option-num">' + option.num + '</span>';
html += '<span class="option-text">' + escapeHtml(option.text) + '</span>';
html += '</button>';
});
html += '</div>';
html += '<button class="hint-btn" onclick="PoetryQuiz.getHint()">';
html += '💡 获取提示';
html += '</button>';
html += '<div class="hint-message" id="hintMessage"></div>';
elements.questionCard.innerHTML = html;
}
function updateNavigation(currentId) {
var html = '<button class="nav-btn random" onclick="PoetryQuiz.goToRandomQuestion()">🎲 随机</button>';
var start = Math.max(1, currentId - 4);
var end = currentId + 5;
for (var i = start; i <= end; i++) {
var activeClass = i === currentId ? ' active' : '';
html += '<button class="nav-btn' + activeClass + '" onclick="PoetryQuiz.goToQuestion(' + i + ')">' + i + '</button>';
}
elements.navigation.innerHTML = html;
}
function updateDetails(data) {
elements.detailAuthor.textContent = data.author || '-';
elements.detailDynasty.textContent = data.dynasty || '-';
elements.detailType.textContent = data.type || '-';
elements.detailGrade.textContent = data.grade || '-';
elements.details.style.display = 'grid';
}
function updateStats() {
elements.correctCount.textContent = state.correctCount;
elements.totalCount.textContent = state.totalCount;
}
function selectOption(num) {
if (state.answered || state.isLoading) return;
var buttons = document.querySelectorAll('.option-btn');
buttons.forEach(function(btn) {
btn.classList.remove('selected');
});
var selectedBtn = document.querySelector('.option-btn[data-num="' + num + '"]');
if (selectedBtn) {
selectedBtn.classList.add('selected');
}
state.selectedOption = num;
submitAnswer(state.currentId, num);
}
function markOption(num, type) {
var btn = document.querySelector('.option-btn[data-num="' + num + '"]');
if (btn) {
btn.classList.add(type);
}
}
function clearOptionMark(num) {
var btn = document.querySelector('.option-btn[data-num="' + num + '"]');
if (btn) {
btn.classList.remove('wrong', 'selected');
}
}
function showFeedback(type, message) {
elements.feedback.className = 'feedback show ' + type;
elements.feedbackIcon.textContent = type === 'correct' ? '🎉' : '😢';
elements.feedbackText.textContent = message.replace(/^[🎉😢]\s*/, '');
elements.overlay.classList.add('show');
}
function hideFeedback() {
elements.feedback.classList.remove('show');
elements.overlay.classList.remove('show');
}
function showHintMessage(message) {
var hintEl = document.getElementById('hintMessage');
if (hintEl) {
hintEl.textContent = '💡 ' + message;
hintEl.classList.add('show');
}
}
function goToQuestion(id) {
if (state.isLoading) return;
state.currentId = id;
state.answered = false;
state.selectedOption = null;
setUrlParam('id', id);
fetchQuestion(id);
}
function goToRandomQuestion() {
if (state.isLoading) return;
var randomId = Math.floor(Math.random() * 500) + 1;
goToQuestion(randomId);
}
function retry() {
fetchQuestion(state.currentId);
}
function escapeHtml(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function init() {
var idParam = getUrlParam('id');
if (idParam) {
state.currentId = parseInt(idParam, 10) || 1;
} else {
state.currentId = Math.floor(Math.random() * 500) + 1;
}
fetchQuestion(state.currentId);
}
window.PoetryQuiz = {
selectOption: selectOption,
getHint: function() { getHint(state.currentId); },
goToQuestion: goToQuestion,
goToRandomQuestion: goToRandomQuestion,
retry: retry
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();