iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0

▍程式碼

<!-- history_analysis.html -->

<!-- 題目詳情 -->
<div id="questionDetailModal">
    <div>
        <div>
            <div>
                <h5 id="questionDetailModalLabel">題目詳情與筆記</h5>
                <button type="button" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div>
                <h6 id="modal-question-id"></h6>
                <p id="modal-question-text">載入中...</p>
                <div id="modal-options">
                    <!-- 選項 -->
                </div>
                <div class="modal-question-info bg-light p-3 rounded mb-4">
                    <p><strong>正確答案:</strong> <span id="modal-answer">N/A</span></p>
                    <p><strong>來源書籍:</strong> <span id="modal-book-source">N/A</span></p>
                    <p><strong>頁數:</strong> <span id="modal-page-number">N/A</span></p>
                </div>

                <h6>我的筆記</h6>
                <textarea id="modal-user-notes" placeholder="寫下重點筆記..."></textarea>
            </div>
            <div>
                <button type="button" data-bs-dismiss="modal">關閉</button>
                <button type="button" id="save-notes-btn" data-question-key="">儲存筆記</button>
                <div id="notes-status"></div>
            </div>
        </div>
    </div>
</div>

<script>
    $(document).on('click', '.clickable-question', function() {
        const questionKey = $(this).data('question-key');

        if (!questionKey || questionKey === '題目內容缺失') {
            console.error("DANGER: 無法解析題目 Key (內容),屬性為:", $(this).attr('data-question-key'));
            showStatus('錯誤:無法解析題目內容。', 'danger');
            return;
        }

        currentQuestionKey = questionKey;
        const encodedKey = encodeURIComponent(questionKey);
        const apiUrl = `/api/question/${encodedKey}`;

        $('#modal-question-id').text(`Key: ${questionKey}`); // 顯示題目 key
        $('#modal-question-text').text('載入中...');
        $('#modal-options').empty();
        $('#modal-answer').text('N/A');
        $('#modal-book-source').text('N/A');
        $('#modal-page-number').text('N/A');
        $('#modal-user-notes').val('');
        $('#notes-status').text('');
        $('#save-notes-btn').prop('disabled', true).text('儲存筆記').removeAttr('data-question-id');

        if (questionDetailModal) {
            questionDetailModal.show();
        } else {
             console.error("Bootstrap Modal 物件未初始化!請檢查 Bootstrap JS 是否正確載入。");
             return;
        }

        console.log(`[DEBUG] 正在發送 GET 請求到: ${apiUrl}`);

        $.ajax({
            url: apiUrl,
            type: 'GET',
            success: function(data) {
                console.log(`[DEBUG] API 請求成功,收到數據:`, data);

                $('#modal-question-id').text(`ID(索引): ${data.id} | Key: ${data.question_key}`); // 顯示後端返回的 key
                $('#modal-question-text').text(data.question_text);
                $('#modal-answer').text(data.answer);
                $('#modal-book-source').text(data.book_source);
                $('#modal-page-number').text(data.page_number);
                $('#modal-user-notes').val(data.user_notes);

                const labels = ['A', 'B', 'C', 'D', 'E'];
                let optionsHtml = '';
                (data.options || []).forEach((opt, index) => {
                    optionsHtml += `<p class="mb-1">(${labels[index]}) ${opt}</p>`;
                });
                $('#modal-options').html(optionsHtml);

                // 啟用儲存按鈕
                $('#save-notes-btn').prop('disabled', false).attr('data-question-key', data.question_key);
            },
            error: function(jqXHR) {
                const errorMsg = jqXHR.responseJSON ? (jqXHR.responseJSON.error || JSON.stringify(jqXHR.responseJSON)) : jqXHR.responseText;
                console.error(`[ERROR] 獲取題目詳情失敗 (${jqXHR.status}):`, errorMsg);

                $('#modal-question-text').html(`<strong>載入失敗!</strong> 錯誤碼: ${jqXHR.status}。請檢查後端日誌。`);
                showStatus(`錯誤: 載入詳情失敗。${jqXHR.status}`, 'danger');
            }
        });
    });

    // 儲存筆記處理
    $('#save-notes-btn').on('click', function() {
        const qKey = $(this).data('question-key');
        const notes = $('#modal-user-notes').val();

        if (!qKey) {
             showStatus('錯誤:找不到題目 Key。', 'danger');
             return;
        }
        $('#save-notes-btn').prop('disabled', true).text('儲存中...');

        $.ajax({
            url: '/api/save_notes',
            type: 'POST',
            contentType: 'application/json',
            // *** 關鍵變更:提交 question_key 而不是 id ***
            data: JSON.stringify({ question_key: qKey, user_notes: notes }),
            success: function(response) {
                showStatus(response.message || '儲存成功!', 'success');
                $('#save-notes-btn').prop('disabled', false).text('儲存筆記');
            },
            error: function(jqXHR) {
                const errorMsg = jqXHR.responseJSON ? jqXHR.responseJSON.error : '未知錯誤';
                showStatus(`儲存失敗: ${errorMsg}`, 'danger');
                console.error("儲存筆記失敗:", errorMsg);
                $('#save-notes-btn').prop('disabled', false).text('儲存筆記');
            }
        });
    });
