每日总结

屏幕截图 2026-01-06 004711

屏幕截图 2026-01-06 004417

<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>学习记录 - 心理健康应用</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: Arial, sans-serif;
        background: #f5f5f5;
        min-height: 100vh;
    }

    .header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px 0;
        text-align: center;
    }

    .header h1 {
        font-size: 2.5em;
        margin-bottom: 10px;
    }

    .nav {
        background: white;
        padding: 15px 0;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }

    .nav-container {
        max-width: 1200px;
        margin: 0 auto;
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0 20px;
    }

    .nav-links a {
        margin-left: 20px;
        color: #667eea;
        text-decoration: none;
        font-weight: 500;
    }

    .nav-links a:hover {
        color: #764ba2;
    }

    .container {
        max-width: 1200px;
        margin: 40px auto;
        padding: 0 20px;
    }

    .tabs {
        display: flex;
        gap: 10px;
        margin-bottom: 30px;
        flex-wrap: wrap;
    }

    .tab-btn {
        background: #f5f5f5;
        border: none;
        padding: 10px 20px;
        border-radius: 25px;
        cursor: pointer;
        font-weight: 500;
        transition: all 0.3s ease;
        font-size: 1em;
    }

    .tab-btn.active {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
    }

    .tab-content {
        display: none;
    }

    .tab-content.active {
        display: block;
    }

    .record-card {
        background: white;
        border-radius: 15px;
        padding: 25px;
        margin-bottom: 25px;
        box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
    }

    .record-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 15px;
        flex-wrap: wrap;
        gap: 10px;
    }

    .record-title {
        font-size: 1.3em;
        color: #333;
        font-weight: bold;
    }

    .record-date {
        color: #666;
        font-size: 0.9em;
    }

    .record-details {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 15px;
        margin-bottom: 20px;
    }

    .detail-item {
        background: #f5f5f5;
        padding: 10px 15px;
        border-radius: 10px;
    }

    .detail-label {
        color: #999;
        font-size: 0.8em;
        margin-bottom: 5px;
    }

    .detail-value {
        color: #333;
        font-weight: 500;
    }

    .progress-bar {
        width: 100%;
        height: 10px;
        background: #e0e0e0;
        border-radius: 5px;
        overflow: hidden;
        margin-bottom: 15px;
    }

    .progress-fill {
        height: 100%;
        background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
        border-radius: 5px;
    }

    .status-badge {
        padding: 5px 10px;
        border-radius: 15px;
        font-size: 0.8em;
        font-weight: 500;
    }

    .status-completed {
        background: #e8f5e8;
        color: #2e7d32;
    }

    .status-in-progress {
        background: #fff3e0;
        color: #ef6c00;
    }

    .status-passed {
        background: #e8f5e8;
        color: #2e7d32;
    }

    .status-failed {
        background: #ffebee;
        color: #c62828;
    }

    .action-buttons {
        display: flex;
        gap: 10px;
        margin-top: 20px;
        flex-wrap: wrap;
    }

    .action-btn {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        padding: 8px 15px;
        border-radius: 8px;
        cursor: pointer;
        font-weight: 500;
        font-size: 0.9em;
        transition: opacity 0.3s ease;
        text-decoration: none;
        display: inline-block;
    }

    .action-btn:hover {
        opacity: 0.9;
    }

    .view-btn {
        background: #4caf50;
    }

    .no-records {
        text-align: center;
        padding: 60px 20px;
        color: #666;
        background: white;
        border-radius: 15px;
        box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
    }

    .loading {
        text-align: center;
        padding: 60px 20px;
        color: #666;
    }

    @media (max-width: 768px) {
        .record-details {
            grid-template-columns: 1fr;
        }

        .tabs {
            justify-content: center;
        }

        .action-buttons {
            justify-content: center;
        }
    }
