🎮ArcadeLab

视译后练习 · 热词闯关 | 口译多元挑战

by RocketGecko40
733 lines34.0 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <title>视译后练习 · 热词闯关 | 口译多元挑战</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            background: #fef7e8;
            background-image: radial-gradient(circle at 10% 20%, rgba(255, 235, 200, 0.6) 2%, transparent 2.5%);
            background-size: 28px 28px;
            font-family: 'Segoe UI', 'Poppins', 'Inter', system-ui, -apple-system, 'Microsoft YaHei', sans-serif;
            padding: 32px 24px;
            color: #2c2418;
        }

        /* 主容器 */
        .main-quiz-container {
            max-width: 1300px;
            margin: 0 auto;
        }

        /* 头部 */
        .hero {
            text-align: center;
            margin-bottom: 32px;
        }
        .hero h1 {
            font-size: 2.4rem;
            background: linear-gradient(135deg, #E67E22, #F4A261);
            background-clip: text;
            -webkit-background-clip: text;
            color: transparent;
            letter-spacing: -0.5px;
        }
        .hero p {
            color: #b97f44;
            font-weight: 500;
            margin-top: 8px;
            font-size: 1.05rem;
        }
        .score-bar {
            display: flex;
            justify-content: flex-end;
            align-items: baseline;
            gap: 28px;
            background: #ffffffcc;
            backdrop-filter: blur(4px);
            padding: 12px 28px;
            border-radius: 80px;
            margin-bottom: 32px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
        }
        .score-card {
            background: #fae6cf;
            padding: 6px 20px;
            border-radius: 40px;
            font-weight: bold;
        }
        .score-label {
            font-size: 0.8rem;
            color: #a7582c;
        }
        .score-value {
            font-size: 1.8rem;
            font-weight: 800;
            color: #e67e22;
            line-height: 1;
        }

        /* 关卡选项卡 */
        .level-tabs {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            margin-bottom: 28px;
            justify-content: center;
        }
        .level-tab {
            background: #f5e6d3;
            padding: 12px 26px;
            border-radius: 60px;
            font-weight: 600;
            cursor: pointer;
            transition: 0.2s;
            border: 1px solid #eed7bb;
            color: #7a4d2a;
        }
        .level-tab.active {
            background: #e67e22;
            color: white;
            border-color: #e67e22;
            box-shadow: 0 6px 12px rgba(230,126,34,0.25);
        }
        .level-tab.completed-tab {
            background: #b7d968;
            color: #2c5a1e;
            border-color: #9bc45a;
        }
        .level-tab.locked-tab {
            opacity: 0.55;
            cursor: not-allowed;
            background: #ddd0be;
        }

        /* 主体卡片: 每个关卡独立内容 */
        .quiz-panel {
            background: #fffef7;
            border-radius: 64px;
            box-shadow: 0 20px 35px rgba(100, 60, 10, 0.1);
            padding: 32px 36px;
            transition: 0.2s;
            border: 1px solid #ffdfb8;
        }

        .section-title {
            font-size: 1.5rem;
            font-weight: 700;
            border-left: 8px solid #f4a261;
            padding-left: 20px;
            margin-bottom: 28px;
            color: #6b3f1c;
        }

        /* 判断题/选择题共用样式 */
        .question-card {
            background: #fef5ea;
            border-radius: 40px;
            padding: 20px 28px;
            margin-bottom: 24px;
            transition: all 0.1s;
            border: 1px solid #ffe0bc;
        }
        .question-text {
            font-weight: 600;
            font-size: 1.05rem;
            margin-bottom: 16px;
        }
        .options {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin: 12px 0 8px;
        }
        .opt-btn {
            background: #ffffff;
            border: 1.5px solid #f0cfaa;
            padding: 8px 24px;
            border-radius: 60px;
            cursor: pointer;
            transition: 0.1s;
            font-weight: 500;
        }
        .opt-btn.selected {
            background: #e67e22;
            border-color: #e67e22;
            color: white;
        }
        .feedback {
            margin-top: 12px;
            font-size: 0.85rem;
            padding: 6px 12px;
            border-radius: 28px;
            display: inline-block;
        }
        .correct-fb {
            background: #dcfce7;
            color: #15803d;
        }
        .wrong-fb {
            background: #ffe4e2;
            color: #b91c1c;
        }

        /* 连线题区域 */
        .match-area {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: space-between;
            margin: 25px 0;
        }
        .match-col {
            flex: 1;
            background: #faf0e2;
            border-radius: 48px;
            padding: 18px;
        }
        .match-item {
            background: white;
            margin: 12px 0;
            padding: 12px 16px;
            border-radius: 60px;
            text-align: center;
            cursor: pointer;
            transition: 0.08s linear;
            border: 1px solid #e9cfa7;
            font-weight: 500;
        }
        .match-item.selected-match {
            background: #e67e22;
            color: white;
            border-color: #e67e22;
        }
        .paired-info {
            font-size: 0.8rem;
            margin-top: 16px;
            text-align: center;
            background: #e7dcc8;
            padding: 8px;
            border-radius: 40px;
        }

        /* 视译专区 */
        .sight-card {
            background: #fef2e2;
            border-radius: 40px;
            padding: 20px;
            margin-bottom: 28px;
        }
        .eng-sentence {
            background: #2c3e2f10;
            padding: 14px;
            font-family: 'Courier New', monospace;
            border-left: 6px solid #f4a261;
            margin-bottom: 12px;
        }
        textarea {
            width: 100%;
            background: white;
            border: 1px solid #f3cfaa;
            border-radius: 36px;
            padding: 14px 20px;
            font-size: 0.9rem;
            font-family: inherit;
            resize: vertical;
        }
        .submit-area {
            text-align: right;
            margin-top: 28px;
        }
        .submit-btn {
            background: #e67e22;
            border: none;
            padding: 12px 32px;
            border-radius: 60px;
            font-weight: bold;
            color: white;
            font-size: 1rem;
            cursor: pointer;
            transition: 0.1s;
            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
        }
        .reset-btn {
            background: #b0aa8c;
            margin-right: 16px;
        }
        .complete-badge {
            text-align: center;
            background: #cbe6b0;
            border-radius: 48px;
            padding: 14px;
            margin-top: 20px;
            font-weight: bold;
        }

        @media (max-width: 700px) {
            .quiz-panel { padding: 20px; }
            .match-area { flex-direction: column; }
        }
        footer {
            text-align: center;
            margin-top: 32px;
            opacity: 0.7;
        }
    </style>
</head>
<body>
<div class="main-quiz-container">
    <div class="hero">
        <h1>🎤 视译后·热词大闯关</h1>
        <p>判断题 ✓ | 选择题 ✨ | 连线题 🔗 | 视译挑战 🎙️</p>
    </div>
    <div class="score-bar">
        <div class="score-card"><span class="score-label">🏆 累计得分</span><div class="score-value" id="totalScoreDisplay">0</div></div>
        <div class="score-card"><span class="score-label">📌 通关进度</span><div class="score-value" id="progressDisplay">0</div><span style="font-size:0.8rem;">/4</span></div>
    </div>

    <!-- 关卡选项卡 -->
    <div class="level-tabs" id="levelTabs"></div>

    <!-- 动态内容面板 -->
    <div id="quizPanel" class="quiz-panel"></div>
    <footer>🎯 每关独立计分,全部完成解锁大师成就!</footer>
</div>

<script>
    // --------------------------------------------------------------
    // 基于提供的四个热词构建丰富题库 (判断+选择+连线+视译)
    // --------------------------------------------------------------
    const levels = [
        { // 热词01 习近平会见郑丽文
            id: 0,
            name: "🏛️ 01 两岸会晤 · 习近平见郑丽文",
            completed: false,
            scoreEarned: 0,
            unlocked: true,
            tasks: {
                truefalse: [
                    { text: "习近平指出,国共两党领导人时隔10年再次会面,对两岸关系发展无足轻重。", isTrue: false, explanation: "原文明确表示“具有重要意义”,对两党关系和两岸关系发展都很重要。" },
                    { text: "习近平强调,中华民族伟大复兴的大趋势不会因为国际形势变化而改变。", isTrue: true, explanation: "无论国际形势和台海局势如何演变,民族复兴的大趋势不会改变。" }
                ],
                multipleChoice: [
                    { question: "根据报道,郑丽文此访大陆有何特殊意义?", options: ["首次率团访问江苏", "时隔10年国民党主席再次率团访问大陆", "与习近平总书记签署经济协议", "宣布两岸直航新政策"], correct: 1, explanation: "郑丽文是近十年来首位率团来访大陆的国民党主席。" },
                    { question: "习近平提到国共两党不可推卸的责任是什么?", options: ["实现两岸军事同盟", "推动台湾独立", "回应两岸同胞对和平与美好生活的期盼", "联合举办奥运会"], correct: 2, explanation: "两岸同胞期盼和平安宁与更好生活,这是不可推卸的责任。" }
                ],
                matching: {
                    left: ["overarching trend", "national rejuvenation", "shirk responsibility"],
                    right: ["首要趋势", "民族复兴", "推卸责任"]
                },
                sightTranslation: [
                    { eng: "No matter how the international landscape may evolve, the overarching trend toward the great rejuvenation of the Chinese nation will not change.", refZh: "无论国际形势如何演变,中华民族伟大复兴的大趋势不会改变。" },
                    { eng: "This is a responsibility that the CPC and the KMT cannot shirk, and also a driving force for the two parties to work together.", refZh: "这是国共两党不可推卸的责任,也是携手合作的动力。" }
                ]
            }
        },
        { // 热词02 哪吒2
            id: 1,
            name: "🎬 02 哪吒2 · 票房传奇",
            completed: false,
            scoreEarned: 0,
            unlocked: false,
            tasks: {
                truefalse: [
                    { text: "《哪吒2》全球票房超越了《泰坦尼克号》,成为影史票房第三的电影。", isTrue: false, explanation: "它成为第四高票房电影,并非第三。" },
                    { text: "截至4月8日,《哪吒2》全球累计票房达到22.67亿美元。", isTrue: true, explanation: "新闻原文明确提到22.67亿美元。" }
                ],
                multipleChoice: [
                    { question: "《哪吒2》的票房成绩在影史排名第几?", options: ["第二", "第三", "第四", "第五"], correct: 2, explanation: "猫眼数据显示,已升至全球第四。" },
                    { question: "“blockbuster”在电影语境中最合适的含义是?", options: ["票房惨败", "大片/非常成功的电影", "小众艺术片", "动画短片"], correct: 1, explanation: "blockbuster指一鸣惊人的大片。" }
                ],
                matching: {
                    left: ["box office haul", "overtake", "epic"],
                    right: ["票房总收入", "超越", "史诗巨制"]
                },
                sightTranslation: [
                    { eng: "Chinese animated blockbuster 'Ne Zha 2' has overtaken 'Titanic' to become the fourth-highest-grossing film in global box office history.", refZh: "中国动画大片《哪吒2》已超越《泰坦尼克号》,成为全球影史票房第四的电影。" },
                    { eng: "The film's worldwide box office haul reached 2.267 billion dollars, lifting it past James Cameron's 1997 epic.", refZh: "该片全球票房达到22.67亿美元,超越了詹姆斯·卡梅隆1997年的史诗巨制。" }
                ]
            }
        },
        { // 热词03 全红婵遭网暴
            id: 2,
            name: "🤺 03 全红婵 · 向网暴说不",
            completed: false,
            scoreEarned: 0,
            unlocked: false,
            tasks: {
                truefalse: [
                    { text: "国家体育总局游泳中心对全红婵遭遇网暴事件保持沉默,未作回应。", isTrue: false, explanation: "体育部门发布了联合声明,谴责网络暴力并报警。" },
                    { text: "网暴言论可能源于一个200多人的微信群,群公告针对全红婵有攻击性内容。", isTrue: true, explanation: "媒体报道群公告明确写‘禁止攻击其他运动员(全红婵除外)’。" }
                ],
                multipleChoice: [
                    { question: "体育部门针对全红婵事件采取的措施不包括以下哪一项?", options: ["开展核查处置工作", "向警方报案", "加强运动员权益保障", "永久关闭所有粉丝群"], correct: 3, explanation: "声明提及核查、报案及抵制畸形饭圈,并未一刀切关闭所有群。" },
                    { question: "以下哪个词汇最符合‘derogatory nicknames’的意思?", options: ["亲切昵称", "侮辱性外号", "官方头衔", "匿名账号"], correct: 1, explanation: "derogatory意为贬低的,侮辱性的。" }
                ],
                matching: {
                    left: ["cyberbully", "toxic fan culture", "medalist"],
                    right: ["网络暴力", "畸形饭圈文化", "奖牌获得者"]
                },
                sightTranslation: [
                    { eng: "Chinese sports authorities condemned online abuse after three-time Olympic gold medalist Quan Hongchan was targeted by cyberbullying.", refZh: "在三金得主全红婵遭受网暴后,中国体育部门谴责了网络暴力行为。" },
                    { eng: "According to reports, the abuse may have originated from a WeChat group of over 200 members.", refZh: "据报道,这些攻击可能源于一个200多人的微信群。" }
                ]
            }
        },
        { // 热词04 陈丽华去世
            id: 3,
            name: "🌺 04 陈丽华 · 紫檀传奇",
            completed: false,
            scoreEarned: 0,
            unlocked: false,
            tasks: {
                truefalse: [
                    { text: "陈丽华曾是中国女首富,2016年财富总额达505亿元人民币。", isTrue: true, explanation: "胡润2016女富豪榜显示其财富505亿元。" },
                    { text: "陈丽华曾任全国政协港澳台侨委员会主任委员。", isTrue: false, explanation: "她担任的是副主任委员。" }
                ],
                multipleChoice: [
                    { question: "陈丽华的主要荣誉身份不包括?", options: ["中国紫檀博物馆馆长", "联合国杰出亚裔女性终身成就奖", "富华国际集团名誉主席", "中国美术家协会主席"], correct: 3, explanation: "她是企业家、博物馆馆长,并非美协主席。" },
                    { question: "讣告中‘liaison’在‘Committee on Liaison with Hong Kong, Macao, Taiwan and Overseas Chinese’的含义是?", options: ["联络", "私通", "隔离", "行政"], correct: 0, explanation: "这里指联络委员会。" }
                ],
                matching: {
                    left: ["obituary", "sandalwood", "net worth"],
                    right: ["讣告", "檀香木/紫檀", "净资产"]
                },
                sightTranslation: [
                    { eng: "Chen Lihua, Honorary Chairman of Fu Wah International Enterprises Group and Director of the China Red Sandalwood Museum, passed away at the age of 85.", refZh: "富华国际集团名誉主席、中国紫檀博物馆馆长陈丽华逝世,享年85岁。" },
                    { eng: "Having served as a CPPCC member for five consecutive terms, she was also vice chairperson of several committees.", refZh: "她曾连任五届全国政协委员,并担任多个委员会副主任。" }
                ]
            }
        }
    ];

    // 全局状态
    let currentLevelId = 0;          // 当前打开关卡索引
    let totalScore = 0;
    let levelAnswers = {};            // 存储每个关卡的选择/判断/连线/视译临时答案
    
    // 连线配对状态存储 (每个关卡独立)
    let matchPairsState = {};          // { levelId: { pairs: [{leftIdx, rightIdx}], leftSelected, rightSelected } }

    // DOM 元素
    const levelTabsDiv = document.getElementById('levelTabs');
    const quizPanel = document.getElementById('quizPanel');
    const totalScoreSpan = document.getElementById('totalScoreDisplay');
    const progressSpan = document.getElementById('progressDisplay');

    function saveGlobalScore() {
        totalScore = levels.reduce((sum, lvl) => sum + (lvl.completed ? lvl.scoreEarned : 0), 0);
        totalScoreSpan.innerText = totalScore;
        const completedCount = levels.filter(l => l.completed).length;
        progressSpan.innerText = completedCount;
        // 解锁逻辑:完成前一关自动解锁下一个未解锁关卡
        for (let i = 0; i < levels.length; i++) {
            if (i === 0) levels[i].unlocked = true;
            else if (levels[i-1].completed && !levels[i].unlocked) {
                levels[i].unlocked = true;
            }
        }
        renderTabs();
    }

    function renderTabs() {
        levelTabsDiv.innerHTML = '';
        levels.forEach((level, idx) => {
            const tab = document.createElement('div');
            tab.className = `level-tab ${currentLevelId === idx ? 'active' : ''} ${level.completed ? 'completed-tab' : ''} ${!level.unlocked ? 'locked-tab' : ''}`;
            tab.innerText = `${level.name} ${level.completed ? '✓' : ''}`;
            if (level.unlocked) {
                tab.addEventListener('click', () => {
                    if (level.unlocked) {
                        currentLevelId = idx;
                        renderCurrentLevel();
                        renderTabs();
                    }
                });
            } else {
                tab.style.cursor = 'not-allowed';
            }
            levelTabsDiv.appendChild(tab);
        });
    }

    // 初始化某关卡的连线配对存储
    function initMatchStorage(levelId, leftLen, rightLen) {
        if (!matchPairsState[levelId]) {
            matchPairsState[levelId] = {
                pairs: [],          // 存储配对 {leftIdx, rightIdx}
                leftSelected: null,
                rightSelected: null
            };
        }
    }

    // 渲染当前关卡所有题型
    function renderCurrentLevel() {
        const level = levels[currentLevelId];
        if (!level) return;
        const tasks = level.tasks;
        // 构建html
        let html = `<div class="section-title">📖 ${level.name} · 题型闯关</div>`;
        
        // 1. 判断题区域
        html += `<div style="margin-bottom: 30px;"><h3>⚖️ 判断题 (每题5分)</h3>`;
        tasks.truefalse.forEach((item, idx) => {
            const saved = levelAnswers[`tf_${currentLevelId}_${idx}`];
            html += `
                <div class="question-card">
                    <div class="question-text">${idx+1}. ${item.text}</div>
                    <div class="options">
                        <div class="opt-btn" data-type="tf" data-qidx="${idx}" data-val="true">✅ 正确</div>
                        <div class="opt-btn" data-type="tf" data-qidx="${idx}" data-val="false">❌ 错误</div>
                    </div>
                    <div id="tf_fb_${idx}" class="feedback"></div>
                </div>
            `;
        });
        html += `</div>`;

        // 2. 选择题区域
        html += `<div style="margin-bottom: 30px;"><h3>🔍 选择题 (每题8分)</h3>`;
        tasks.multipleChoice.forEach((mc, idx) => {
            const saved = levelAnswers[`mc_${currentLevelId}_${idx}`];
            html += `<div class="question-card">
                        <div class="question-text">${idx+1}. ${mc.question}</div>
                        <div class="options">`;
            mc.options.forEach((opt, optIdx) => {
                html += `<div class="opt-btn" data-type="mc" data-qidx="${idx}" data-opt="${optIdx}">${String.fromCharCode(65+optIdx)}. ${opt}</div>`;
            });
            html += `</div><div id="mc_fb_${idx}" class="feedback"></div></div>`;
        });
        html += `</div>`;

        // 3. 连线题区域
        const match = tasks.matching;
        const leftItems = match.left;
        const rightItems = match.right;
        initMatchStorage(currentLevelId, leftItems.length, rightItems.length);
        const storage = matchPairsState[currentLevelId];
        // 计算已配对数量用于展示
        const pairedCount = storage.pairs.length;
        html += `<div style="margin-bottom: 30px;"><h3>🔗 连线匹配 (每正确配对一组6分,满分18分)</h3>
                 <div class="match-area">
                    <div class="match-col"><strong>左列(术语)</strong><div id="matchLeftCol">${leftItems.map((l, i) => `<div class="match-item" data-side="left" data-idx="${i}">${l}</div>`).join('')}</div></div>
                    <div class="match-col"><strong>右列(释义)</strong><div id="matchRightCol">${rightItems.map((r, i) => `<div class="match-item" data-side="right" data-idx="${i}">${r}</div>`).join('')}</div></div>
                 </div>
                 <div id="matchStatusMsg" class="paired-info">✔️ 当前配对: ${pairedCount} / ${leftItems.length} 组</div>
                 <div id="matchFeedbackMsg" style="font-size:0.8rem; margin-top:6px;"></div>
                 </div>`;
        
        // 4. 视译题
        html += `<div><h3>🎙️ 视译题 (每句满分12分)</h3>`;
        tasks.sightTranslation.forEach((item, idx) => {
            const savedText = levelAnswers[`sight_${currentLevelId}_${idx}`] || '';
            html += `<div class="sight-card">
                        <div class="eng-sentence">📖 ${item.eng}</div>
                        <textarea rows="2" class="sight-textarea" data-sightidx="${idx}" placeholder="输入中文视译...">${savedText}</textarea>
                        <div id="sight_fb_${idx}" class="feedback"></div>
                        <div style="font-size:0.7rem; opacity:0.6;">参考译文: ${item.refZh.substring(0,70)}…</div>
                    </div>`;
        });
        html += `</div>`;

        html += `<div class="submit-area">
                    <button class="reset-btn" id="resetLevelBtn">🔄 重置本关答案</button>
                    <button class="submit-btn" id="submitLevelBtn">✨ 提交本关 · 获得分数 ✨</button>
                 </div>`;
        if (level.completed) {
            html += `<div class="complete-badge">🏅 本关已通关! 得分: ${level.scoreEarned} 分。可再次练习但分数不重复累计。</div>`;
        }
        quizPanel.innerHTML = html;

        // 绑定事件:判断/选择题高亮及暂存
        document.querySelectorAll('.opt-btn[data-type="tf"]').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const qidx = parseInt(btn.dataset.qidx);
                const val = btn.dataset.val === 'true';
                const parentDiv = btn.closest('.question-card');
                parentDiv.querySelectorAll('.opt-btn').forEach(b => b.classList.remove('selected'));
                btn.classList.add('selected');
                levelAnswers[`tf_${currentLevelId}_${qidx}`] = val;
                // 清除旧反馈
                document.getElementById(`tf_fb_${qidx}`).innerHTML = '';
            });
        });
        document.querySelectorAll('.opt-btn[data-type="mc"]').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const qidx = parseInt(btn.dataset.qidx);
                const opt = parseInt(btn.dataset.opt);
                const parentDiv = btn.closest('.question-card');
                parentDiv.querySelectorAll('.opt-btn').forEach(b => b.classList.remove('selected'));
                btn.classList.add('selected');
                levelAnswers[`mc_${currentLevelId}_${qidx}`] = opt;
                document.getElementById(`mc_fb_${qidx}`).innerHTML = '';
            });
        });

        // 连线逻辑重新挂载
        attachMatchEvents(currentLevelId, leftItems, rightItems);
        // 视译输入暂存
        document.querySelectorAll('.sight-textarea').forEach(ta => {
            const idx = parseInt(ta.dataset.sightidx);
            ta.addEventListener('input', (e) => {
                levelAnswers[`sight_${currentLevelId}_${idx}`] = ta.value;
            });
        });
        // 重置按钮
        document.getElementById('resetLevelBtn')?.addEventListener('click', () => resetCurrentLevel());
        // 提交得分按钮
        document.getElementById('submitLevelBtn')?.addEventListener('click', () => evaluateAndSubmit());
    }

    function attachMatchEvents(levelId, leftArr, rightArr) {
        const storage = matchPairsState[levelId];
        if (!storage) return;
        const leftItemsDom = document.querySelectorAll('.match-item[data-side="left"]');
        const rightItemsDom = document.querySelectorAll('.match-item[data-side="right"]');
        const updateHighlight = () => {
            leftItemsDom.forEach(l => l.classList.remove('selected-match'));
            rightItemsDom.forEach(r => r.classList.remove('selected-match'));
            if(storage.leftSelected !== null) {
                const target = document.querySelector(`.match-item[data-side="left"][data-idx="${storage.leftSelected}"]`);
                if(target) target.classList.add('selected-match');
            }
            if(storage.rightSelected !== null) {
                const target = document.querySelector(`.match-item[data-side="right"][data-idx="${storage.rightSelected}"]`);
                if(target) target.classList.add('selected-match');
            }
        };
        const makePair = (leftIdx, rightIdx) => {
            const leftWord = leftArr[leftIdx];
            const rightWord = rightArr[rightIdx];
            // 验证配对是否正确 (依据热词内容)
            const expectedPairs = [
                {l:"overarching trend", r:"首要趋势"},{l:"national rejuvenation", r:"民族复兴"},{l:"shirk responsibility", r:"推卸责任"},
                {l:"box office haul", r:"票房总收入"},{l:"overtake", r:"超越"},{l:"epic", r:"史诗巨制"},
                {l:"cyberbully", r:"网络暴力"},{l:"toxic fan culture", r:"畸形饭圈文化"},{l:"medalist", r:"奖牌获得者"},
                {l:"obituary", r:"讣告"},{l:"sandalwood", r:"檀香木/紫檀"},{l:"net worth", r:"净资产"}
            ];
            let isValid = expectedPairs.some(p => (p.l === leftWord && p.r === rightWord));
            if(isValid && !storage.pairs.some(p => p.left === leftIdx && p.right === rightIdx)) {
                storage.pairs.push({left: leftIdx, right: rightIdx});
                document.getElementById('matchStatusMsg').innerHTML = `✔️ 当前配对: ${storage.pairs.length} / ${leftArr.length} 组`;
                document.getElementById('matchFeedbackMsg').innerHTML = '✅ 配对成功!';
                setTimeout(()=>{if(document.getElementById('matchFeedbackMsg')) document.getElementById('matchFeedbackMsg').innerHTML = '';}, 1000);
            } else if(!isValid){
                document.getElementById('matchFeedbackMsg').innerHTML = '❌ 配对错误,请匹配正确术语';
                setTimeout(()=>{if(document.getElementById('matchFeedbackMsg')) document.getElementById('matchFeedbackMsg').innerHTML = '';}, 1000);
            }
            storage.leftSelected = null;
            storage.rightSelected = null;
            updateHighlight();
        };
        const onLeftClick = (e) => {
            const leftIdx = parseInt(e.currentTarget.dataset.idx);
            if(storage.rightSelected !== null) {
                makePair(leftIdx, storage.rightSelected);
                storage.rightSelected = null;
            } else {
                storage.leftSelected = leftIdx;
                storage.rightSelected = null;
                updateHighlight();
            }
        };
        const onRightClick = (e) => {
            const rightIdx = parseInt(e.currentTarget.dataset.idx);
            if(storage.leftSelected !== null) {
                makePair(storage.leftSelected, rightIdx);
                storage.leftSelected = null;
            } else {
                storage.rightSelected = rightIdx;
                storage.leftSelected = null;
                updateHighlight();
            }
        };
        leftItemsDom.forEach(el => { el.removeEventListener('click', onLeftClick); el.addEventListener('click', onLeftClick); });
        rightItemsDom.forEach(el => { el.removeEventListener('click', onRightClick); el.addEventListener('click', onRightClick); });
        updateHighlight();
    }

    function resetCurrentLevel() {
        const level = levels[currentLevelId];
        if(level.completed) { alert("本关已通关,重置不会清除已获分数,但会清空答题记录。"); }
        // 清空存储的临时答案
        for(let key in levelAnswers) {
            if(key.includes(`_${currentLevelId}_`)) delete levelAnswers[key];
        }
        if(matchPairsState[currentLevelId]) matchPairsState[currentLevelId] = { pairs: [], leftSelected: null, rightSelected: null };
        renderCurrentLevel();
    }

    function evaluateAndSubmit() {
        const level = levels[currentLevelId];
        if(level.completed) {
            alert(`本关已通关,得分 ${level.scoreEarned}。再次练习不重复计分。`);
            return;
        }
        let score = 0;
        const tasks = level.tasks;
        // 判断评分
        tasks.truefalse.forEach((item, idx) => {
            const user = levelAnswers[`tf_${currentLevelId}_${idx}`];
            const isCor = (user === item.isTrue);
            const fbDiv = document.getElementById(`tf_fb_${idx}`);
            if(isCor) { score += 5; if(fbDiv) fbDiv.innerHTML = '✓ 正确 +5分'; fbDiv.className = 'feedback correct-fb';}
            else { if(fbDiv) fbDiv.innerHTML = `✗ 错误。正确答案: ${item.isTrue ? '正确' : '错误'}。 ${item.explanation}`; fbDiv.className = 'feedback wrong-fb';}
        });
        // 选择题
        tasks.multipleChoice.forEach((mc, idx) => {
            const userOpt = levelAnswers[`mc_${currentLevelId}_${idx}`];
            const correct = (userOpt === mc.correct);
            const fbDiv = document.getElementById(`mc_fb_${idx}`);
            if(correct) { score += 8; if(fbDiv) fbDiv.innerHTML = '✓ 正确 +8分'; fbDiv.className = 'feedback correct-fb';}
            else { if(fbDiv) fbDiv.innerHTML = `✗ 错误。正确答案: ${mc.options[mc.correct]}。${mc.explanation}`; fbDiv.className = 'feedback wrong-fb';}
        });
        // 连线评分 每组6分 上限18
        const matchStore = matchPairsState[currentLevelId];
        let matchPoints = 0;
        if(matchStore && matchStore.pairs) {
            matchPoints = Math.min(18, matchStore.pairs.length * 6);
            score += matchPoints;
            document.getElementById('matchStatusMsg').innerHTML += `  · 获得连线分 ${matchPoints}/18`;
        }
        // 视译评分 (每题12分, 酌情给分)
        let sightScore = 0;
        tasks.sightTranslation.forEach((item, idx) => {
            const userTrans = levelAnswers[`sight_${currentLevelId}_${idx}`] || '';
            let pts = 0;
            if(userTrans.trim().length >= 6) pts = 8;
            if(userTrans.includes(item.refZh.substring(2,12)) || userTrans.length > 15) pts = 12;
            if(userTrans.trim() === item.refZh) pts = 12;
            else if(userTrans.length>0 && pts===0) pts=4;
            sightScore += pts;
            const fbSpan = document.getElementById(`sight_fb_${idx}`);
            if(fbSpan) fbSpan.innerHTML = `视译得分: ${pts}/12  (参考: ${item.refZh.substring(0,45)}…)`;
        });
        score += sightScore;
        score = Math.min(100, score);
        // 通关记录
        level.completed = true;
        level.scoreEarned = score;
        saveGlobalScore();
        renderCurrentLevel();   // 刷新显示通关标志
        alert(`🏆 恭喜通关「${level.name}」\n获得 ${score}/100 分!总积分已达 ${totalScore+score} 分`);
        renderTabs();
    }

    // 初始化渲染
    function init() {
        saveGlobalScore();
        renderTabs();
        renderCurrentLevel();
    }
    init();
</script>
</body>
</html>

Game Source: 视译后练习 · 热词闯关 | 口译多元挑战

Creator: RocketGecko40

Libraries: none

Complexity: complex (733 lines, 34.0 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-rocketgecko40" to link back to the original. Then publish at arcadelab.ai/publish.