</script>
{% endblock %}

# views.py

@app.route('/api/question/<path:question_key>', methods=['GET'])
def get_question_details(question_key):
    """根據題目內容 (question_key) 獲取單個題目的詳細資訊和用戶筆記。"""
    try:
        # 遍歷知識庫以找到匹配的題目
        found_question = None
        found_index = -1
        
        for index, question in enumerate(KNOWLEDGE_BASE):
            # 兼容 '題目' 和 'question_text' 兩種 key
            q_text = question.get('題目', question.get('question_text', ''))
            
            # 使用完全匹配
            if q_text == question_key:
                found_question = question
                found_index = index
                break
        
        if found_question:
            # 確保返回前端需要的欄位名稱
            response_data = {
                'id': found_index, # 傳回索引給前端備用,雖然查找用 key
                'question_key': question_key, # 傳回 key 供前端儲存筆記時使用
                'question_text': found_question.get('題目', found_question.get('question_text', '內容缺失')), 
                'options': found_question.get('選項', []),
                'answer': found_question.get('答案', 'N/A'),
                'book_source': found_question.get('來源書籍', 'N/A'),
                'page_number': found_question.get('頁數', 'N/A'),
                'user_notes': found_question.get('user_notes', '') 
            }
            return jsonify(response_data)
        else:
            return jsonify({'error': f'找不到題目詳情: {question_key}'}, 404)
    except Exception as e:
        print(f"獲取題目詳情失敗: {e}")
        return jsonify({'error': f'伺服器內部錯誤: {e}'}), 500

@app.route('/api/save_notes', methods=['POST'])
def save_user_notes():
    """接收 POST 請求,儲存用戶筆記到 KNOWLEDGE_BASE 並持久化到文件。使用題目內容作為查找鍵。"""
    try:
        data = request.get_json()
        question_key = data.get('question_key') # 現在用 question_key 而不是 id
        user_notes = data.get('user_notes', '')
        
        if question_key is None:
            return jsonify({'error': '缺少題目內容鍵 (question_key)'}), 400
        
        # 查找題目
        found_index = -1
        for index, question in enumerate(KNOWLEDGE_BASE):
            q_text = question.get('題目', question.get('question_text', ''))
            if q_text == question_key:
                found_index = index
                break
                
        if found_index != -1:
            # 更新 KNOWLEDGE_BASE
            KNOWLEDGE_BASE[found_index]['user_notes'] = user_notes
            
            # 持久化到文件
            if save_knowledge_base():
                return jsonify({'success': True, 'message': '筆記儲存成功!'})
            else:
                return jsonify({'error': '筆記儲存成功,但寫入文件失敗。'}, 500) 
        else:
            return jsonify({'error': f'找不到題目內容: {question_key}'}, 404)
            
    except Exception as e:
        print(f"儲存筆記失敗: {e}")
        return jsonify({'error': f'伺服器內部錯誤: {e}'}), 500

上一篇
DAY21 - 小考題目導覽
下一篇
DAY23 - AI 助教
系列文
打造你的數位圖書館:從雜亂檔案到個人化知識庫26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言