</style>
</head> <body> <!-- 引入上边栏 --> <div th:replace="~{_top-nav :: top-nav}"></div>
<div class="main-content-with-topnav">
    <div class="container">
        <div class="tabs">
            <button class="tab-btn active" onclick="openTab('learning')">学习记录</button>
            <button class="tab-btn" onclick="openTab('test')">测试记录</button>
            <button class="tab-btn" onclick="openTab('assessment')">评估记录</button>
        </div>

        <!-- 学习记录 -->
        <div id="learning" class="tab-content active">
            <div id="learningLoading" class="loading">
                <h3>加载学习记录中...</h3>
            </div>
            <div id="learningRecords" style="display: none;">
                <!-- 学习记录将通过 JavaScript 动态生成 -->
            </div>
            <div id="noLearningRecords" class="no-records" style="display: none;">
                <h3>暂无学习记录</h3>
                <p>开始学习推荐的学习包,记录将显示在这里</p>
                <a href="recommended-learning.html" class="action-btn">查看推荐学习</a>
            </div>
        </div>

        <!-- 测试记录 -->
        <div id="test" class="tab-content">
            <div id="testLoading" class="loading">
                <h3>加载测试记录中...</h3>
            </div>
            <div id="testRecords" style="display: none;">
                <!-- 测试记录将通过 JavaScript 动态生成 -->
            </div>
            <div id="noTestRecords" class="no-records" style="display: none;">
                <h3>暂无测试记录</h3>
                <p>完成学习包后参加测试,记录将显示在这里</p>
                <a href="recommended-learning.html" class="action-btn">查看推荐学习</a>
            </div>
        </div>

        <!-- 评估记录 -->
        <div id="assessment" class="tab-content">
            <div id="assessmentLoading" class="loading">
                <h3>加载评估记录中...</h3>
            </div>
            <div id="assessmentRecords" style="display: none;">
                <!-- 评估记录将通过 JavaScript 动态生成 -->
            </div>
            <div id="noAssessmentRecords" class="no-records" style="display: none;">
                <h3>暂无评估记录</h3>
                <p>完成测试后生成评估报告,记录将显示在这里</p>
                <a href="recommended-learning.html" class="action-btn">查看推荐学习</a>
            </div>
        </div>
    </div>
</div>

<script>
    // 切换标签页
    function openTab(tabName) {
        // 隐藏所有标签内容
        const tabContents = document.querySelectorAll('.tab-content');
        tabContents.forEach(content => {
            content.classList.remove('active');
        });

        // 移除所有按钮的激活状态
        const tabBtns = document.querySelectorAll('.tab-btn');
        tabBtns.forEach(btn => {
            btn.classList.remove('active');
        });

        // 显示当前标签内容
        document.getElementById(tabName).classList.add('active');
        event.currentTarget.classList.add('active');

        // 加载对应记录
        if (tabName === 'learning' && !window.learningRecordsLoaded) {
            loadLearningRecords();
        } else if (tabName === 'test' && !window.testRecordsLoaded) {
            loadTestRecords();
        } else if (tabName === 'assessment' && !window.assessmentRecordsLoaded) {
            loadAssessmentRecords();
        }
    }

    // 初始化
    function init() {
        // 加载学习记录
        loadLearningRecords();
    }

    // 加载学习记录
    async function loadLearningRecords() {
        window.learningRecordsLoaded = true;
        try {
            const token = localStorage.getItem('token');
            const user = JSON.parse(localStorage.getItem('user'));
            const userId = user.id;

            const response = await fetch(`/api/learning/user/${userId}/records`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (!response.ok) {
                throw new Error('加载学习记录失败');
            }

            const records = await response.json();
            displayLearningRecords(records);
        } catch (error) {
            console.error('加载学习记录失败:', error);
            alert('加载学习记录失败,请重试');
        }
    }

    // 显示学习记录
    function displayLearningRecords(records) {
        const container = document.getElementById('learningRecords');
        const loading = document.getElementById('learningLoading');
        const noRecords = document.getElementById('noLearningRecords');

        if (records.length === 0) {
            loading.style.display = 'none';
            noRecords.style.display = 'block';
            return;
        }

        container.innerHTML = '';

        // 按日期分组记录
        const recordsByDate = groupByDate(records, r => new Date(r.updatedDate));

        // 按日期倒序排列
        const sortedDates = Object.keys(recordsByDate).sort((a, b) => new Date(b) - new Date(a));

        sortedDates.forEach(date => {
            const dateRecords = recordsByDate[date];

            dateRecords.forEach(record => {
                const card = document.createElement('div');
                card.className = 'record-card';

                let status = '学习中';
                let statusClass = 'status-in-progress';
                if (record.isCompleted) {
                    status = '已完成';
                    statusClass = 'status-completed';
                }

                card.innerHTML = `
                    <div class="record-header">
                        <div class="record-title">${record.videoTitle}</div>
                        <div class="record-date">${formatDate(record.updatedDate)}</div>
                    </div>
                    <div class="record-details">
                        <div class="detail-item">
                            <div class="detail-label">学习包</div>
                            <div class="detail-value">${record.learningPackageName}</div>
                        </div>
                        <div class="detail-item">
                            <div class="detail-label">观看进度</div>
                            <div class="detail-value">${record.watchProgress}%</div>
                        </div>
                        <div class="detail-item">
                            <div class="detail-label">状态</div>
                            <div class="detail-value status-badge ${statusClass}">${status}</div>
                        </div>
                    </div>
                    <div class="progress-bar">
                        <div class="progress-fill" style="width: ${record.watchProgress}%;"></div>
                    </div>
                    <div class="action-buttons">
                        <a href="/learning-package-detail.html?id=${record.learningPackageId}" class="action-btn">继续学习</a>
                    </div>
                `;

                container.appendChild(card);
            });
        });

        loading.style.display = 'none';
        container.style.display = 'block';
    }

    // 加载测试记录
    async function loadTestRecords() {
        window.testRecordsLoaded = true;
        try {
            const token = localStorage.getItem('token');

            const response = await fetch(`/api/tests/user-records`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (!response.ok) {
                throw new Error('加载测试记录失败');
            }

            const records = await response.json();
            displayTestRecords(records);
        } catch (error) {
            console.error('加载测试记录失败:', error);
            alert('加载测试记录失败,请重试');
        }
    }

    // 显示测试记录
    function displayTestRecords(records) {
        const container = document.getElementById('testRecords');
        const loading = document.getElementById('testLoading');
        const noRecords = document.getElementById('noTestRecords');

        if (records.length === 0) {
            loading.style.display = 'none';
            noRecords.style.display = 'block';
            return;
        }

        container.innerHTML = '';

        // 按日期倒序排列
        records.sort((a, b) => new Date(b.createTime) - new Date(a.createTime));

        records.forEach(record => {
            const card = document.createElement('div');
            card.className = 'record-card';

            let status = '未通过';
            let statusClass = 'status-failed';
            if (record.isPassed) {
                status = '已通过';
                statusClass = 'status-passed';
            }

            card.innerHTML = `
                <div class="record-header">
                    <div class="record-title">${record.learningPackageName} - 测试</div>
                    <div class="record-date">${formatDate(record.createTime)}</div>
                </div>
                <div class="record-details">
                    <div class="detail-item">
                        <div class="detail-label">得分</div>
                        <div class="detail-value">${record.score} / ${record.totalQuestions}</div>
                    </div>
                    <div class="detail-item">
                        <div class="detail-label">正确率</div>
                        <div class="detail-value">${Math.round((record.score / record.totalQuestions) * 100)}%</div>
                    </div>
                    <div class="detail-item">
                        <div class="detail-label">状态</div>
                        <div class="detail-value status-badge ${statusClass}">${status}</div>
                    </div>
                </div>
                <div class="action-buttons">
                    <a href="/assessment-result.html?testRecordId=${record.id}" class="action-btn view-btn">查看评估报告</a>
                    <a href="/test-questions.html?packageId=${record.learningPackageId}" class="action-btn">重新测试</a>
                </div>
            `;

            container.appendChild(card);
        });

        loading.style.display = 'none';
        container.style.display = 'block';
    }

    // 加载评估记录
    async function loadAssessmentRecords() {
        window.assessmentRecordsLoaded = true;
        try {
            const token = localStorage.getItem('token');

            const response = await fetch(`/api/assessments/user-records`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (!response.ok) {
                throw new Error('加载评估记录失败');
            }

            const records = await response.json();
            displayAssessmentRecords(records);
        } catch (error) {
            console.error('加载评估记录失败:', error);
            alert('加载评估记录失败,请重试');
        }
    }

    // 显示评估记录
    function displayAssessmentRecords(records) {
        const container = document.getElementById('assessmentRecords');
        const loading = document.getElementById('assessmentLoading');
        const noRecords = document.getElementById('noAssessmentRecords');

        if (records.length === 0) {
            loading.style.display = 'none';
            noRecords.style.display = 'block';
            return;
        }

        container.innerHTML = '';

        // 按日期倒序排列
        records.sort((a, b) => new Date(b.createdDate) - new Date(a.createdDate));

        records.forEach(record => {
            const card = document.createElement('div');
            card.className = 'record-card';

            let effectivenessLevel;
            if (record.learningEffectiveness >= 80) {
                effectivenessLevel = '优秀';
            } else if (record.learningEffectiveness >= 60) {
                effectivenessLevel = '良好';
            } else {
                effectivenessLevel = '有待提高';
            }

            card.innerHTML = `
                <div class="record-header">
                    <div class="record-title">${record.learningPackageName} - 心理状态评估</div>
                    <div class="record-date">${formatDate(record.createdDate)}</div>
                </div>
                <div class="record-details">
                    <div class="detail-item">
                        <div class="detail-label">学习包</div>
                        <div class="detail-value">${record.learningPackageName}</div>
                    </div>
                    <div class="detail-item">
                        <div class="detail-label">学习效果</div>
                        <div class="detail-value">${effectivenessLevel} (${record.learningEffectiveness}%)</div>
                    </div>
                    <div class="detail-item">
                        <div class="detail-label">测试得分</div>
                        <div class="detail-value">${record.testScore}分</div>
                    </div>
                </div>
                <div class="action-buttons">
                    <a href="/assessment-result.html?testRecordId=${record.testRecordId}" class="action-btn view-btn">查看评估报告</a>
                </div>
            `;

            container.appendChild(card);
        });

        loading.style.display = 'none';
        container.style.display = 'block';
    }

    // 按日期分组
    function groupByDate(items, dateGetter) {
        return items.reduce((acc, item) => {
            const date = formatDateOnly(dateGetter(item));
            if (!acc[date]) {
                acc[date] = [];
            }
            acc[date].push(item);
            return acc;
        }, {});
    }

    // 格式化日期时间
    function formatDate(dateString) {
        const date = new Date(dateString);
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        return `${year}-${month}-${day} ${hours}:${minutes}`;
    }

    // 格式化日期(仅年月日)
    function formatDateOnly(date) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    }

    // 退出登录
    function logout() {
        localStorage.removeItem('token');
        localStorage.removeItem('user');
        window.location.href = 'login.html';
    }

    // 页面加载完成后初始化
    window.addEventListener('DOMContentLoaded', init);
</script>
</body>

微服务架构
微服务将单体应用拆分为独立部署的小服务,每个服务负责特定业务功能。优势:技术异构、独立扩展、容错性。挑战:服务间通信(如REST/gRPC)、数据一致性(分布式事务)、运维复杂度(监控、部署)。适合大型团队和复杂业务。

posted @ 2025-12-10 20:04  李蕊lr  阅读(1)  评论(0)    收藏  举报