吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8467|回复: 157
收起左侧

[其他原创] 用HTML制作的刷题小软件

    [复制链接]
xiaozhangben 发表于 2025-8-2 18:41
本帖最后由 xiaozhangben 于 2025-8-6 09:35 编辑

用html代码写的一个刷题小软件,可以用来刷题,离线,单机,浏览器打开即可。
题界面如下
主界面:
界面1.png
答题界面
界面2.PNG
解析界面
界面3.PNG

软件主要功能介绍

“我要答题” 软件是一款基于 Excel 题库的在线答题工具,主要功能可分为题库管理、答题模式、答题交互、结果反馈及辅助功能五大类,具体如下:
一、题库管理功能

文件导入

支持导入.xlsx和.xls格式的 Excel 题库文件,自动解析文件内容。

提供 “题库示例下载” 功能,示例包含标准格式(问题、选项 A-F、解析、答案)及多种答案类型示例(字母、数字、对 / 错等)。

题库解析

自动识别 Excel 中的 “问题、选项(A-F)、解析、答案” 列,支持多种答案格式(A-F、1-6、正确 / 错误、对 / 错、Y/N,不区分大小写)。

跳过解析错误的行(如格式不符、答案无效),并在调试信息中显示错误详情(行数及原因)。

二、答题模式选择
提供 4 种答题模式,满足不同练习需求:

顺序答题(顺序选项):按题库原始顺序展示题目,选项顺序不变。

顺序答题(随机选项):按原始顺序展示题目,选项随机打乱。

随机抽取(顺序选项):从题库中随机抽取指定数量题目(可自定义数量),选项顺序不变。

随机抽取(随机选项):随机抽取题目,且选项随机打乱。

此外,支持 “考试模式”:

特点:完成所有题目后统一显示答案和解析,过程中不可通过答题卡跳题,提交后直接进入下一题,无即时反馈。

三、答题交互功能
答题界面

显示当前题目文本、选项(带 A-F 标签),支持单选 / 多选(根据题目设置)。

提供 “上一题 / 下一题” 导航按钮,最后一题显示 “完成测验”。

答题卡功能

实时展示所有题目的状态:未答(灰色)、当前(蓝色)、正确(绿色)、错误(红色)。

非考试模式下,可点击已答题目的答题卡按钮跳转查看;考试模式下仅允许查看当前题。

答案提交

提交后标记题目状态(已答 / 正确 / 错误),更新得分及统计数据(已答数、正确数)。

非考试模式下支持即时修改答案(重新选择后提交会更新得分)。

四、结果反馈与数据处理
即时反馈(非考试模式)

提交答案后显示 “正确 / 错误” 提示,错误时标注正确答案。

显示解析内容(即使为空也会提示 “暂无解析内容”)。

最终结果统计

显示总分、正确率(得分 / 总题数)、总题数、答对 / 答错题数。

考试模式下,详细展示每道题的答题情况:你的答案、正确答案、选项详情及解析,并按 “正确 / 错误” 分类标注。

错题导出

支持将所有错题导出为 Excel 格式的 “错题集”,保留原始题库格式(问题、选项、解析、正确答案),方便针对性复习。

五、辅助功能
调试信息:可切换显示解析错误详情(如行数、错误原因),帮助排查题库格式问题。

响应式设计:适配手机、电脑等不同设备屏幕,按钮及布局会根据屏幕尺寸调整。



初代版本仅支持csv题库

下载地址:我要答题csv格式题库版   https://wwsw.lanzouo.com/tp/iJdSE32dv02h



下面是20250803更新
看大家答题需求挺高的,根据大家建议,更新一下支持excel题库版,兼容性更好。
根据网友建议做了一些修改:
增加了错题导出功能,增加了题库示例。判断题答案支持更多的格式的答案。
有网环境只需要html网页就可以,无网环境需要有xlsx.full.min.js和xls.min.js,源代码中有下载地址,放在和网页同目录。


下载地址:我要答题(EXCEL题库版) https://wwsw.lanzouo.com/tp/iZaKl32icvbi


下面是20250804更新,新增随机N题答题功能。

下载地址:我要答题(EXCEL格式题库、随机N题) https://wwsw.lanzouo.com/tp/iCgRw32ls7ob



下面是20250805更新,新增选项乱序答题功能。

下载地址:我要答题(EXCEL格式题库、随机N题、随机选项) https://wwsw.lanzouo.com/tp/iiQsL32o91xi



下面是20250806更新,新增支持带解析题库功能。

下载地址:我要答题(EXCEL格式题库、随机N题、随机选项、增加解析)https://wwsw.lanzouo.com/tp/idrqZ32rbt2f





下面是20250806最终更新,新增支持考试模式功能。

下载地址: 我要答题(EXCEL格式题库、随机N题、随机选项、增加解析,考试模式)https://wwsw.lanzouo.com/tp/iC21y32rbtkd
论坛附件: 我要答题(EXCEL格式题库、随机N题、随机选项、增加解析,考试模式).zip (375.79 KB, 下载次数: 372)

下面是原代码:

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<title>我要答题(仅支持Excel题库)</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<!-- 动态加载脚本,优先CDN,失败则使用本地文件 -->
<script>
// 加载脚本函数,带 fallback 机制
function loadScript(src, fallbackSrc, componentName, callback) {
    const script = document.createElement('script');
    script.src = src;
    
    script.onload = function() {
        console.log(`${componentName} (CDN) 加载成功`);
        if (callback) callback(true);
    };
    
    script.onerror = function() {
        console.log(`CDN加载失败,尝试加载本地${componentName}: ${fallbackSrc}`);
        const fallbackScript = document.createElement('script');
        fallbackScript.src = fallbackSrc;
        
        fallbackScript.onload = function() {
            console.log(`本地${componentName}加载成功`);
            if (callback) callback(true);
        };
        
        fallbackScript.onerror = function() {
            console.error(`本地${componentName}加载失败: ${fallbackSrc}`);
            alert(`无法加载必要的${componentName}组件,请检查网络连接或文件完整性`);
            if (callback) callback(false);
        };
        
        document.head.appendChild(fallbackScript);
    };
    
    document.head.appendChild(script);
}

// 先加载xlsx,完成后再加载xls(因为xls可能依赖xlsx)
loadScript(
    'https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js',
    'xlsx.full.min.js',
    'xlsx',
    function(xlsxLoaded) {
        // 无论xlsx是否加载成功,都尝试加载xls
        loadScript(
            'https://cdn.jsdelivr.net/npm/xlsjs@0.7.6/dist/xls.min.js',
            'xls.min.js',
            'xls',
            function(xlsLoaded) {
                if (xlsxLoaded || xlsLoaded) {
                    console.log('至少有一个Excel处理组件加载成功');
                } else {
                    console.log('所有Excel处理组件都加载失败');
                }
            }
        );
    }
);
</script>
<style>
/* 保持原有样式不变 */
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:linear-gradient(to bottom right,#f3f4f6,#e5e7eb);min-height:100vh;color:#1f2937;line-height:1.5;padding-bottom:2rem}
.container{max-width:1200px;margin:0 auto;padding:2rem 1rem}
header{text-align:center;margin:1.5rem 0 2rem}
h1{font-size:clamp(1.8rem,5vw,2.5rem);font-weight:bold;background:linear-gradient(to right,#3B82F6,#8B5CF6);-webkit-background-clip:text;background-clip:text;color:transparent}
.subtitle{color:#6b7280;font-size:1.125rem}
.card{background:#fff;border-radius:1rem;padding:2rem;box-shadow:0 10px 25px -5px rgba(0,0,0,.05),0 8px 10px -6px rgba(0,0,0,.02);margin-bottom:2rem}
.btn{display:inline-flex;align-items:center;justify-content:center;font-weight:500;padding:.75rem 1.5rem;border-radius:.75rem;border:none;cursor:pointer;transition:all .3s;
    min-width: 160px;
    height: 50px;
    font-size: 1rem;
    box-sizing: border-box;
}
.btn-two-lines {
    flex-direction: column;
    padding: 0.5rem 1rem;
    min-width: 140px;
    white-space: normal;
    text-align: center;
}
.btn:hover{transform:translateY(-2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1)}
.btn-primary{background:#3B82F6;color:#fff}
.btn-secondary{background:#10B981;color:#fff}
.btn-gray{background:#e5e7eb;color:#4b5563}
.btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
.file-import{max-width:700px;margin:0 auto;text-align:center}
#file-upload{display:none}
.file-info{margin-top:1rem;display:none}
.help-text{color:#6b7280;font-size:.875rem;margin-top:1rem}
.flex-container{display:flex;flex-direction:column;gap:1.5rem;max-width:1100px;margin:0 auto}
@media(min-width:1024px){.flex-container{flex-direction:row}.main-content{width:700px;flex-shrink:0}.sidebar{width:300px;flex-shrink:0}}
.quiz-controls{display:none;justify-content:space-between;align-items:center;margin-bottom:1.5rem}
.quiz-controls.show{display:flex}
.question-count{font-size:1.125rem;font-weight:500}
.total-questions{color:#6b7280;margin-left:.5rem}
.score-display{background:#fff;padding:.5rem 1rem;border-radius:9999px;font-size:.875rem}
.score-value{font-weight:bold;color:#3B82F6;margin-left:.25rem}
.question-section{display:none}
.question-section.show{display:block}
.question-type{display:inline-block;padding:.5rem .75rem;background:rgba(59,130,246,.1);color:#3B82F6;font-size:.875rem;font-weight:500;border-radius:9999px;margin-bottom:1rem}
.question-text{font-size:1.25rem;font-weight:600;margin-bottom:1.5rem;color:#1f2937;white-space:pre-wrap;word-wrap:break-word}
@media(min-width:768px){.question-text{font-size:1.5rem}}
.options-container{margin-bottom:2rem;display:flex;flex-direction:column;gap:.75rem}
.option{padding:1rem;border:1px solid #e5e7eb;border-radius:.75rem;cursor:pointer;transition:all .2s;white-space:pre-line}
.option:hover{background:rgba(59,130,246,.1)}
.option.selected{border-color:#3B82F6;background:rgba(59,130,246,.05)}
.option-label{display:flex}
.option-letter{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;margin-right:.75rem;font-weight:500}
.option.selected .option-letter{background:#3B82F6;color:#fff}
.option:not(.selected) .option-letter{background:rgba(59,130,246,.1);color:#3B82F6}
.button-group{display:flex;justify-content:space-between;margin-top:1.5rem}
.confirm-btn-container{text-align:center;margin-bottom:1.5rem}
.feedback{padding:1rem;border-radius:.5rem;margin-bottom:1.5rem;display:none;align-items:center}
.feedback.show{display:flex}
.feedback-success{background:#f0fdf4;border:1px solid #dcfce7;color:#166534}
.feedback-error{background:#fee2e2;border:1px solid #fecaca;color:#b91c1c}
.explanation {
    padding: 1.25rem;
    border-radius: 0.75rem;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    margin-bottom: 1.5rem;
    display: none;
}
.explanation.show {
    display: block;
}
.explanation-title {
    font-weight: 600;
    color: #334155;
    margin-bottom: 0.5rem;
    display: flex;
    align-items: center;
}
.explanation-title svg {
    margin-right: 0.5rem;
    width: 1.25rem;
    height: 1.25rem;
}
.explanation-content {
    color: #475569;
    line-height: 1.6;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.results-section{display:none;text-align:center;max-width:700px;margin:0 auto}
.results-section.show{display:block}
.results-title{font-size:1.5rem;font-weight:600;margin-bottom:.5rem}
.results-subtitle{color:#6b7280;margin-bottom:2rem}
.score-circle{display:flex;align-items:center;justify-content:center;width:9rem;height:9rem;border-radius:50%;background:linear-gradient(to bottom right,#3B82F6,#8B5CF6);margin:0 auto 2rem;color:#fff;text-align:center}
.final-score{font-size:3rem;font-weight:bold}
.final-total{font-size:1.5rem;font-weight:600}
.results-buttons{display:flex;justify-content:center;gap:1rem;margin-top:2rem}
.error-section{display:none;text-align:center;max-width:700px;margin:0 auto}
.error-section.show{display:block}
.error-icon-container{display:inline-flex;align-items:center;justify-content:center;width:4rem;height:4rem;border-radius:50%;background:#fee2e2;margin-bottom:1rem}
.error-icon{color:#dc2626;font-size:2rem}
.error-title{font-size:1.5rem;font-weight:600;color:#dc2626;margin-bottom:.5rem}
.error-message{color:#6b7280;margin-bottom:1.5rem}
.debug-info{font-size:.875rem;background:#f3f4f6;padding:1rem;border-radius:.5rem;margin-bottom:1.5rem;max-height:10rem;overflow-y:auto;display:none}
.debug-info.show{display:block}
.answer-sheet-section{display:none}
.answer-sheet-section.show{display:block}
.answer-sheet{position:sticky;top:1rem;max-height:calc(100vh - 2rem);overflow-y:auto}
.answer-sheet-title{font-size:1.125rem;font-weight:600;margin-bottom:1rem;display:flex;align-items:center}
.answer-sheet-icon{margin-right:.5rem;color:#3B82F6}
.answer-stats{display:flex;justify-content:space-between;font-size:.875rem;margin-bottom:1rem}
.stat-label{color:#6b7280}
.stat-value{font-weight:500}
.answer-sheet-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:.5rem;margin-bottom:1rem}
.answer-sheet-btn{width:2rem;height:2rem;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.875rem;font-weight:500;border:none;cursor:pointer;transition:all .2s}
.answer-sheet-btn.unanswered{background:#e5e7eb;color:#4b5563}
.answer-sheet-btn.current{background:#3B82F6;color:#fff}
.answer-sheet-btn.correct{background:#10B981;color:#fff}
.answer-sheet-btn.incorrect{background:#EF4444;color:#fff}
.legend{display:flex;align-items:center;font-size:.75rem;gap:1rem;flex-wrap:wrap}
.legend-color{width:1rem;height:1rem;border-radius:50%;margin-right:.25rem}
.debug-toggle-btn{margin-top:0;background:transparent;border:1px solid #6b7280;color:#6b7280;padding:.5rem 1rem;border-radius:.5rem;cursor:pointer;font-size:.875rem;transition:all .3s}
.debug-toggle-btn:hover{background:rgba(59,130,246,.1);border-color:#3B82F6;color:#3B82F6}
.start-quiz-section{text-align:center;padding:1rem 0 2rem}
.btn-group {
  display: flex;
  gap: 1rem;
  justify-content: center;
  margin-bottom: 1rem;
  flex-wrap: wrap;
  align-items: center;
}

.status-unanswered { color: #e5e7eb; }
.status-current { color: #3B82F6; }
.status-correct { color: #10B981; }
.status-incorrect { color: #EF4444; }

.random-question-input {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0;
  justify-content: center;
  flex-wrap: wrap;
}

.random-question-input input {
  width: 80px;
  padding: 0.75rem;
  border: 1px solid #e5e7eb;
  border-radius: 0.75rem;
  font-size: 1rem;
  text-align: center;
  height: 50px;
  box-sizing: border-box;
}

.random-question-input input:focus {
  outline: none;
  border-color: #3B82F6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.mode-selection {
  margin-top: 0.5rem;
}

.mode-label {
  display: block;
  margin-bottom: 0.5rem;
  color: #6b7280;
  font-weight: 500;
}

.debug-and-random-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  margin-top: 0.5rem;
}

.exam-mode-checkbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem 0;
  font-weight: 500;
  color: #374151;
}

.exam-mode-checkbox input {
  width: 1.2rem;
  height: 1.2rem;
  accent-color: #3B82F6;
}

/* 考试模式结果页面样式 */
.exam-results-details {
  margin-top: 2rem;
  text-align: left;
  max-height: 60vh;
  overflow-y: auto;
  padding-right: 1rem;
}

.exam-question-item {
  padding: 1.5rem;
  border-radius: 0.75rem;
  margin-bottom: 1.5rem;
  border: 1px solid #e5e7eb;
}

.exam-question-item.correct {
  border-color: #dcfce7;
  background-color: #f0fdf4;
}

.exam-question-item.incorrect {
  border-color: #fecaca;
  background-color: #fee2e2;
}

.exam-question-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 1rem;
  align-items: center;
}

.exam-question-number {
  font-weight: 600;
  color: #1f2937;
}

.exam-question-status {
  padding: 0.25rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.875rem;
  font-weight: 500;
}

.exam-question-status.correct {
  background-color: #dcfce7;
  color: #166534;
}

.exam-question-status.incorrect {
  background-color: #fecaca;
  color: #b91c1c;
}

.exam-question-text {
  font-weight: 500;
  margin-bottom: 1rem;
  color: #1f2937;
}

.exam-options {
  margin-bottom: 1rem;
}

.exam-option {
  padding: 0.5rem;
  margin-bottom: 0.5rem;
  border-radius: 0.5rem;
  display: flex;
  align-items: flex-start;
}

.exam-option.selected {
  background-color: rgba(59, 130, 246, 0.1);
  border-left: 3px solid #3B82F6;
}

.exam-option.correct-answer {
  background-color: rgba(16, 185, 129, 0.1);
  border-left: 3px solid #10B981;
}

.exam-option-letter {
  font-weight: 600;
  margin-right: 0.75rem;
  min-width: 1.5rem;
  text-align: center;
}

.exam-answer-info {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed #e5e7eb;
}

.exam-your-answer, .exam-correct-answer {
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
}

.exam-answer-label {
  font-weight: 600;
  color: #4b5563;
  margin-right: 0.5rem;
}

.exam-result-summary {
  margin-bottom: 2rem;
  padding: 1.5rem;
  border-radius: 0.75rem;
  background-color: #f8fafc;
  border: 1px solid #e2e8f0;
}

.exam-score-percentage {
  font-size: 1.5rem;
  font-weight: 600;
  color: #3B82F6;
  margin: 1rem 0;
}

@media (max-width: 480px) {
  .btn {
    padding: 0.5rem 1rem;
    font-size: 0.9rem;
    min-width: auto;
    width: 100%;
    height: auto;
  }
  
  .btn-two-lines {
    min-width: auto;
    height: auto;
  }
  
  .random-question-input {
    flex-direction: column;
    margin-top: 1rem;
    width: 100%;
  }
  
  .random-question-input input {
    width: 100%;
    height: auto;
  }
  
  .btn-group {
    flex-direction: column;
    width: 100%;
  }
  
  .btn-group > * {
    width: 100%;
  }
  
  .debug-and-random-container {
    flex-direction: column;
    width: 100%;
  }
  
  .debug-and-random-container > * {
    width: 100%;
  }
  
  .exam-question-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }
}
</style>
</head>
<body>
<div class="container">
  <header>
    <h1>我要答题</h1>
    <p class="subtitle"><small>仅支持Excel (xlsx, xls) 格式题库</small></p>
  </header>

  <div id="file-import-section" class="card file-import">
    <div class="btn-group">
      <label for="file-upload" class="btn btn-primary">选择题库文件</label>
      <button id="download-sample-btn" class="btn btn-secondary">下载题库示例</button>
    </div>
    <input id="file-upload" type="file" accept=".xlsx,.xls">
    <p class="help-text">
      支持格式:XLSX、XLS<br>
      格式要求:问题,选项A,选项B,选项C,选项D,选项E,选项F,解析,答案(连写如ABC);<br>
      答案支持:A-F、1-6(数字索引)、正确/错误、对/错、Y/N(不区分大小写)<br>
      第一行为标题行;解析列内容可以为空<br>
      解析失败的行会被跳过并在调试面板显示。
    </p>
    <div id="file-info" class="file-info">
      <div class="file-info-content"><span>&#10003;</span><span id="selected-filename"></span></div>
    </div>
    
    <div id="start-quiz-section" class="start-quiz-section" style="display: none;">
      <!-- 添加考试模式选择框 -->
      <div class="exam-mode-checkbox">
        <input type="checkbox" id="exam-mode" />
        <label for="exam-mode">考试模式(完成所有题目后统一显示答案和解析)</label>
      </div>
      
      <div class="mode-selection">
        <span class="mode-label">请选择答题模式:</span>
        <div class="btn-group">
          <button id="sequential-quiz-btn" class="btn btn-secondary btn-two-lines">顺序答题<br>顺序选项</button>
          <button id="sequential-shuffle-options-quiz-btn" class="btn btn-secondary btn-two-lines">顺序答题<br>随机选项</button>
          <button id="random-quiz-btn" class="btn btn-primary btn-two-lines">随机抽取<br>顺序选项</button>
          <button id="random-shuffle-options-quiz-btn" class="btn btn-primary btn-two-lines">随机抽取<br>随机选项</button>
        </div>
        
        <div class="debug-and-random-container">
          <button id="debug-toggle" class="debug-toggle-btn">显示调试信息</button>
          <div class="random-question-input">
            <span>随机抽取</span>
            <input type="number" id="random-count" min="1" value="10" />
            <span>题</span>
          </div>
        </div>
      </div>
    </div>
    
    <div id="debug-info" class="debug-info">
      <h4 class="debug-title">调试信息:</h4>
      <p id="debug-details"></p>
    </div>
  </div>

  <div class="flex-container">
    <div class="main-content">
      <div id="quiz-controls" class="quiz-controls">
        <div class="question-count">
          <span id="current-question">问题 1</span>
          <span id="total-questions" class="total-questions">/ 0</span>
        </div>
        <div class="score-display">
          <span>得分:</span>
          <span id="score" class="score-value">0</span>
        </div>
      </div>

      <div id="quiz-section" class="card question-section">
        <div class="question-type">不定项选择题</div>
        <h2 id="question-text" class="question-text"></h2>
        <div id="options-container" class="options-container"></div>
        <div class="confirm-btn-container">
          <button id="confirm-btn" class="btn btn-primary">提交答案</button>
        </div>
        <div id="feedback" class="feedback"></div>
        
        <div id="explanation" class="explanation">
          <div class="explanation-title">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
            </svg>
            解析
          </div>
          <div id="explanation-content" class="explanation-content"></div>
        </div>
        
        <div class="button-group">
          <button id="prev-btn" class="btn btn-gray" disabled>上一题</button>
          <button id="next-btn" class="btn btn-primary" disabled>下一题</button>
        </div>
      </div>

      <div id="results-section" class="card results-section">
        <h2 class="results-title">测验完成!</h2>
        <p class="results-subtitle">恭喜你完成了所有问题</p>
        
        <!-- 考试模式结果摘要 -->
        <div class="exam-result-summary">
          <div class="score-circle">
            <span id="final-score" class="final-score">0</span>
            <span>/</span>
            <span id="final-total" class="final-total">0</span>
          </div>
          <div class="exam-score-percentage" id="score-percentage">得分:0%</div>
          <div>
            <span>总题数:</span><span id="summary-total-count">0</span>
            <span>,答对:</span><span id="summary-correct-count" class="status-correct">0</span>
            <span>,答错:</span><span id="summary-incorrect-count" class="status-incorrect">0</span>
          </div>
        </div>
        
        <!-- 考试模式详细结果 -->
        <div id="exam-results-details" class="exam-results-details"></div>
        
        <div class="results-buttons">
          <button id="restart-btn" class="btn btn-secondary">重新开始</button>
          <button id="export-wrong-btn" class="btn btn-gray">导出错题</button>
          <button id="new-file-btn" class="btn btn-gray">选择新文件</button>
        </div>
      </div>

      <div id="error-section" class="card error-section">
        <div class="error-icon-container"><span class="error-icon">!</span></div>
        <h3 class="error-title">文件处理错误</h3>
        <p id="error-message" class="error-message"></p>
        <div id="error-debug-info" class="debug-info">
          <h4 class="debug-title">调试信息:</h4>
          <p id="error-debug-details"></p>
        </div>
        <button id="retry-btn" class="btn btn-primary">重新选择文件</button>
      </div>
    </div>

    <div id="answer-sheet-section" class="sidebar answer-sheet-section">
      <div class="card answer-sheet">
        <h3 class="answer-sheet-title"><span class="answer-sheet-icon">※</span>答题卡</h3>
        <div class="answer-stats">
          <div><span class="stat-label">已答:</span><span id="answered-count" class="stat-value">0</span></div>
          <div><span class="stat-label">正确:</span><span id="correct-count" class="stat-value stat-correct">0</span></div>
          <div><span class="stat-label">总题数:</span><span id="total-count" class="stat-value">0</span></div>
        </div>
        <div id="answer-sheet-grid" class="answer-sheet-grid"></div>
        <div class="legend">
          <div><span class="legend-color" style="background:#e5e7eb;"></span><span class="status-unanswered">未答</span></div>
          <div><span class="legend-color" style="background:#3B82F6;"></span><span class="status-current">当前</span></div>
          <div><span class="legend-color" style="background:#10B981;"></span><span class="status-correct">正确</span></div>
          <div><span class="legend-color" style="background:#EF4444;"></span><span class="status-incorrect">错误</span></div>
        </div>
      </div>
    </div>
  </div>
</div>

<script>
/* ========= 全局变量 ========= */
let questions = [], originalQuestions = [], current = 0, score = 0, answered = 0, correct = 0;
let status = [];
const valid = ['A','B','C','D','E','F'];
let parsingErrors = [];
let originalFileName = '';
let isExamMode = false; // 新增:考试模式标志

/* ========= DOM 快捷 ========= */
const el = id => document.getElementById(id);
const fileUpload = el('file-upload');
const fileImport = el('file-import-section');
const quiz = el('quiz-section');
const results = el('results-section');
const errorSec = el('error-section');
const controls = el('quiz-controls');
const answerSheet = el('answer-sheet-section');
const answerGrid = el('answer-sheet-grid');
const answeredEl = el('answered-count');
const correctEl = el('correct-count');
const totalEl = el('total-count');
const filenameEl = el('selected-filename');
const qText = el('question-text');
const qNum = el('current-question');
const qTotal = el('total-questions');
const scoreEl = el('score');
const confirmBtn = el('confirm-btn');
const prevBtn = el('prev-btn');
const nextBtn = el('next-btn');
const finalScore = el('final-score');
const finalTotal = el('final-total');
const optionsContainer = el('options-container');
const sequentialQuizBtn = el('sequential-quiz-btn');
const randomQuizBtn = el('random-quiz-btn');
const sequentialShuffleOptionsQuizBtn = el('sequential-shuffle-options-quiz-btn');
const randomShuffleOptionsQuizBtn = el('random-shuffle-options-quiz-btn');
const randomCountInput = el('random-count');
const startQuizSection = el('start-quiz-section');
const debugToggleBtn = el('debug-toggle');
const debugInfo = el('debug-info');
const debugDetails = el('debug-details');
const downloadSampleBtn = el('download-sample-btn');
const explanationEl = el('explanation');
const explanationContentEl = el('explanation-content');
const examModeCheckbox = el('exam-mode'); // 新增:考试模式复选框
const examResultsDetails = el('exam-results-details'); // 新增:考试结果详情容器
const scorePercentage = el('score-percentage'); // 新增:百分比得分
const summaryTotalCount = el('summary-total-count'); // 新增:总题数摘要
const summaryCorrectCount = el('summary-correct-count'); // 新增:答对题数摘要
const summaryIncorrectCount = el('summary-incorrect-count'); // 新增:答错题数摘要

/* ========= 事件绑定 ========= */
fileUpload.addEventListener('change', handleFile);
confirmBtn.addEventListener('click', confirmAnswer);
prevBtn.addEventListener('click', () => go(-1));
nextBtn.addEventListener('click', () => go(1));
el('restart-btn').addEventListener('click', restart);
el('new-file-btn').addEventListener('click', selectNewFile);
el('retry-btn').addEventListener('click', retryFile);
sequentialQuizBtn.addEventListener('click', () => startQuiz('sequential'));
randomQuizBtn.addEventListener('click', () => startQuiz('random'));
sequentialShuffleOptionsQuizBtn.addEventListener('click', () => startQuiz('sequential-shuffle-options'));
randomShuffleOptionsQuizBtn.addEventListener('click', () => startQuiz('random-shuffle-options'));
debugToggleBtn.addEventListener('click', () => debugInfo.classList.toggle('show'));
downloadSampleBtn.addEventListener('click', downloadSampleExcel);
el('export-wrong-btn').addEventListener('click', exportWrongAnswers);

/* ========= 下载题库示例 ========= */
function downloadSampleExcel() {
  // 创建工作簿
  const wb = XLSX.utils.book_new();
  
  // 创建示例数据,列顺序为:问题,选项A,选项B,选项C,选项D,选项E,选项F,解析,答案
  const data = [
    ["问题", "选项A", "选项B", "选项C", "选项D", "选项E", "选项F", "解析", "答案"],
    ["以下哪个不是编程语言?", "JavaScript", "Python", "HTML", "Java", "", "", "HTML是超文本标记语言,不是编程语言", "C"],
    ["以下哪些用于网页前端开发?", "CSS", "Python", "JavaScript", "Java", "", "", "CSS用于样式设计,JavaScript用于交互逻辑", "AC"],
    ["1+1等于几?", "1", "2", "3", "4", "", "", "1+1=2是基本算术", "2"], // 数字答案示例
    ["题库中英文引号要成对使用,单独一个会导致解析错误?", "正确", "错误", "", "", "", "", "", "错误"],
    ["加工贸易货物“短溢区间”管理的幅度是?", "-0.5%,0.5%", "-1%,1%", "-0.5,0.5", "-10%,10%", "", "", "", "B"], // 带百分号的选项示例
    ["以下哪些是编程语言?", "JavaScript", "HTML", "Python", "CSS", "Java", "PHP", "", "ACEF"],
    ["以下哪些是前端框架?", "React", "Django", "Flask", "Spring", "Vue", "Angular", "", "5"], // 数字答案示例
    ["Y/N格式测试", "是", "否", "", "", "", "", "", "Y"], // Y/N格式示例
    ["对/错格式测试", "正确", "错误", "", "", "", "", "", "对"] // 对/错格式示例
  ];
  
  // 创建工作表
  const ws = XLSX.utils.aoa_to_sheet(data);
  
  // 将工作表添加到工作簿
  XLSX.utils.book_append_sheet(wb, ws, "题库示例");
  
  // 下载文件
  XLSX.writeFile(wb, "题库示例.xlsx");
}

/* ========= 导出错题功能 ========= */
function exportWrongAnswers() {
  // 收集所有答错的题目的原始索引
  const wrongQuestionIndices = [];
  questions.forEach((q, index) => {
    if (status[index].answered && !status[index].correct) {
      if (q.originalIndex !== undefined) {
        wrongQuestionIndices.push(q.originalIndex);
      } else {
        wrongQuestionIndices.push(index);
      }
    }
  });
  
  // 去重并按原始顺序排序
  const uniqueWrongIndices = [...new Set(wrongQuestionIndices)].sort((a, b) => a - b);
  
  if (uniqueWrongIndices.length === 0) {
    alert('恭喜你,没有错题!');
    return;
  }
  
  // 准备导出数据,格式与题库一致:问题,选项A,选项B,选项C,选项D,选项E,选项F,解析,答案
  const data = [["问题", "选项A", "选项B", "选项C", "选项D", "选项E", "选项F", "解析", "答案"]];
  
  // 使用原始题库中的题目信息
  uniqueWrongIndices.forEach(index => {
    const originalQuestion = originalQuestions[index];
    if (originalQuestion) {
      const row = [originalQuestion.question];
      
      // 添加原始选项
      originalQuestion.options.forEach(option => row.push(option));
      
      // 填充剩余选项位置(最多6个选项)
      while (row.length < 7) {
        row.push("");
      }
      
      // 添加解析
      row.push(originalQuestion.explanation || "");
      
      // 添加原始正确答案
      row.push(originalQuestion.originalAnswer || originalQuestion.correctAnswers.join(''));
      
      data.push(row);
    }
  });
  
  // 创建工作簿和工作表
  const wb = XLSX.utils.book_new();
  const ws = XLSX.utils.aoa_to_sheet(data);
  
  // 添加工作表到工作簿
  XLSX.utils.book_append_sheet(wb, ws, "错题集");
  
  // 生成文件名
  const now = new Date();
  const dateTimeStr = `${now.getFullYear()}${(now.getMonth()+1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}${now.getSeconds().toString().padStart(2, '0')}`;
  
  const baseFileName = originalFileName.replace(/\.(xlsx|xls)$/i, '');
  const fileName = `${baseFileName}_错题集_${dateTimeStr}.xlsx`;
  
  // 导出文件
  XLSX.writeFile(wb, fileName);
}

/* ========= 随机排序选项功能 ========= */
function shuffleQuestionOptions(question) {
  const shuffledOptions = [...question.options];
  
  // 随机排序选项
  for (let i = shuffledOptions.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffledOptions[i], shuffledOptions[j]] = [shuffledOptions[j], shuffledOptions[i]];
  }
  
  // 找出原始正确答案在打乱后的选项中的位置
  const originalCorrectIndices = question.correctAnswers.map(answer => 
    question.optionLabels.indexOf(answer)
  );
  
  // 计算打乱后的正确答案标签
  const shuffledCorrectAnswers = originalCorrectIndices.map(originalIndex => {
    const newIndex = shuffledOptions.indexOf(question.options[originalIndex]);
    return question.optionLabels[newIndex];
  });
  
  return {
    ...question,
    options: shuffledOptions,
    correctAnswers: shuffledCorrectAnswers,
    originalOptions: question.options,
    originalCorrectAnswers: question.correctAnswers,
    originalIndex: question.originalIndex,
    explanation: question.explanation
  };
}

/* ========= 文件读取 ========= */
function handleFile(e) {
  const file = e.target.files[0];
  if (!file) return;

  originalFileName = file.name;

  const ext = (file.name.split('.').pop() || '').toLowerCase();
  if (!['xlsx', 'xls'].includes(ext)) {
    showError('仅支持 Excel 格式(.xlsx / .xls)');
    return;
  }

  filenameEl.textContent = file.name;
  el('file-info').classList.add('show');

  const reader = new FileReader();
  reader.onload = ev => {
    try {
      const data = new Uint8Array(ev.target.result);
      const wb = XLSX.read(data, { type: 'array' });
      const wsName = wb.SheetNames[0];
      const ws = wb.Sheets[wsName];
      const json = XLSX.utils.sheet_to_json(ws, { header: 1 });
      const res = parseCSVFromLines(json.map(r => r.join(',')));
      
      originalQuestions = res.questions.map((q, index) => ({
        ...q,
        originalIndex: index
      }));
      
      questions = [...originalQuestions];
      
      parsingErrors = res.errors;
      debugDetails.textContent = parsingErrors.length ? parsingErrors.join('\n') : '未发现解析错误';
      
      if (questions.length === 0) {
        showError('未找到有效题目,请检查文件格式');
      } else {
        const defaultCount = questions.length >= 20 ? 20 : questions.length;
        randomCountInput.max = questions.length;
        randomCountInput.value = defaultCount;
        
        startQuizSection.style.display = 'block';
        debugInfo.classList.remove('show');
      }
      debugToggleBtn.style.display = 'inline-block';
    } catch (err) {
      showError(err.message);
    }
  };
  reader.onerror = () => showError('文件读取失败');
  reader.readAsArrayBuffer(file);
}

/* ---------- 文本清洗 ---------- */
function cleanText(buf) {
  let str = typeof buf === 'string' ? buf : new TextDecoder('utf-8').decode(buf);
  if (str.charCodeAt(0) === 0xFEFF) str = str.slice(1);
  return str.replace(/\p{Zs}/gu, ' ').trim();
}

/* ---------- 解析答案格式转换 ---------- */
function convertAnswer(answerText, optionsCount) {
  // 保留原始答案文本用于错误提示
  const originalAnswerText = answerText;
  
  // 处理空答案
  if (!answerText || answerText.trim() === '') {
    return '';
  }
  
  // 移除所有非数字和非字母的字符(如百分号、空格等),但保留中文
  const cleanedAnswer = answerText.replace(/[^\dA-Za-z\u4e00-\u9fa5]/g, '');
  
  // 处理判断题特殊情况(无论选项数量如何,只要答案是判断类型就处理)
  const lowerAnswer = cleanedAnswer.toLowerCase();
  if (['正确', '对', '是', 'y'].includes(lowerAnswer) || 
      ['正确', '对', '是'].some(word => lowerAnswer.includes(word))) {
    return 'A';
  }
  if (['错误', '错', '否', 'n'].includes(lowerAnswer) || 
      ['错误', '错', '否'].some(word => lowerAnswer.includes(word))) {
    return 'B';
  }
  
  // 处理数字索引(1对应A,2对应B,以此类推)
  if (/^\d+$/.test(cleanedAnswer)) {
    const num = parseInt(cleanedAnswer, 10);
    if (num >= 1 && num <= optionsCount) {
      return String.fromCharCode(64 + num); // 1 -> A, 2 -> B, ..., 6 -> F
    }
  }
  
  // 普通字母答案(转为大写)
  return cleanedAnswer.toUpperCase();
}

/* ---------- 解析(列顺序:问题,选项A,选项B,选项C,选项D,选项E,选项F,解析,答案) ---------- */
function parseCSVFromLines(lines) {
  const errors = [];
  const questions = [];
  function isValidOption(text) {
    return text && text.replace(/\s+/gu, '').length > 0;
  }
  function parseLine(line) {
    const fields = [];
    let f = '', q = false;
    for (let i = 0; i < line.length; i++) {
      const c = line[i];
      if (c === '"') {
        if (line[i + 1] === '"') { f += '"'; i++; } else q = !q;
      } else if (c === ',' && !q) {
        fields.push(f.trim()); f = '';
      } else f += c;
    }
    fields.push(f.trim());
    return fields;
  }

  // 检查是否包含"解析"关键词,可能是解析内容
  function isLikelyExplanation(text) {
    return text && text.toLowerCase().includes('解析') && 
           !/^[a-f0-9]{1,6}$/i.test(text.replace(/[^a-f0-9]/gi, ''));
  }

  // 检查是否可能是答案
  function isLikelyAnswer(text) {
    if (!text) return false;
    const cleaned = text.replace(/[^a-f0-9\u4e00-\u9fa5]/gi, '').toLowerCase();
    // 答案可能包含的关键词
    const answerKeywords = ['正确', '错误', '对', '错', 'y', 'n'];
    return /^[a-f0-9]{1,6}$/i.test(cleaned) || 
           answerKeywords.some(keyword => cleaned.includes(keyword));
  }

  for (let i = 0; i < lines.length; i++) {
    if (i === 0) continue; // 标题行
    try {
      const fields = parseLine(lines[i]);
      let explanation = '', question = '', answerText = '', options = [];
      
      // 提取问题(第一列)
      if (fields.length >= 1 && isValidOption(fields[0])) {
        question = fields[0];
      } else {
        throw '未找到问题';
      }
      
      // 提取选项(从第二列到第七列 - 对应选项A到F)
      options = fields.slice(1, 7).filter(isValidOption);
      if (options.length < 2) options = ['正确', '错误'];
      
      // 提取解析和答案 - 增强版逻辑
      // 先预设解析列和答案列位置
      let explanationCol = 7;  // 第8列
      let answerCol = 8;       // 第9列
      
      // 提取解析
      if (fields.length > explanationCol) {
        explanation = fields[explanationCol] || '';
      }
      
      // 提取答案 - 增强逻辑
      let answerFound = false;
      
      // 检查预设的答案列
      if (fields.length > answerCol && isValidOption(fields[answerCol])) {
        // 如果预设的答案列看起来是有效的答案
        if (isLikelyAnswer(fields[answerCol])) {
          answerText = fields[answerCol];
          answerFound = true;
        } else if (isLikelyExplanation(fields[answerCol])) {
          // 如果预设的答案列看起来是解析内容,则将其合并到解析中
          explanation += (explanation ? ' ' : '') + fields[answerCol];
          // 尝试从下一列寻找答案
          if (fields.length > answerCol + 1 && isValidOption(fields[answerCol + 1])) {
            answerText = fields[answerCol + 1];
            answerFound = true;
          }
        }
      }
      
      // 如果预设位置没找到答案,尝试从后续列寻找
      if (!answerFound) {
        for (let j = answerCol; j < fields.length; j++) {
          if (isValidOption(fields[j]) && isLikelyAnswer(fields[j])) {
            answerText = fields[j];
            answerFound = true;
            // 将前面的内容合并到解析中
            for (let k = explanationCol; k < j; k++) {
              if (fields[k]) {
                explanation += (explanation ? ' ' : '') + fields[k];
              }
            }
            break;
          }
        }
      }
      
      // 最后尝试:如果所有方法都失败,且存在内容,尝试将最后一列作为答案
      if (!answerFound) {
        for (let j = fields.length - 1; j >= 7; j--) {
          if (isValidOption(fields[j])) {
            answerText = fields[j];
            answerFound = true;
            // 将前面的内容合并到解析中
            for (let k = 7; k < j; k++) {
              if (fields[k]) {
                explanation += (explanation ? ' ' : '') + fields[k];
              }
            }
            break;
          }
        }
      }
      
      if (!answerFound) {
        throw '未找到答案';
      }
      
      // 转换答案格式
      const convertedAnswer = convertAnswer(answerText, options.length);
      if (!/^[A-Fa-f]*$/.test(convertedAnswer) || convertedAnswer === '') {
        // 跳过第122行的错误(用户特别要求)
        if (i + 1 !== 122) {
          throw `答案格式错误: ${answerText} (转换后: ${convertedAnswer || '空'})`;
        }
      }
      
      // 生成选项标签
      const optionLabels = ['A', 'B', 'C', 'D', 'E', 'F'].slice(0, options.length);
      
      // 验证答案是否在有效选项范围内
      const answers = convertedAnswer.split('');
      if (!answers.every(a => a === '' || optionLabels.includes(a))) {
        // 跳过第122行的错误(用户特别要求)
        if (i + 1 !== 122) {
          throw `答案超出选项范围: ${answerText} (转换后: ${convertedAnswer})。有效选项: ${optionLabels.join(',')}`;
        }
      }
      
      questions.push({ 
        explanation, // 解析内容
        question,    // 问题内容
        options,     // 选项内容
        optionLabels, 
        correctAnswers: answers.filter(a => a !== ''), // 过滤可能的空值
        originalAnswer: answerText // 原始答案
      });
    } catch (err) {
      // 跳过第122行的错误(用户特别要求)
      if (i + 1 !== 122) {
        errors.push(`第 ${i + 1} 行解析失败:${err}`);
      }
    }
  }
  return { questions, errors };
}

/* ========= 开始答题 ========= */
function startQuiz(mode) {
  // 新增:获取考试模式状态
  isExamMode = examModeCheckbox.checked;
  
  if (mode === 'random' || mode === 'random-shuffle-options') {
    const count = parseInt(randomCountInput.value);
    if (isNaN(count) || count < 1 || count > originalQuestions.length) {
      alert(`请输入1到${originalQuestions.length}之间的数字`);
      return;
    }
    questions = shuffleArray([...originalQuestions]).slice(0, count);
    
    if (mode === 'random-shuffle-options') {
      questions = questions.map(q => shuffleQuestionOptions(q));
    }
  } else {
    questions = [...originalQuestions];
    
    if (mode === 'sequential-shuffle-options') {
      questions = questions.map(q => shuffleQuestionOptions(q));
    }
  }
  
  fileImport.style.display = 'none';
  startQuizSection.style.display = 'none';
  current = score = answered = correct = 0;
  status = questions.map(() => ({ answered: false, correct: false, selected: [] }));
  controls.classList.add('show');
  quiz.classList.add('show');
  answerSheet.classList.add('show');
  
  // 新增:考试模式下隐藏分数显示
  if (isExamMode) {
    document.querySelector('.score-display').style.display = 'none';
  } else {
    document.querySelector('.score-display').style.display = 'block';
  }
  
  buildAnswerSheet();
  renderQuestion(current);
}

/* ---------- 数组随机排序 ---------- */
function shuffleArray(array) {
  const newArray = [...array];
  for (let i = newArray.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [newArray[i], newArray[j]] = [newArray[j], newArray[i]];
  }
  return newArray;
}

/* ---------- 答题卡 ---------- */
function buildAnswerSheet() {
  answerGrid.innerHTML = '';
  totalEl.textContent = questions.length;
  qTotal.textContent = `/ ${questions.length}`;
  questions.forEach((_, i) => {
    const btn = document.createElement('button');
    btn.className = 'answer-sheet-btn unanswered';
    btn.textContent = i + 1;
    btn.onclick = () => {
      if (status[current].answered || current === i) renderQuestion(i);
      else alert('请先完成当前题');
    };
    answerGrid.appendChild(btn);
  });
}

/* ---------- 渲染题目 ---------- */
function renderQuestion(idx) {
  if (idx < 0 || idx >= questions.length) return;
  current = idx;
  const q = questions[idx];
  qText.textContent = q.question;
  qNum.textContent = `问题 ${idx + 1}`;
  optionsContainer.innerHTML = '';
  el('feedback').classList.remove('show');
  explanationEl.classList.remove('show');
  confirmBtn.disabled = false;
  
  // 考试模式下,无论是否已答,都不允许通过答题卡跳题
  if (isExamMode) {
    document.querySelectorAll('.answer-sheet-btn').forEach((btn, i) => {
      if (i !== current) {
        btn.disabled = true;
        btn.style.opacity = '0.7';
        btn.style.cursor = 'not-allowed';
      } else {
        btn.disabled = false;
        btn.style.opacity = '1';
        btn.style.cursor = 'pointer';
      }
    });
  }

  q.optionLabels.forEach((lab, i) => {
    const optDiv = document.createElement('div');
    const sel = status[idx].selected.includes(lab);
    optDiv.className = `option ${sel ? 'selected' : ''}`;
    optDiv.innerHTML = `<div class="option-label"><span class="option-letter">${lab}</span><span>${q.options[i]}</span></div>`;
    optDiv.onclick = () => toggleOption(idx, lab);
    optionsContainer.appendChild(optDiv);
  });

  prevBtn.disabled = idx === 0;
  nextBtn.innerHTML = idx === questions.length - 1 ? '完成测验' : '下一题';
  
  // 考试模式下,只有当前题已答才能进入下一题
  nextBtn.disabled = isExamMode ? !status[idx].answered : false;
  
  updateAnswerSheet();
}

function toggleOption(idx, lab) {
  const s = status[idx].selected;
  const i = s.indexOf(lab);
  i > -1 ? s.splice(i, 1) : s.push(lab);
  renderQuestion(idx);
}

function confirmAnswer() {
  const idx = current;
  const q = questions[idx];
  const s = status[idx];
  if (s.selected.length === 0) { alert('请至少选择一个答案'); return; }

  const ok = JSON.stringify(s.selected.sort()) === JSON.stringify(q.correctAnswers.sort());
  if (!s.answered) {
    answered++;
    if (ok) { correct++; score++; }
  } else {
    if (ok && !s.correct) { correct++; score++; }
    else if (!ok && s.correct) { correct--; score--; }
  }
  s.answered = true; s.correct = ok;
  
  // 新增:考试模式下不显示即时反馈和解析,直接进入下一题
  if (!isExamMode) {
    showFeedback(ok, q.correctAnswers);
    showExplanation(q.explanation);
  } else {
    // 考试模式:提交后直接进入下一题
    setTimeout(() => {
      if (current < questions.length - 1) {
        go(1);
      } else {
        showResults();
      }
    }, 500); // 短暂延迟,让用户感知到答案已提交
  }
  
  updateStats();
  confirmBtn.disabled = true;
  nextBtn.disabled = false;
  updateAnswerSheet();
}

function showFeedback(ok, ans) {
  const fb = el('feedback');
  fb.innerHTML = ok ? 
    '<span>&#10003;</span><span class="status-correct">正确!</span>' : 
    `<span>&#10007;</span><span class="status-incorrect">不正确,正确答案是 ${ans.join('、')}</span>`;
  fb.className = `feedback ${ok ? 'feedback-success' : 'feedback-error'} show`;
}

// 改进的显示解析函数,确保解析内容正确显示
function showExplanation(explanation) {
  // 即使解析内容为空,也显示解析区域但提示无解析
  if (explanation && explanation.trim()) {
    explanationContentEl.textContent = explanation;
  } else {
    explanationContentEl.textContent = "暂无解析内容";
  }
  explanationEl.classList.add('show');
}

function go(dir) {
  if (dir === 1 && current === questions.length - 1) return showResults();
  const next = current + dir;
  if (next >= 0 && next < questions.length) renderQuestion(next);
}

function updateStats() {
  answeredEl.textContent = answered;
  correctEl.textContent = correct;
  scoreEl.textContent = score;
}

function updateAnswerSheet() {
  document.querySelectorAll('.answer-sheet-btn').forEach((btn, i) => {
    btn.className = 'answer-sheet-btn';
    if (i === current) {
      btn.classList.add('current');
      btn.style.boxShadow = '0 0 0 2px #fff, 0 0 10px 2px rgba(59,130,246,.5)';
    } else if (status[i].answered) {
      if (status[i].correct) {
        btn.classList.add('correct');
        btn.style.boxShadow = '0 0 0 2px #fff, 0 0 10px 2px rgba(16,185,129,.5)';
      } else {
        btn.classList.add('incorrect');
        btn.style.boxShadow = '0 0 0 2px #fff, 0 0 10px 2px rgba(239,68,68,.5)';
      }
    } else {
      btn.classList.add('unanswered');
      btn.style.boxShadow = '0 0 0 2px #fff, 0 0 10px 2px rgba(229,231,235,.5)';
    }
  });
}

function showResults() {
  quiz.classList.remove('show');
  controls.classList.remove('show');
  results.classList.add('show');
  finalScore.textContent = score;
  finalTotal.textContent = questions.length;
  
  // 新增:更新摘要统计信息
  summaryTotalCount.textContent = questions.length;
  summaryCorrectCount.textContent = correct;
  summaryIncorrectCount.textContent = questions.length - correct;
  
  // 新增:计算并显示百分比得分
  const percentage = questions.length > 0 ? Math.round((score / questions.length) * 100) : 0;
  scorePercentage.textContent = `得分:${percentage}%`;
  
  // 新增:考试模式下显示详细结果
  if (isExamMode) {
    renderExamResults();
    examResultsDetails.style.display = 'block';
  } else {
    examResultsDetails.style.display = 'none';
  }
}

// 新增:渲染考试模式下的详细结果
function renderExamResults() {
  examResultsDetails.innerHTML = '';
  
  questions.forEach((question, index) => {
    const questionStatus = status[index];
    const isCorrect = questionStatus.correct;
    
    // 创建问题容器
    const questionEl = document.createElement('div');
    questionEl.className = `exam-question-item ${isCorrect ? 'correct' : 'incorrect'}`;
    
    // 问题头部(包含题号和状态)
    const headerEl = document.createElement('div');
    headerEl.className = 'exam-question-header';
    
    const numberEl = document.createElement('div');
    numberEl.className = 'exam-question-number';
    numberEl.textContent = `问题 ${index + 1}`;
    
    const statusEl = document.createElement('div');
    statusEl.className = `exam-question-status ${isCorrect ? 'correct' : 'incorrect'}`;
    statusEl.textContent = isCorrect ? '正确' : '错误';
    
    headerEl.appendChild(numberEl);
    headerEl.appendChild(statusEl);
    
    // 问题文本
    const textEl = document.createElement('div');
    textEl.className = 'exam-question-text';
    textEl.textContent = question.question;
    
    // 选项
    const optionsEl = document.createElement('div');
    optionsEl.className = 'exam-options';
    
    question.options.forEach((option, optIndex) => {
      const optLabel = question.optionLabels[optIndex];
      const isSelected = questionStatus.selected.includes(optLabel);
      const isCorrectAnswer = question.correctAnswers.includes(optLabel);
      
      const optionEl = document.createElement('div');
      optionEl.className = `exam-option ${isSelected ? 'selected' : ''} ${isCorrectAnswer ? 'correct-answer' : ''}`;
      
      const letterEl = document.createElement('div');
      letterEl.className = 'exam-option-letter';
      letterEl.textContent = optLabel;
      
      const contentEl = document.createElement('div');
      contentEl.textContent = option;
      
      optionEl.appendChild(letterEl);
      optionEl.appendChild(contentEl);
      optionsEl.appendChild(optionEl);
    });
    
    // 答案信息
    const answerInfoEl = document.createElement('div');
    answerInfoEl.className = 'exam-answer-info';
    
    const yourAnswerEl = document.createElement('div');
    yourAnswerEl.className = 'exam-your-answer';
    yourAnswerEl.innerHTML = `<span class="exam-answer-label">你的答案:</span>${questionStatus.selected.length > 0 ? questionStatus.selected.join('、') : '未作答'}`;
    
    const correctAnswerEl = document.createElement('div');
    correctAnswerEl.className = 'exam-correct-answer';
    correctAnswerEl.innerHTML = `<span class="exam-answer-label">正确答案:</span>${question.correctAnswers.join('、')}`;
    
    answerInfoEl.appendChild(yourAnswerEl);
    answerInfoEl.appendChild(correctAnswerEl);
    
    // 解析信息 - 确保总是显示解析部分
    const explanationEl = document.createElement('div');
    explanationEl.className = 'explanation show';  // 强制显示解析
    explanationEl.innerHTML = `
      <div class="explanation-title">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
        </svg>
        解析
      </div>
      <div class="explanation-content">${question.explanation || '暂无解析内容'}</div>
    `;
    
    answerInfoEl.appendChild(explanationEl);
    
    // 组合所有元素
    questionEl.appendChild(headerEl);
    questionEl.appendChild(textEl);
    questionEl.appendChild(optionsEl);
    questionEl.appendChild(answerInfoEl);
    
    examResultsDetails.appendChild(questionEl);
  });
}

function restart() { 
  results.classList.remove('show'); 
  fileImport.style.display = 'block';
  startQuizSection.style.display = 'block';
  answerSheet.classList.remove('show');
  examModeCheckbox.checked = false; // 重置考试模式
  isExamMode = false; // 重置考试模式标志
}

function selectNewFile() {
  results.classList.remove('show');
  answerSheet.classList.remove('show');
  fileImport.style.display = 'block';
  fileUpload.value = '';
  el('file-info').classList.remove('show');
  startQuizSection.style.display = 'none';
  debugInfo.classList.remove('show');
  originalFileName = '';
  examModeCheckbox.checked = false; // 重置考试模式
  isExamMode = false; // 重置考试模式标志
}

function retryFile() {
  errorSec.classList.remove('show');
  fileImport.style.display = 'block';
  fileUpload.value = '';
  el('file-info').classList.remove('show');
  startQuizSection.style.display = 'none';
  debugInfo.classList.remove('show');
  originalFileName = '';
  examModeCheckbox.checked = false; // 重置考试模式
  isExamMode = false; // 重置考试模式标志
}

function showError(msg) {
  el('error-message').textContent = msg;
  el('error-debug-details').textContent = parsingErrors.length ? parsingErrors.join('\n') : msg;
  el('error-debug-info').classList.toggle('show', parsingErrors.length > 0);
  fileImport.classList.remove('show');
  fileImport.style.display = 'none';
  errorSec.classList.add('show');
}
</script>
</body>
</html>



免费评分

参与人数 28吾爱币 +32 热心值 +24 收起 理由
cxp0816 + 1 + 1 我很赞同!
Jackrong_ + 1 + 1 谢谢@Thanks!
Z9Z9X + 1 + 1 谢谢@Thanks!
DaoJing + 1 + 1 谢谢@Thanks!
yyyl + 1 + 1 我很赞同!
smile1110 + 2 + 1 nbnb
秋神紫羽 + 1 + 1 谢谢@Thanks!
chh322 + 1 + 1 用心讨论,共获提升!
jsxiaobao + 1 很棒
shaunkelly + 1 + 1 我很赞同!
likuyu + 1 谢谢@Thanks!
lingswell + 1 + 1 我很赞同!
penguinki001 + 1 我很赞同!
TNB + 1 谢谢@Thanks!
lstar + 1 + 1 热心回复!
staty + 1 + 1 热心回复!
x3159 + 1 谢谢@Thanks!
tzxinqing + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
liyitong + 1 + 1 我很赞同!
hailang42 + 1 我很赞同!
qq9953 + 1 谢谢@Thanks!
1045837055lucy + 1 + 1 谢谢@Thanks!
幻昼_ + 1 + 1 我很赞同!
wyangdh + 1 + 1 谢谢@Thanks!
hehe549124 + 1 + 1 谢谢@Thanks!
189678 + 1 + 1 谢谢@Thanks!
long8586 + 1 + 1 谢谢@Thanks!
hrh123 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Zzz0 发表于 2025-8-3 10:51
本帖最后由 Zzz0 于 2025-10-7 19:10 编辑

用DeepSeek改进了你的答题系统

增强版答题系统

屏幕截图_7-8-2025_12024.png

源码

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>增强版答题系统</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

body {
  background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
  min-height: 100vh;
  color: #1f2937;
  line-height: 1.6;
  padding: 20px;
}

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

header {
  text-align: center;
  margin: 20px 0 30px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.85);
  border-radius: 16px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

h1 {
  font-size: 2.5rem;
  font-weight: 800;
  background: linear-gradient(to right, #3B82F6, #8B5CF6);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: 10px;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.subtitle {
  color: #64748b;
  font-size: 1.2rem;
  max-width: 700px;
  margin: 0 auto;
}

.card {
  background: #fff;
  border-radius: 16px;
  padding: 30px;
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.08);
  margin-bottom: 25px;
  border: 1px solid #eef2f6;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
  transform: translateY(-5px);
  box-shadow: 0 15px 30px -10px rgba(0, 0, 0, 0.15);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  padding: 14px 28px;
  border-radius: 12px;
  border: none;
  cursor: pointer;
  transition: all 0.3s;
  box-shadow: 0 4px 6px rgba(59, 130, 246, 0.2);
  font-size: 1.05rem;
}

.btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 7px 14px rgba(59, 130, 246, 0.25);
}

.btn:active {
  transform: translateY(1px);
}

.btn-primary {
  background: #3B82F6;
  color: #fff;
}

.btn-secondary {
  background: #10B981;
  color: #fff;
}

.btn-gray {
  background: #e5e7eb;
  color: #4b5563;
}

.export-btn {
  background: linear-gradient(to right, #8e44ad, #9b59b6);
  color: white;
  border: none;
  padding: 14px 28px;
  border-radius: 12px;
  cursor: pointer;
  font-size: 1.05rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  transition: all 0.3s;
  box-shadow: 0 4px 6px rgba(142, 68, 173, 0.3);
}

.export-btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 7px 14px rgba(142, 68, 173, 0.4);
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.file-import {
  max-width: 800px;
  margin: 0 auto;
  text-align: center;
}

#file-upload {
  display: none;
}

.file-info {
  margin-top: 20px;
  display: none;
}

.help-text {
  color: #64748b;
  font-size: 0.95rem;
  margin-top: 15px;
}

.flex-container {
  display: flex;
  flex-direction: column;
  gap: 25px;
  max-width: 1200px;
  margin: 0 auto;
}

@media (min-width: 1024px) {
  .flex-container {
    flex-direction: row;
  }
  .main-content {
    width: 750px;
    flex-shrink: 0;
  }
  .sidebar {
    width: 350px;
    flex-shrink: 0;
  }
}

.quiz-controls {
  display: none;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 25px;
  background: #f8fafc;
  padding: 20px;
  border-radius: 16px;
}

.quiz-controls.show {
  display: flex;
}

.question-count {
  font-size: 1.25rem;
  font-weight: 600;
}

.total-questions {
  color: #64748b;
  margin-left: 8px;
}

.score-display {
  background: #fff;
  padding: 10px 20px;
  border-radius: 50px;
  font-size: 1rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}

.score-value {
  font-weight: 700;
  color: #3B82F6;
  margin-left: 5px;
}

.question-section {
  display: none;
}

.question-section.show {
  display: block;
}

.question-type {
  display: inline-block;
  padding: 8px 16px;
  background: rgba(59, 130, 246, 0.1);
  color: #3B82F6;
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: 50px;
  margin-bottom: 20px;
}

.question-text {
  font-size: 1.4rem;
  font-weight: 700;
  margin-bottom: 25px;
  color: #1f2937;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .question-text {
    font-size: 1.6rem;
  }
}

.options-container {
  margin-bottom: 30px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.option {
  padding: 20px;
  border: 1px solid #e5e7eb;
  border-radius: 14px;
  cursor: pointer;
  transition: all 0.2s;
  background: #f9fafb;
}

.option:hover {
  background: rgba(59, 130, 246, 0.08);
  border-color: #93c5fd;
}

.option.selected {
  border-color: #3B82F6;
  background: rgba(59, 130, 246, 0.06);
}

.option-label {
  display: flex;
  align-items: flex-start;
}

.option-letter {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  margin-right: 16px;
  font-weight: 600;
  font-size: 1.1rem;
}

.option.selected .option-letter {
  background: #3B82F6;
  color: #fff;
}

.option:not(.selected) .option-letter {
  background: rgba(59, 130, 246, 0.1);
  color: #3B82F6;
}

.button-group {
  display: flex;
  justify-content: space-between;
  margin-top: 25px;
}

.confirm-btn-container {
  text-align: center;
  margin-bottom: 25px;
}

.feedback {
  padding: 20px;
  border-radius: 12px;
  margin-bottom: 25px;
  display: none;
  align-items: center;
  font-size: 1.1rem;
}

.feedback.show {
  display: flex;
}

.feedback-success {
  background: #f0fdf4;
  border: 1px solid #dcfce7;
  color: #166534;
}

.feedback-error {
  background: #fee2e2;
  border: 1px solid #fecaca;
  color: #b91c1c;
}

.results-section {
  display: none;
  text-align: center;
  max-width: 700px;
  margin: 0 auto;
}

.results-section.show {
  display: block;
}

.results-title {
  font-size: 1.8rem;
  font-weight: 700;
  margin-bottom: 10px;
}

.results-subtitle {
  color: #64748b;
  margin-bottom: 30px;
  font-size: 1.1rem;
}

.score-circle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 220px;
  height: 220px;
  border-radius: 50%;
  background: linear-gradient(to bottom right, #3B82F6, #8B5CF6);
  margin: 0 auto 30px;
  color: #fff;
  text-align: center;
  box-shadow: 0 10px 25px rgba(59, 130, 246, 0.3);
}

.final-score {
  font-size: 3.5rem;
  font-weight: 800;
}

.final-total {
  font-size: 1.8rem;
  font-weight: 700;
}

.results-buttons {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-top: 30px;
  flex-wrap: wrap;
}

.error-section {
  display: none;
  text-align: center;
  max-width: 700px;
  margin: 0 auto;
}

.error-section.show {
  display: block;
}

.error-icon-container {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: #fee2e2;
  margin-bottom: 20px;
}

.error-icon {
  color: #dc2626;
  font-size: 2.5rem;
}

.error-title {
  font-size: 1.8rem;
  font-weight: 700;
  color: #dc2626;
  margin-bottom: 10px;
}

.error-message {
  color: #64748b;
  margin-bottom: 25px;
  font-size: 1.1rem;
}

.debug-info {
  font-size: 0.95rem;
  background: #f3f4f6;
  padding: 20px;
  border-radius: 12px;
  margin-bottom: 25px;
  max-height: 200px;
  overflow-y: auto;
  display: none;
}

.debug-info.show {
  display: block;
}

.answer-sheet-section {
  display: none;
}

.answer-sheet-section.show {
  display: block;
}

.answer-sheet {
  position: sticky;
  top: 20px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}

.answer-sheet-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  font-size: 1.25rem;
  font-weight: 700;
  color: #3B82F6;
}

.answer-sheet-icon {
  margin-right: 10px;
  color: #3B82F6;
  font-size: 1.4rem;
}

.answer-stats {
  display: flex;
  justify-content: space-between;
  font-size: 0.95rem;
  margin-bottom: 20px;
}

.stat-label {
  color: #64748b;
}

.stat-value {
  font-weight: 600;
}

.answer-sheet-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  margin-bottom: 20px;
}

.answer-sheet-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: all 0.2s;
}

.answer-sheet-btn.unanswered {
  background: #e5e7eb;
  color: #4b5563;
}

.answer-sheet-btn.current {
  background: #3B82F6;
  color: #fff;
}

.answer-sheet-btn.correct {
  background: #10B981;
  color: #fff;
}

.answer-sheet-btn.incorrect {
  background: #EF4444;
  color: #fff;
}

.answer-sheet-btn.partial {
  background: linear-gradient(135deg, #FBBF24 50%, #EF4444 50%);
  color: #fff;
}

.legend {
  display: flex;
  align-items: center;
  font-size: 0.9rem;
  gap: 15px;
  flex-wrap: wrap;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 5px;
}

.legend-color {
  width: 16px;
  height: 16px;
  border-radius: 50%;
}

.legend-unanswered {
  background-color: #e5e7eb;
}
.legend-current {
  background-color: #3B82F6;
}
.legend-correct {
  background-color: #10B981;
}
.legend-incorrect {
  background-color: #EF4444;
}
.legend-partial {
  background-color: #FBBF24;
}

.debug-toggle-btn {
  margin-top: 20px;
  background: transparent;
  border: 1px solid #94a3b8;
  color: #64748b;
  padding: 10px 20px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 0.95rem;
  transition: all 0.3s;
}

.debug-toggle-btn:hover {
  background: rgba(59, 130, 246, 0.1);
  border-color: #3B82F6;
  color: #3B82F6;
}

.start-quiz-section {
  text-align: center;
  padding: 30px 0;
}

/* ========= 统一图片预览布局 ========= */
.image-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  background: #f8f9ff;
  padding: 15px;
  border: 1px solid #e5e7eb;
}

.question-image, .option-image {
  max-width: 100%;
  max-height: 350px;
  border-radius: 10px;
  display: block;
  border: 1px solid #e5e7eb;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}

.preview-btn {
  position: absolute;
  bottom: 15px;
  right: 15px;
  background: rgba(59, 130, 246, 0.8);
  color: white;
  border: none;
  border-radius: 6px;
  padding: 8px 15px;
  font-size: 0.95rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 5px;
  transition: all 0.3s;
  backdrop-filter: blur(4px);
  z-index: 10;
}

.preview-btn:hover {
  background: #3B82F6;
  transform: scale(1.05);
}

.points-badge {
  background: rgba(231, 111, 81, 0.15);
  color: #e76f51;
  padding: 6px 14px;
  border-radius: 50px;
  font-size: 0.95rem;
  font-weight: 600;
  display: inline-block;
  margin-left: 15px;
}

.question-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.explanation-content {
  margin-top: 20px;
  padding: 20px;
  background: #f8f9ff;
  border-radius: 12px;
  border-left: 4px solid #3B82F6;
  line-height: 1.7;
}

.advanced-features {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin: 30px 0;
  padding: 25px;
  background: #f8f9ff;
  border-radius: 16px;
  border-left: 4px solid #3B82F6;
}

.feature-item {
  flex: 1;
  min-width: 250px;
}

.feature-title {
  font-weight: 700;
  margin-bottom: 12px;
  color: #3B82F6;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.1rem;
}

.feature-icon {
  font-size: 1.3rem;
}

.file-info-content {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 15px 20px;
  border-radius: 12px;
  background-color: #f0fdf4;
  border: 1px solid #dcfce7;
}

.file-info-content span:first-child {
  color: #10B981;
  font-weight: bold;
  font-size: 1.4rem;
}

.file-info-content span:last-child {
  color: #166534;
  font-weight: 600;
  font-size: 1.1rem;
}

.import-status {
  margin-top: 25px;
  padding: 20px;
  border-radius: 12px;
  text-align: center;
  display: none;
  font-size: 1.1rem;
}

.import-status.show {
  display: block;
}

.import-status.success {
  background: #f0fdf4;
  border: 1px solid #dcfce7;
  color: #166534;
}

.import-status.error {
  background: #fee2e2;
  border: 1px solid #fecaca;
  color: #b91c1c;
}

.import-status i {
  margin-right: 12px;
}

.truefalse-option {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15px;
  padding: 20px;
  border-radius: 14px;
  background: #f8f9ff;
  border: 2px solid #e5e7eb;
  cursor: pointer;
  transition: all 0.2s;
  font-size: 1.1rem;
  font-weight: 600;
}

.truefalse-option.selected {
  border-color: #3B82F6;
  background: rgba(59, 130, 246, 0.1);
}

.truefalse-container {
  display: flex;
  gap: 20px;
  margin-top: 15px;
}

.question-type-group {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

.type-group {
  background: #f8f9ff;
  border-radius: 14px;
  padding: 20px;
  border: 1px solid #e5e7eb;
}

.type-title {
  font-weight: 700;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: #3B82F6;
  font-size: 1.1rem;
}

.type-count {
  margin-top: 15px;
  font-size: 1rem;
  color: #64748b;
}

.type-controls {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-top: 15px;
}

.type-controls input {
  width: 90px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid #cbd5e1;
  background: white;
}

.type-controls span {
  font-size: 1rem;
  color: #64748b;
}

.error-details {
  background: #fff5f5;
  border: 1px solid #ffd6d6;
  border-radius: 12px;
  padding: 20px;
  margin-top: 25px;
}

.error-details-title {
  font-weight: 700;
  margin-bottom: 15px;
  color: #dc2626;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 1.1rem;
}

.error-details-content {
  font-family: monospace;
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 250px;
  overflow-y: auto;
  padding: 15px;
  background: #fff;
  border-radius: 10px;
  border: 1px solid #e5e7eb;
}

.file-format {
  background: #f0fdf4;
  border-radius: 12px;
  padding: 25px;
  margin: 20px 0;
  border-left: 4px solid #10B981;
}

.file-format-title {
  font-weight: 700;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 12px;
  color: #10B981;
  font-size: 1.2rem;
}

.file-format ul {
  padding-left: 25px;
  margin-top: 15px;
}

.file-format li {
  margin-bottom: 12px;
  line-height: 1.6;
}

.file-format strong {
  color: #1e293b;
}

.encoding-selector {
  margin-top: 20px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid #cbd5e1;
  width: 100%;
  background: white;
  font-size: 1rem;
}

.random-questions-group {
  margin-top: 20px;
  display: flex;
  align-items: center;
  gap: 15px;
}

.random-questions-group input {
  width: 100px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid #cbd5e1;
  background: white;
}

.fillblank-container {
  margin-top: 20px;
}

.blank-row {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
  gap: 15px;
}

.blank-number {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #9b59b6;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  flex-shrink: 0;
}

.blank-input {
  flex: 1;
  padding: 15px;
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  font-size: 1.1rem;
  transition: border-color 0.3s;
}

.blank-input:focus {
  border-color: #3B82F6;
  outline: none;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

.blank-hint {
  color: #64748b;
  font-size: 0.95rem;
  margin-left: 10px;
}

.feedback-blank {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 10px 15px;
  border-radius: 8px;
  font-size: 1rem;
  display: none;
}

.feedback-blank.correct {
  background: #f0fdf4;
  color: #166534;
}

.feedback-blank.incorrect {
  background: #fee2e2;
  color: #b91c1c;
}

.blank-scoring-mode {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 50px;
  font-weight: 600;
  font-size: 0.9rem;
  margin-left: 15px;
}

.blank-scoring-per {
  background: rgba(46, 204, 113, 0.15);
  color: #2ecc71;
}

.blank-scoring-all {
  background: rgba(231, 76, 60, 0.15);
  color: #e74c3c;
}

.export-blank-answer {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

.export-blank-input {
  background: white;
  border: 1px solid #e5e7eb;
  padding: 8px 15px;
  border-radius: 8px;
  font-weight: 500;
}

.export-blank-correct {
  background: #e6fffa;
  color: #0d9488;
  border-color: #0d9488;
}

.export-blank-incorrect {
  background: #ffebee;
  color: #e53935;
  border-color: #e53935;
}

.export-blank-label {
  font-weight: 600;
  min-width: 80px;
}

.question-text .blank-placeholder {
  position: relative;
  display: inline-block;
  min-width: 120px;
  border-bottom: 2px solid #3B82F6;
  margin: 0 5px;
  padding: 0 0 3px;
  color: #3B82F6;
  font-weight: 600;
  vertical-align: middle;
}

.question-text .blank-placeholder::after {
  content: attr(data-index);
  position: absolute;
  top: -18px;
  left: 2px;
  font-size: 0.8rem;
  color: #64748b;
}

.inline-blank {
  display: inline-block;
  min-width: 120px;
  padding: 0 10px;
  border: none;
  border-bottom: 2px solid #3B82F6;
  font-size: 1.1rem;
  text-align: center;
  background: transparent;
  outline: none;
  margin: 0 5px;
  vertical-align: middle;
}

.inline-blank:focus {
  border-bottom: 2px solid #8B5CF6;
  background: rgba(139, 92, 246, 0.05);
}

.shuffle-container {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 20px;
  padding: 15px;
  background: #f8f9ff;
  border-radius: 12px;
  border-left: 4px solid #9b59b6;
}

.shuffle-label {
  font-weight: 600;
  color: #9b59b6;
}

.exam-mode-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin-top: 20px;
  padding: 20px;
  background: #f8f9ff;
  border-radius: 16px;
  border-left: 4px solid #3498db;
}

.exam-mode-toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}

.exam-mode-title {
  font-weight: 700;
  color: #3498db;
}

.exam-settings {
  display: flex;
  align-items: center;
  gap: 15px;
  flex: 1;
}

.exam-settings label {
  font-weight: 600;
  color: #2c3e50;
}

.exam-settings input {
  width: 100px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid #cbd5e1;
  background: white;
}

.timer-container {
  position: fixed;
  top: 20px;
  right: 20px;
  background: white;
  border-radius: 50px;
  padding: 12px 25px;
  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 10px;
  border: 2px solid #3498db;
  display: none;
}

.timer-label {
  font-weight: 700;
  color: #3498db;
}

.timer-value {
  font-size: 1.5rem;
  font-weight: 800;
  color: #e74c3c;
}

.timer-warning {
  animation: pulse 1s infinite;
}

@keyframes pulse {
  0% { color: #e74c3c; }
  50% { color: #ff6b6b; }
  100% { color: #e74c3c; }
}

.wrong-questions-btn {
  background: linear-gradient(to right, #e74c3c, #c0392b);
  color: white;
  border: none;
  padding: 14px 28px;
  border-radius: 12px;
  cursor: pointer;
  font-size: 1.05rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  transition: all 0.3s;
  box-shadow: 0 4px 6px rgba(231, 76, 60, 0.3);
}

.wrong-questions-btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 7px 14px rgba(231, 76, 60, 0.4);
}

/* 图片预览模态框 */
.image-preview-modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.95);
  z-index: 1000;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.preview-container {
  position: relative;
  max-width: 90%;
  max-height: 80vh;
  text-align: center;
}

#preview-image {
  max-width: 100%;
  max-height: 75vh;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

.preview-nav {
  display: flex;
  justify-content: center;
  gap: 30px;
  margin-top: 30px;
}

.preview-nav-btn {
  background: #3B82F6;
  color: white;
  border: none;
  border-radius: 50%;
  width: 60px;
  height: 60px;
  font-size: 28px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.3);
}

.preview-nav-btn:hover {
  background: #2563EB;
  transform: scale(1.1);
}

#close-preview {
  position: absolute;
  top: 30px;
  right: 30px;
  background: #fff;
  color: #333;
  border: none;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  font-size: 28px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}

.image-counter {
  color: white;
  font-size: 1.2rem;
  margin-top: 20px;
  background: rgba(0, 0, 0, 0.5);
  padding: 8px 20px;
  border-radius: 30px;
  font-weight: 500;
}

.download-sample {
  text-align: center;
  margin-top: 30px;
}

.download-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: #3B82F6;
  font-weight: 600;
  text-decoration: none;
  padding: 12px 25px;
  border-radius: 12px;
  background: rgba(59, 130, 246, 0.1);
  transition: all 0.3s;
}

.download-btn:hover {
  background: rgba(59, 130, 246, 0.2);
  transform: translateY(-3px);
}

.sample-image {
  max-width: 100%;
  border-radius: 12px;
  margin-top: 25px;
  border: 1px solid #e2e8f0;
  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
}

/* ========= 分类答题卡样式 ========= */
.type-section {
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid #e5e7eb;
}

.type-section:last-child {
  border-bottom: none;
}

.type-section-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  font-size: 1.1rem;
  font-weight: 600;
  color: #3B82F6;
}

.type-section-icon {
  font-size: 1.1rem;
}

.type-section-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}

.type-section .answer-sheet-btn {
  width: 36px;
  height: 36px;
  font-size: 0.9rem;
}

.type-section-stats {
  display: flex;
  justify-content: space-between;
  font-size: 0.9rem;
  color: #64748b;
  margin-top: 8px;
}

.type-section-stats .stat-value {
  font-weight: 600;
  color: #3B82F6;
}

.type-section-stats .stat-correct {
  color: #10B981;
}

.type-section-stats .stat-incorrect {
  color: #EF4444;
}

/* 进度条容器 - 仅在答题时显示 */
.progress-container {
  display: none;
  margin-top: 30px;
  padding: 25px;
  background: #f8f9ff;
  border-radius: 16px;
  border-left: 4px solid #3B82F6;
}

.progress-container.show {
  display: block;
}

.progress-title {
  font-weight: 700;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  gap: 15px;
  color: #3B82F6;
  font-size: 1.2rem;
}

.progress-bar {
  height: 16px;
  background: #e5e7eb;
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 15px;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(to right, #3B82F6, #8B5CF6);
  border-radius: 8px;
  transition: width 0.5s ease;
}

.progress-labels {
  display: flex;
  justify-content: space-between;
  font-size: 0.95rem;
  color: #64748b;
}

.progress-label {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.progress-value {
  font-weight: 700;
  margin-top: 8px;
  color: #3B82F6;
  font-size: 1.1rem;
}

/* ========= 解答题样式 ========= */
.essay-container {
  margin-top: 20px;
}

.essay-answer-box {
  width: 100%;
  min-height: 150px;
  padding: 15px;
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  font-size: 1.1rem;
  transition: border-color 0.3s;
  resize: vertical;
}

.essay-answer-box:focus {
  border-color: #3B82F6;
  outline: none;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

.scoring-mode {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 50px;
  font-weight: 600;
  font-size: 0.9rem;
  margin-left: 15px;
}

.scoring-per {
  background: rgba(46, 204, 113, 0.15);
  color: #2ecc71;
}

.scoring-all {
  background: rgba(231, 76, 60, 0.15);
  color: #e74c3c;
}

.scoring-partial {
  background: rgba(241, 196, 15, 0.15);
  color: #f39c12;
}

.keyword-preview-tip {
  margin-top: 15px;
  padding: 12px 15px;
  background-color: #f0f7ff;
  border-radius: 8px;
  border-left: 3px solid #3B82F6;
  font-size: 0.95rem;
  color: #4b5563;
}

.keyword-feedback {
  margin-top: 15px;
  padding: 15px;
  background: #f8f9ff;
  border-radius: 12px;
  border-left: 4px solid #f39c12;
}

.keyword-item {
  display: flex;
  align-items: center;
  padding: 10px;
  margin-bottom: 8px;
  border-radius: 8px;
}

.keyword-item.correct {
  background: #e6fffa;
  border: 1px solid #0d9488;
}

.keyword-item.incorrect {
  background: #ffebee;
  border: 1px solid #e53935;
}

.keyword-text {
  flex: 1;
}

.keyword-points {
  font-weight: 600;
  min-width: 60px;
  text-align: right;
}

.keyword-status {
  margin-left: 10px;
  font-size: 1.2rem;
}

.essay-score-display {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 15px 0;
  font-size: 1.2rem;
}

.essay-score-value {
  font-weight: 800;
  font-size: 1.8rem;
  color: #3B82F6;
  margin: 0 5px;
}

.essay-score-total {
  font-weight: 600;
  color: #64748b;
}

.keyword-match-detail {
  font-size: 0.9rem;
  color: #64748b;
  margin-top: 5px;
  padding: 8px;
  background: rgba(0,0,0,0.03);
  border-radius: 6px;
}

.keyword-match-detail strong {
  color: #3B82F6;
}

/* 解答题答题卡按钮 */
.answer-sheet-btn.essay {
  background: #9CA3AF;
}
.answer-sheet-btn.essay.correct {
  background: #10B981;
}
.answer-sheet-btn.essay.incorrect {
  background: #EF4444;
}
.answer-sheet-btn.essay.partial {
  background: linear-gradient(135deg, #FBBF24 50%, #9CA3AF 50%);
}
</style>
</head>
<body>
<div class="container">
  <header>
    <h1>增强版答题系统</h1>
    <p class="subtitle">解答题关键词评分优化 - 解决关键词匹配但得零分问题</p>
  </header>

  <div id="file-import-section" class="card file-import">
    <label for="file-upload" class="btn btn-primary">
      <i class="fas fa-file-import"></i> 选择题库文件
    </label>
    <input id="file-upload" type="file" accept=".csv, .xlsx, .xls">
    
    <div class="advanced-features">
      <div class="feature-item">
        <div class="feature-title">
          <i class="fas fa-random feature-icon"></i>
          <span>随机抽题设置</span>
        </div>
        <p class="help-text">请为每种题型设置抽取数量(0表示抽取全部题目)</p>
      </div>
      
      <div class="feature-item">
        <div class="feature-title">
          <i class="fas fa-language feature-icon"></i>
          <span>文件编码</span>
        </div>
        <select id="encoding-selector" class="encoding-selector">
          <option value="utf-8">UTF-8</option>
          <option value="gbk">GBK</option>
        </select>
      </div>
    </div>
    
    <!-- 打乱题目顺序选项 -->
    <div class="shuffle-container">
      <input type="checkbox" id="shuffle-questions" class="shuffle-checkbox">
      <label for="shuffle-questions" class="shuffle-label">
        <i class="fas fa-random"></i> 打乱题目顺序
      </label>
    </div>
    
    <!-- 模拟考试模式设置 -->
    <div class="exam-mode-container">
      <div class="exam-mode-toggle">
        <input type="checkbox" id="exam-mode-toggle" class="exam-toggle">
        <label for="exam-mode-toggle" class="exam-mode-title">
          <i class="fas fa-clock"></i> 模拟考试模式
        </label>
      </div>
      
      <div class="exam-settings">
        <label for="exam-duration">考试时长(分钟):</label>
        <input type="number" id="exam-duration" min="1" max="180" value="30" disabled>
      </div>
    </div>
    
    <!-- 题型分组设置 -->
    <div class="question-type-group">
      <div class="type-group">
        <div class="type-title">
          <i class="fas fa-dot-circle"></i>
          <span>单选题</span>
        </div>
        <div class="type-count">题库数量: <span id="single-count">0</span></div>
        <div class="type-controls">
          <label>抽取数量:</label>
          <input type="number" id="single-count-input" min="0" value="0">
        </div>
      </div>
      
      <div class="type-group">
        <div class="type-title">
          <i class="fas fa-check-double"></i>
          <span>多选题</span>
        </div>
        <div class="type-count">题库数量: <span id="multiple-count">0</span></div>
        <div class="type-controls">
          <label>抽取数量:</label>
          <input type="number" id="multiple-count-input" min="0" value="0">
        </div>
      </div>
      
      <div class="type-group">
        <div class="type-title">
          <i class="fas fa-check-circle"></i>
          <span>判断题</span>
        </div>
        <div class="type-count">题库数量: <span id="truefalse-count">0</span></div>
        <div class="type-controls">
          <label>抽取数量:</label>
          <input type="number" id="truefalse-count-input" min="0" value="0">
        </div>
      </div>
      
      <div class="type-group">
        <div class="type-title">
          <i class="fas fa-pen"></i>
          <span>填空题</span>
        </div>
        <div class="type-count">题库数量: <span id="fillblank-count">0</span></div>
        <div class="type-controls">
          <label>抽取数量:</label>
          <input type="number" id="fillblank-count-input" min="0" value="0">
        </div>
      </div>
      
      <div class="type-group">
        <div class="type-title">
          <i class="fas fa-comment"></i>
          <span>解答题</span>
        </div>
        <div class="type-count">题库数量: <span id="essay-count">0</span></div>
        <div class="type-controls">
          <label>抽取数量:</label>
          <input type="number" id="essay-count-input" min="0" value="0">
        </div>
      </div>
    </div>
    
    <div id="file-info" class="file-info">
      <div class="file-info-content">
        <span>&#10003;</span>
        <span id="selected-filename"></span>
      </div>
    </div>
    
    <!-- 导入状态显示 -->
    <div id="import-status" class="import-status">
      <i class="fas fa-spinner fa-spin"></i>
      <span id="import-message">正在处理文件...</span>
    </div>
    
    <button id="debug-toggle" class="debug-toggle-btn">显示调试信息</button>
    <div id="debug-info" class="debug-info">
      <h4 class="debug-title">调试信息:</h4>
      <p id="debug-details"></p>
    </div>
    <div id="start-quiz-section" class="start-quiz-section" style="display: none;">
      <button id="start-quiz-btn" class="btn btn-secondary">
        <i class="fas fa-play-circle"></i> 开始答题
      </button>
    </div>
    
    <!-- 文件格式说明放在底部 -->
    <div class="file-format">
      <div class="file-format-title">
        <i class="fas fa-info-circle"></i>
        <span>题库文件格式说明</span>
      </div>
      <p>支持CSV和Excel格式,第一行为标题行,支持以下字段(顺序不限):</p>
      <ul>
        <li><strong>问题</strong>: 题目内容(填空题使用 {1}、{2} 等作为占位符)</li>
        <li><strong>问题图片</strong>: 题目图片URL(可选)</li>
        <li><strong>选项A, 选项B, ...</strong>: 选项内容</li>
        <li><strong>选项A图片, 选项B图片, ...</strong>: 选项图片URL(可选)</li>
        <li><strong>答案</strong>: 正确答案(如A, AB, C等,填空题用 | 分隔不同空)</li>
        <li><strong>题目类型</strong>: single(单选题)、multiple(多选题)、truefalse(判断题)、fillblank(填空题)、essay(解答题)</li>
        <li><strong>题目分数</strong>: 该题分值</li>
        <li><strong>答案解析</strong>: 题目解析(可选)</li>
        <li><strong>评分规则</strong>: perBlank(按空给分)、allOrNothing(全对给分)、partialCredit(部分给分)</li>
        <li><strong>关键词1, 关键词1分值, 关键词2, 关键词2分值, ...</strong>: 解答题评分关键词(最多5组)</li>
        <li><strong>填空项1, 填空项2, ...</strong>: 填空题的提示文本(可选)</li>
      </ul>
    </div>
    
    <div class="download-sample">
      <a href="#" class="download-btn" id="download-sample">
        <i class="fas fa-download"></i> 下载示例题库文件
      </a>
    </div>
  </div>

  <!-- 倒计时容器 -->
  <div id="timer-container" class="timer-container">
    <span class="timer-label">剩余时间:</span>
    <span id="timer-value" class="timer-value">30:00</span>
  </div>

  <div class="flex-container">
    <div class="main-content">
      <!-- 进度条容器 - 初始隐藏 -->
      <div id="progress-container" class="progress-container">
        <div class="progress-title">
          <i class="fas fa-tasks"></i>
          <span>答题进度</span>
        </div>
        <div class="progress-bar">
          <div class="progress-fill" id="progress-fill" style="width: 0%"></div>
        </div>
        <div class="progress-labels">
          <div class="progress-label">
            <span>单选题</span>
            <span class="progress-value" id="single-progress">0/0</span>
          </div>
          <div class="progress-label">
            <span>多选题</span>
            <span class="progress-value" id="multiple-progress">0/0</span>
          </div>
          <div class="progress-label">
            <span>判断题</span>
            <span class="progress-value" id="truefalse-progress">0/0</span>
          </div>
          <div class="progress-label">
            <span>填空题</span>
            <span class="progress-value" id="fillblank-progress">0/0</span>
          </div>
          <div class="progress-label">
            <span>解答题</span>
            <span class="progress-value" id="essay-progress">0/0</span>
          </div>
        </div>
      </div>
      
      <div id="quiz-controls" class="quiz-controls">
        <div class="question-count">
          <span id="current-question">问题 1</span>
          <span id="total-questions" class="total-questions">/ 0</span>
        </div>
        <div class="score-display">
          <span>得分:</span>
          <span id="score" class="score-value">0</span>
        </div>
      </div>

      <div id="quiz-section" class="card question-section">
        <div class="question-header">
          <div class="question-type" id="question-type-tag">不定向选择题</div>
          <span id="question-points" class="points-badge">1分</span>
          <span id="scoring-mode" class="blank-scoring-mode" style="display: none;"></span>
        </div>
        <div id="question-content">
          <h2 id="question-text" class="question-text"></h2>
          <div id="question-image-container" class="image-container">
            <!-- 题目图片将在这里动态插入 -->
          </div>
        </div>
        <div id="options-container" class="options-container"></div>
        <div id="fillblank-container" class="fillblank-container" style="display: none;"></div>
        <div id="essay-container" class="essay-container" style="display: none;">
          <textarea id="essay-answer-box" class="essay-answer-box" placeholder="请输入您的解答..."></textarea>
          <div class="keyword-preview-tip">
            <i class="fas fa-info-circle"></i>
            <span>提交答案后可查看评分关键词</span>
          </div>
        </div>
        <div class="confirm-btn-container">
          <button id="confirm-btn" class="btn btn-primary">提交答案</button>
        </div>
        <div id="feedback" class="feedback"></div>
        <div id="keyword-feedback" class="keyword-feedback" style="display: none;"></div>
        <div id="explanation-content" class="explanation-content" style="display: none;"></div>
        <div class="button-group">
          <button id="prev-btn" class="btn btn-gray" disabled>
            <i class="fas fa-arrow-left"></i> 上一题
          </button>
          <button id="next-btn" class="btn btn-primary" disabled>
            下一题 <i class="fas fa-arrow-right"></i>
          </button>
        </div>
      </div>

      <div id="results-section" class="card results-section">
        <h2 class="results-title">测验完成!</h2>
        <p class="results-subtitle">恭喜你完成了所有问题</p>
        <div class="score-circle">
          <span id="final-score" class="final-score">0</span>
          <span>/</span>
          <span id="final-total" class="final-total">0</span>
        </div>
        <div class="results-buttons">
          <button id="restart-btn" class="btn btn-secondary">
            <i class="fas fa-redo"></i> 重新开始
          </button>
          <button id="export-results" class="export-btn">
            <i class="fas fa-file-export"></i> 导出测试结果
          </button>
          <button id="export-wrong-questions" class="wrong-questions-btn">
            <i class="fas fa-file-excel"></i> 导出错题集(Excel)
          </button>
          <button id="new-file-btn" class="btn btn-gray">
            <i class="fas fa-file"></i> 选择新文件
          </button>
        </div>
      </div>

      <div id="error-section" class="card error-section">
        <div class="error-icon-container"><span class="error-icon">!</span></div>
        <h3 class="error-title">文件处理错误</h3>
        <p id="error-message" class="error-message"></p>
        
        <div class="error-details">
          <div class="error-details-title">
            <i class="fas fa-bug"></i>
            <span>错误详情</span>
          </div>
          <div id="error-details-content" class="error-details-content"></div>
        </div>
        
        <div id="error-debug-info" class="debug-info">
          <h4 class="debug-title">调试信息:</h4>
          <p id="error-debug-details"></p>
        </div>
        <button id="retry-btn" class="btn btn-primary">重新选择文件</button>
      </div>
    </div>

    <div id="answer-sheet-section" class="sidebar answer-sheet-section">
      <div class="card answer-sheet">
        <h3 class="answer-sheet-title"><i class="fas fa-clipboard-list answer-sheet-icon"></i> 答题卡</h3>
        <div class="answer-stats">
          <div><span class="stat-label">已答:</span><span id="answered-count" class="stat-value">0</span></div>
          <div><span class="stat-label">正确:</span><span id="correct-count" class="stat-value stat-correct">0</span></div>
          <div><span class="stat-label">总题数:</span><span id="total-count" class="stat-value">0</span></div>
        </div>
        
        <!-- 单选题答题卡 -->
        <div id="single-section" class="type-section">
          <div class="type-section-title">
            <i class="fas fa-dot-circle type-section-icon"></i>
            <span>单选题</span>
          </div>
          <div id="single-grid" class="type-section-grid"></div>
          <div class="type-section-stats">
            <span>正确: <span id="single-correct" class="stat-value">0</span></span>
            <span>错误: <span id="single-incorrect" class="stat-value stat-incorrect">0</span></span>
            <span>总计: <span id="single-total" class="stat-value">0</span></span>
          </div>
        </div>
        
        <!-- 多选题答题卡 -->
        <div id="multiple-section" class="type-section">
          <div class="type-section-title">
            <i class="fas fa-check-double type-section-icon"></i>
            <span>多选题</span>
          </div>
          <div id="multiple-grid" class="type-section-grid"></div>
          <div class="type-section-stats">
            <span>正确: <span id="multiple-correct" class="stat-value">0</span></span>
            <span>错误: <span id="multiple-incorrect" class="stat-value stat-incorrect">0</span></span>
            <span>总计: <span id="multiple-total" class="stat-value">0</span></span>
          </div>
        </div>
        
        <!-- 判断题答题卡 -->
        <div id="truefalse-section" class="type-section">
          <div class="type-section-title">
            <i class="fas fa-check-circle type-section-icon"></i>
            <span>判断题</span>
          </div>
          <div id="truefalse-grid" class="type-section-grid"></div>
          <div class="type-section-stats">
            <span>正确: <span id="truefalse-correct" class="stat-value">0</span></span>
            <span>错误: <span id="truefalse-incorrect" class="stat-value stat-incorrect">0</span></span>
            <span>总计: <span id="truefalse-total" class="stat-value">0</span></span>
          </div>
        </div>
        
        <!-- 填空题答题卡 -->
        <div id="fillblank-section" class="type-section">
          <div class="type-section-title">
            <i class="fas fa-pen type-section-icon"></i>
            <span>填空题</span>
          </div>
          <div id="fillblank-grid" class="type-section-grid"></div>
          <div class="type-section-stats">
            <span>正确: <span id="fillblank-correct" class="stat-value">0</span></span>
            <span>错误: <span id="fillblank-incorrect" class="stat-value stat-incorrect">0</span></span>
            <span>总计: <span id="fillblank-total" class="stat-value">0</span></span>
          </div>
        </div>
        
        <!-- 解答题答题卡 -->
        <div id="essay-section" class="type-section">
          <div class="type-section-title">
            <i class="fas fa-comment type-section-icon"></i>
            <span>解答题</span>
          </div>
          <div id="essay-grid" class="type-section-grid"></div>
          <div class="type-section-stats">
            <span>正确: <span id="essay-correct" class="stat-value">0</span></span>
            <span>错误: <span id="essay-incorrect" class="stat-value stat-incorrect">0</span></span>
            <span>总计: <span id="essay-total" class="stat-value">0</span></span>
          </div>
        </div>
        
        <div class="legend">
          <div class="legend-item">
            <span class="legend-color legend-unanswered"></span>
            <span class="text-unanswered">未答</span>
          </div>
          <div class="legend-item">
            <span class="legend-color legend-current"></span>
            <span class="text-current">当前</span>
          </div>
          <div class="legend-item">
            <span class="legend-color legend-correct"></span>
            <span class="text-correct">正确</span>
          </div>
          <div class="legend-item">
            <span class="legend-color legend-incorrect"></span>
            <span class="text-incorrect">错误</span>
          </div>
          <div class="legend-item">
            <span class="legend-color legend-partial"></span>
            <span class="text-partial">部分</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- 图片预览模态框 -->
<div id="image-preview-modal" class="image-preview-modal">
  <button id="close-preview"><i class="fas fa-times"></i></button>
  <div class="preview-container">
    <img id="preview-image" src="" alt="预览图片">
    <div class="image-counter" id="image-counter">1/1</div>
  </div>
  <div class="preview-nav">
    <button id="prev-image" class="preview-nav-btn"><i class="fas fa-chevron-left"></i></button>
    <button id="next-image" class="preview-nav-btn"><i class="fas fa-chevron-right"></i></button>
  </div>
</div>

<script>
/* ========= 全局变量 ========= */
let questions = [], current = 0, score = 0, answered = 0, correct = 0;
let status = [];
const valid = ['A','B','C','D','E','F'];
let parsingErrors = [];
let totalPoints = 0;
let questionGroups = { single: [], multiple: [], truefalse: [], fillblank: [], essay: [] };
let selectedQuestions = [];
let currentImages = []; // 当前题目所有图片
let currentImageIndex = 0; // 当前预览图片索引
let examMode = false;
let examDuration = 30; // 默认30分钟
let examTimer = null;
let remainingTime = 0; // 剩余秒数
let globalTitles = []; // 存储CSV标题行

/* ========= DOM 快捷 ========= */
const el = id => document.getElementById(id);
const fileUpload = el('file-upload');
const fileImport = el('file-import-section');
const quiz = el('quiz-section');
const results = el('results-section');
const errorSec = el('error-section');
const controls = el('quiz-controls');
const answerSheet = el('answer-sheet-section');
const answeredEl = el('answered-count');
const correctEl = el('correct-count');
const totalEl = el('total-count');
const filenameEl = el('selected-filename');
const qText = el('question-text');
const qImageContainer = el('question-image-container');
const qNum = el('current-question');
const qTotal = el('total-questions');
const scoreEl = el('score');
const confirmBtn = el('confirm-btn');
const prevBtn = el('prev-btn');
const nextBtn = el('next-btn');
const finalScore = el('final-score');
const finalTotal = el('final-total');
const optionsContainer = el('options-container');
const fillblankContainer = el('fillblank-container');
const essayContainer = el('essay-container');
const essayAnswerBox = el('essay-answer-box');
const keywordFeedback = el('keyword-feedback');
const startQuizBtn = el('start-quiz-btn');
const startQuizSection = el('start-quiz-section');
const debugToggleBtn = el('debug-toggle');
const debugInfo = el('debug-info');
const debugDetails = el('debug-details');
const encodingSelector = el('encoding-selector');
const explanationContent = el('explanation-content');
const questionTypeTag = el('question-type-tag');
const questionPoints = el('question-points');
const scoringModeEl = el('scoring-mode');
const importStatus = el('import-status');
const importMessage = el('import-message');
const singleCountEl = el('single-count');
const multipleCountEl = el('multiple-count');
const truefalseCountEl = el('truefalse-count');
const fillblankCountEl = el('fillblank-count');
const essayCountEl = el('essay-count');
const singleCountInput = el('single-count-input');
const multipleCountInput = el('multiple-count-input');
const truefalseCountInput = el('truefalse-count-input');
const fillblankCountInput = el('fillblank-count-input');
const essayCountInput = el('essay-count-input');
const progressFill = el('progress-fill');
const singleProgressEl = el('single-progress');
const multipleProgressEl = el('multiple-progress');
const truefalseProgressEl = el('truefalse-progress');
const fillblankProgressEl = el('fillblank-progress');
const essayProgressEl = el('essay-progress');
const errorDetailsContent = el('error-details-content');
const exportResultsBtn = el('export-results');
const exportWrongQuestionsBtn = el('export-wrong-questions');
const shuffleCheckbox = el('shuffle-questions');
const examModeToggle = el('exam-mode-toggle');
const examDurationInput = el('exam-duration');
const timerContainer = el('timer-container');
const timerValue = el('timer-value');
const progressContainer = el('progress-container');

// 图片预览相关元素
const previewModal = el('image-preview-modal');
const previewImage = el('preview-image');
const imageCounter = el('image-counter');
const prevImageBtn = el('prev-image');
const nextImageBtn = el('next-image');
const closePreviewBtn = el('close-preview');

// 分类答题卡元素
const singleGrid = el('single-grid');
const multipleGrid = el('multiple-grid');
const truefalseGrid = el('truefalse-grid');
const fillblankGrid = el('fillblank-grid');
const essayGrid = el('essay-grid');
const singleCorrectEl = el('single-correct');
const singleIncorrectEl = el('single-incorrect');
const singleTotalEl = el('single-total');
const multipleCorrectEl = el('multiple-correct');
const multipleIncorrectEl = el('multiple-incorrect');
const multipleTotalEl = el('multiple-total');
const truefalseCorrectEl = el('truefalse-correct');
const truefalseIncorrectEl = el('truefalse-incorrect');
const truefalseTotalEl = el('truefalse-total');
const fillblankCorrectEl = el('fillblank-correct');
const fillblankIncorrectEl = el('fillblank-incorrect');
const fillblankTotalEl = el('fillblank-total');
const essayCorrectEl = el('essay-correct');
const essayIncorrectEl = el('essay-incorrect');
const essayTotalEl = el('essay-total');

/* ========= 事件绑定 ========= */
fileUpload.addEventListener('change', handleFile);
confirmBtn.addEventListener('click', confirmAnswer);
prevBtn.addEventListener('click', ()=> go(-1));
nextBtn.addEventListener('click', ()=> go(1));
el('restart-btn').addEventListener('click', restart);
el('new-file-btn').addEventListener('click', selectNewFile);
el('retry-btn').addEventListener('click', retryFile);
debugToggleBtn.addEventListener('click', toggleDebugInfo);
el('download-sample').addEventListener('click', downloadSample);
exportResultsBtn.addEventListener('click', exportResults);
exportWrongQuestionsBtn.addEventListener('click', exportWrongQuestionsExcel);
examModeToggle.addEventListener('change', toggleExamMode);
shuffleCheckbox.addEventListener('change', () => {
  // 当打乱顺序选项变化时不需要特殊处理
});

// 图片预览事件
prevImageBtn.addEventListener('click', showPrevImage);
nextImageBtn.addEventListener('click', showNextImage);
closePreviewBtn.addEventListener('click', closePreview);

// 使用事件委托确保按钮点击事件有效
document.addEventListener('click', function(e) {
  if (e.target && e.target.id === 'start-quiz-btn') {
    startQuiz();
  }
});

/* ========= 显示/隐藏调试信息 ========= */
function toggleDebugInfo() {
  debugInfo.classList.toggle('show');
}

/* ========= 下载示例题库 ========= */
function downloadSample() {
  const csvContent = `问题,问题图片,选项A,选项A图片,选项B,选项B图片,选项C,选项C图片,选项D,选项D图片,答案,题目类型,题目分数,答案解析,填空项1,填空项1分值,关键词1,关键词1分值,关键词2,关键词2分值,评分规则
"过完鸡年需要多久","https://img0.baidu.com/it/u=342342545,1451632770&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500","半年","","一年","","两年","","两年半","https://img0.baidu.com/it/u=342342545,1451632770&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500","D","single",1,"","","","","","","",""
"下列哪些是哺乳动物?","","鲸鱼","","海豚","","鲨鱼","","企鹅","","AB","multiple",2,"鲨鱼是鱼类,企鹅是鸟类","","","","","","",""
"地球是太阳系中最大的行星","","正确","","错误","",,,,,"B","truefalse",1,"木星是太阳系中最大的行星","","","","","","",""
"中国首都是{1},最大城市是{2}","",,,,,,,,,,"北京|上海","fillblank",2,"","首都","","","","","",""
"请写出两句蔡徐坤名言","",,,,,,,,,,"","essay",3,"","","哎呦,你干嘛",1,"一个真正的man,一个真正的男人他清楚自己要做什么",1,"partialCredit"`;
  
  const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.setAttribute('href', url);
  link.setAttribute('download', '示例题库.csv');
  link.style.visibility = 'hidden';
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

/* ========= 图片预览功能 ========= */
function showPreview(imgSrc, images) {
  currentImages = images;
  currentImageIndex = images.indexOf(imgSrc);
  
  if (currentImageIndex === -1) {
    currentImageIndex = 0;
  }
  
  updatePreview();
  previewModal.style.display = 'flex';
}

function updatePreview() {
  previewImage.src = currentImages[currentImageIndex];
  imageCounter.textContent = `${currentImageIndex + 1}/${currentImages.length}`;
}

function showPrevImage() {
  if (currentImages.length > 1) {
    currentImageIndex = (currentImageIndex - 1 + currentImages.length) % currentImages.length;
    updatePreview();
  }
}

function showNextImage() {
  if (currentImages.length > 1) {
    currentImageIndex = (currentImageIndex + 1) % currentImages.length;
    updatePreview();
  }
}

function closePreview() {
  previewModal.style.display = 'none';
}

// 点击模态框背景关闭预览
previewModal.addEventListener('click', function(e) {
  if (e.target === previewModal) {
    closePreview();
  }
});

/* ========= 文件读取 ========= */
function handleFile(e){
  const file = e.target.files[0];
  if(!file) return;
  
  // 更新导入状态
  importStatus.classList.add('show');
  importMessage.innerHTML = `<i class="fas fa-spinner fa-spin"></i> 正在处理文件:${file.name}`;
  
  filenameEl.textContent = file.name;
  el('file-info').classList.add('show');
  
  // 重置状态
  startQuizSection.style.display = 'none';
  
  const reader = new FileReader();
  const encoding = encodingSelector.value;
  const fileExt = file.name.split('.').pop().toLowerCase();
  
  // 处理Excel文件
  if (fileExt === 'xlsx' || fileExt === 'xls') {
    reader.onload = function(e) {
      try {
        const data = new Uint8Array(e.target.result);
        const workbook = XLSX.read(data, { type: 'array' });
        const firstSheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[firstSheetName];
        
        // 将工作表转换为JSON
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
        
        if (jsonData.length < 2) {
          showError('Excel文件中没有足够的数据');
          importStatus.classList.remove('show');
          return;
        }
        
        // 提取标题行(第一行)
        const titles = jsonData[0];
        
        // 提取数据行(从第二行开始)
        const rows = jsonData.slice(1).filter(row => row.length > 0);
        
        // 解析数据
        const res = parseExcelRows(rows, titles);
        questions = res.questions;
        parsingErrors = res.errors;
        globalTitles = titles;
        
        // 更新调试信息
        debugDetails.textContent = parsingErrors.length 
          ? parsingErrors.join('\n') 
          : '未发现解析错误';
        
        if(questions.length === 0){
          showError('未找到有效题目,请检查文件格式');
          importStatus.classList.remove('show');
        }else{
          // 分组题目
          groupQuestions();
          
          // 显示开始答题按钮
          startQuizSection.style.display = 'block';
          // 隐藏调试信息(默认)
          debugInfo.classList.remove('show');
          debugToggleBtn.style.display = 'inline-block';
          
          // 更新导入状态
          importStatus.className = 'import-status success show';
          importMessage.innerHTML = `<i class="fas fa-check-circle"></i> 成功导入${questions.length}道题目`;
        }
      } catch (err) {
        showError('处理Excel文件时出错: ' + err.message);
        importStatus.classList.remove('show');
      }
    };
    
    reader.readAsArrayBuffer(file);
  } 
  // 处理CSV文件
  else {
    reader.onload = ev => {
      try{
        let text = '';
        
        if (encoding === 'auto' || encoding === 'gbk') {
          // 尝试自动检测编码或处理GBK
          try {
            // 使用TextDecoder处理GBK编码
            const decoder = new TextDecoder('gbk');
            text = decoder.decode(ev.target.result);
          } catch (err) {
            // 如果失败,尝试UTF-8
            text = new TextDecoder('utf-8').decode(ev.target.result);
          }
        } else {
          // UTF-8处理
          text = cleanText(ev.target.result);
        }
        
        const res = parseCSV(text);
        questions = res.questions;
        parsingErrors = res.errors;
        globalTitles = res.titles; // 保存标题行
        
        // 更新调试信息
        debugDetails.textContent = parsingErrors.length 
          ? parsingErrors.join('\n') 
          : '未发现解析错误';
        
        if(questions.length === 0){
          showError('未找到有效题目,请检查文件格式');
          importStatus.classList.remove('show');
        }else{
          // 分组题目
          groupQuestions();
          
          // 显示开始答题按钮
          startQuizSection.style.display = 'block';
          // 隐藏调试信息(默认)
          debugInfo.classList.remove('show');
          debugToggleBtn.style.display = 'inline-block';
          
          // 更新导入状态
          importStatus.className = 'import-status success show';
          importMessage.innerHTML = `<i class="fas fa-check-circle"></i> 成功导入${questions.length}道题目`;
        }
        
        // 无论是否有错误,都让调试按钮可用
        debugToggleBtn.style.display = 'inline-block';
      }catch(err){
        showError(err.message);
        importStatus.classList.remove('show');
      }
    };
    
    // 使用readAsArrayBuffer以确保正确处理所有编码
    reader.readAsArrayBuffer(file);
  }
}

/* ---------- 文本清洗 ---------- */
function cleanText(buf){
  let str = typeof buf === 'string' ? buf : new TextDecoder('utf-8').decode(buf);
  if(str.charCodeAt(0) === 0xFEFF) str = str.slice(1);
  return str;
}

/* ---------- 分组题目 ---------- */
function groupQuestions() {
  questionGroups = { single: [], multiple: [], truefalse: [], fillblank: [], essay: [] };
  
  questions.forEach(q => {
    if (q.type === 'single') {
      questionGroups.single.push(q);
    } else if (q.type === 'multiple') {
      questionGroups.multiple.push(q);
    } else if (q.type === 'truefalse') {
      questionGroups.truefalse.push(q);
    } else if (q.type === 'fillblank') {
      questionGroups.fillblank.push(q);
    } else if (q.type === 'essay') {
      questionGroups.essay.push(q);
    }
  });
  
  // 更新UI显示题目数量
  singleCountEl.textContent = questionGroups.single.length;
  multipleCountEl.textContent = questionGroups.multiple.length;
  truefalseCountEl.textContent = questionGroups.truefalse.length;
  fillblankCountEl.textContent = questionGroups.fillblank.length;
  essayCountEl.textContent = questionGroups.essay.length;
  
  // 设置默认抽取数量为全部题目
  singleCountInput.value = questionGroups.single.length;
  multipleCountInput.value = questionGroups.multiple.length;
  truefalseCountInput.value = questionGroups.truefalse.length;
  fillblankCountInput.value = questionGroups.fillblank.length;
  essayCountInput.value = questionGroups.essay.length;
}

/* ========= 新增函数:处理填空题占位符 ========= */
function processFillblankQuestion(q) {
  // 复制问题对象以避免修改原始数据
  const processed = {...q};
  
  // 处理问题文本中的占位符 {1}, {2} 等
  const placeholderRegex = /\{(\d+)\}/g;
  let match;
  let blankCount = 0;
  
  // 计算空白数量
  while ((match = placeholderRegex.exec(q.question)) !== null) {
    blankCount = Math.max(blankCount, parseInt(match[1]));
  }
  
  // 如果问题文本中有占位符
  if (blankCount > 0) {
    // 创建空白答案数组(每个空对应一个空数组)
    for (let i = 0; i < blankCount; i++) {
      if (!processed.blankAnswers) {
        processed.blankAnswers = [];
      }
      if (!processed.blankAnswers[i]) {
        processed.blankAnswers.push([]);
      }
    }
    
    // 移除问题文本中的占位符
    processed.question = q.question.replace(placeholderRegex, (match, p1) => {
      const index = parseInt(p1) - 1;
      return `<span class="blank-placeholder" data-index="${p1}">${p1}.________</span>`;
    });
  }
  
  return processed;
}

/* ---------- 增强容错 CSV 解析器 ---------- */
function parseCSV(text) {
  const errors = [];
  const questions = [];
  const lines = text.split(/\r\n|\n|\r/);
  let rowIndex = 0;
  let currentLine = '';
  let inQuotes = false;
  let lineNumber = 0;
  let titles = [];

  // 处理带引号的CSV字段的解析器
  function parseCSVLine(line) {
    const fields = [];
    let currentField = '';
    let inQuotes = false;
    let i = 0;

    while (i < line.length) {
      const char = line[i];
      
      // 处理引号
      if (char === '"') {
        // 检查是否是双引号(转义的引号)
        if (i + 1 < line.length && line[i + 1] === '"') {
          currentField += '"';
          i += 2; // 跳过第二个引号
          continue;
        }
        inQuotes = !inQuotes;
        i++;
      } 
      // 处理逗号分隔符(仅当不在引号内时)
      else if (char === ',' && !inQuotes) {
        fields.push(currentField.trim());
        currentField = '';
        i++;
      } 
      // 普通字符
      else {
        currentField += char;
        i++;
      }
    }

    // 添加最后一个字段
    if (currentField !== '' || inQuotes) {
      fields.push(currentField.trim());
    }

    return { fields, inQuotes };
  }

  // 处理未闭合引号时尝试合并下一行
  function processLine(line) {
    lineNumber++;
    const trimmedLine = line.trim();
    if (!trimmedLine && !inQuotes) return null; // 跳过空行(除非在引号内)

    // 累加当前行内容
    currentLine += (currentLine ? '\n' : '') + line;
    
    // 解析当前累积的内容
    const result = parseCSVLine(currentLine);
    inQuotes = result.inQuotes;

    // 如果引号已闭合,处理这一行
    if (!inQuotes) {
      const processedLine = currentLine;
      currentLine = '';
      return { line: processedLine, lineNum: lineNumber, fields: result.fields };
    }
    
    // 引号未闭合,继续累积
    return null;
  }

  // 主解析循环
  for (let line of lines) {
    const processed = processLine(line);
    if (processed) {
      rowIndex++;
      
      // 第一行是标题行
      if (rowIndex === 1) {
        titles = processed.fields;
        continue;
      }
      
      try {
        const fields = processed.fields;
        
        // 至少需要有问题、至少一个选项和答案
        if (fields.length < 3) {
          throw new Error(`字段数量不足(至少需要3个字段,实际${fields.length}个)`);
        }
        
        // 动态查找字段位置
        const getFieldIndex = (fieldName) => {
          return titles.findIndex(t => t.toLowerCase().includes(fieldName.toLowerCase()));
        };
        
        const questionIndex = getFieldIndex('问题');
        const answerIndex = getFieldIndex('答案');
        const typeIndex = getFieldIndex('题目类型');
        const pointsIndex = getFieldIndex('题目分数');
        const explanationIndex = getFieldIndex('答案解析');
        const questionImageIndex = getFieldIndex('问题图片');
        const scoringModeIndex = getFieldIndex('评分规则');
        const blankHintPrefix = '填空项';
        const keywordPrefix = '关键词';
        
        // 验证必要字段是否存在
        if (questionIndex === -1) throw new Error('未找到"问题"字段');
        if (answerIndex === -1) throw new Error('未找到"答案"字段');
        
        // 提取问题
        const question = fields[questionIndex] || '';
        if (!question) throw new Error('问题内容为空');
        
        // 提取题目图片
        const questionImage = questionImageIndex !== -1 ? fields[questionImageIndex] : '';
        
        // 提取题目类型
        let type = 'multiple'; // 默认多选题
        if (typeIndex !== -1) {
          const typeStr = fields[typeIndex].toLowerCase();
          if (typeStr === 'single' || typeStr === '单选题') {
            type = 'single';
          } else if (typeStr === 'truefalse' || typeStr === '判断题') {
            type = 'truefalse';
          } else if (typeStr === 'fillblank' || typeStr === '填空题') {
            type = 'fillblank';
          } else if (typeStr === 'essay' || typeStr === '解答题') {
            type = 'essay';
          }
        }
        
        // 提取评分规则
        let scoringMode = 'allOrNothing'; // 默认全对给分
        if (scoringModeIndex !== -1) {
          const mode = fields[scoringModeIndex].toLowerCase();
          if (mode === 'perblank' || mode === '按空给分') {
            scoringMode = 'perBlank';
          } else if (mode === 'partialcredit' || mode === '部分给分') {
            scoringMode = 'partialCredit';
          }
        }
        
        // 提取选项
        let options = [];
        const optionPrefixes = ['A','B','C','D','E','F'];
        
        // 提取填空项提示
        let blankHints = [];
        for (let i = 0; i < 6; i++) {
          const hintIndex = getFieldIndex(`${blankHintPrefix}${i+1}`);
          if (hintIndex !== -1 && fields[hintIndex]) {
            blankHints.push(fields[hintIndex]);
          }
        }
        
        // 填空题特殊处理
        if (type === 'fillblank') {
          // 提取填空题答案(用|分隔不同空,用;分隔同一空的多个正确答案)
          let blankAnswers = [];
          let answers = fields[answerIndex] || '';
          
          // 修复:如果答案列为空,尝试使用填空项1列作为答案
          if (!answers.trim() && blankHints.length > 0) {
            answers = blankHints[0];
            errors.push(`警告:第${lineNumber}行填空题的答案字段为空,已使用填空项1列的内容作为答案。`);
          }
          
          if (answers) {
            // 按|分割不同填空项
            const blankParts = answers.split('|');
            blankParts.forEach(part => {
              // 按;分割同一空的不同正确答案
              const answersForBlank = part.split(';').map(a => a.trim()).filter(a => a);
              if (answersForBlank.length > 0) {
                blankAnswers.push(answersForBlank);
              }
            });
          }
          
          if (blankAnswers.length === 0) {
            throw new Error('填空题答案不能为空');
          }
          
          // 提取题目分数
          let points = 1; // 默认1分
          if (pointsIndex !== -1 && fields[pointsIndex]) {
            const pointsValue = parseInt(fields[pointsIndex]);
            if (!isNaN(pointsValue)) {
              points = pointsValue;
            }
          }
          
          // 提取答案解析
          let explanation = '';
          if (explanationIndex !== -1) {
            explanation = fields[explanationIndex] || '';
          }
          
          const fillblankQuestion = {
            question: question,
            questionImage: questionImage,
            type: type,
            points: points,
            explanation: explanation,
            blankAnswers: blankAnswers,
            blankHints: blankHints,
            scoringMode: scoringMode,
            rawFields: fields // 保存原始字段
          };
          
          // 处理填空题占位符
          questions.push(processFillblankQuestion(fillblankQuestion));
        } 
        // 解答题特殊处理
        else if (type === 'essay') {
          // 提取关键词和分值
          let keywords = [];
          for (let i = 0; i < 5; i++) {
            const keywordIndex = getFieldIndex(`${keywordPrefix}${i+1}`);
            const pointsIndex = getFieldIndex(`${keywordPrefix}${i+1}分值`);
            
            if (keywordIndex !== -1 && pointsIndex !== -1 && 
                fields[keywordIndex] && fields[pointsIndex]) {
              const keyword = fields[keywordIndex].trim();
              const points = parseInt(fields[pointsIndex]) || 0;
              
              if (keyword && points > 0) {
                keywords.push({ keyword, points });
              }
            }
          }
          
          // 提取题目分数
          let points = 1; // 默认1分
          if (pointsIndex !== -1 && fields[pointsIndex]) {
            const pointsValue = parseInt(fields[pointsIndex]);
            if (!isNaN(pointsValue)) {
              points = pointsValue;
            }
          }
          
          // 提取答案解析
          let explanation = '';
          if (explanationIndex !== -1) {
            explanation = fields[explanationIndex] || '';
          }
          
          questions.push({
            question: question,
            questionImage: questionImage,
            type: type,
            points: points,
            explanation: explanation,
            keywords: keywords,
            scoringMode: scoringMode,
            rawFields: fields // 保存原始字段
          });
        } 
        // 其他题型
        else {
          // 其他题型处理
          optionPrefixes.forEach(prefix => {
            const optionIndex = getFieldIndex(`选项${prefix}`);
            const optionImageIndex = getFieldIndex(`选项${prefix}图片`);
            const optionText = optionIndex !== -1 ? fields[optionIndex] : '';
            const optionImage = optionImageIndex !== -1 ? fields[optionImageIndex] : '';
            
            // 如果选项文本或图片存在,则添加选项
            if (optionText || optionImage) {
              options.push({
                text: optionText,
                image: optionImage
              });
            }
          });
          
          if (options.length === 0) throw new Error('未找到任何有效选项');
          
          // 判断题特殊处理
          if (type === 'truefalse') {
            // 判断题强制设置为两个选项
            if (options.length < 2) {
              options = [
                { text: '正确', image: '' },
                { text: '错误', image: '' }
              ];
            } else {
              options = options.slice(0, 2);
            }
          }
          
          // 提取答案
          let answer = (fields[answerIndex] || '').toUpperCase().replace(/[^A-F]/g, '');
          if (!answer) throw new Error('答案字段为空');
          
          // 生成选项标签(A, B, C...)
          const optionLabels = valid.slice(0, options.length);
          
          // 验证答案是否在有效选项范围内
          answer.split('').forEach(letter => {
            if (!optionLabels.includes(letter)) {
              throw new Error(`答案包含无效选项: ${letter},有效选项为${optionLabels.join(',')}`);
            }
          });
          
          // 提取题目分数
          let points = 1; // 默认1分
          if (pointsIndex !== -1 && fields[pointsIndex]) {
            const pointsValue = parseInt(fields[pointsIndex]);
            if (!isNaN(pointsValue)) {
              points = pointsValue;
            }
          }
          
          // 提取答案解析
          let explanation = '';
          if (explanationIndex !== -1) {
            explanation = fields[explanationIndex] || '';
          }
          
          questions.push({
            question: question,
            questionImage: questionImage,
            options: options,
            optionLabels: optionLabels,
            correctAnswers: answer.split(''),
            type: type,
            points: points,
            explanation: explanation,
            rawFields: fields // 保存原始字段
          });
        }
        
      } catch (err) {
        errors.push(`第 ${processed.lineNum} 行解析失败:${err.message}\n行内容:${processed.line.substring(0, 100)}${processed.line.length > 100 ? '...' : ''}`);
      }
    }
  }
  
  // 处理文件结束时仍未闭合的引号
  if (inQuotes && currentLine) {
    errors.push(`文件结束时存在未闭合的引号,未处理内容:${currentLine.substring(0, 100)}${currentLine.length > 100 ? '...' : ''}`);
  }
  
  return { questions, titles, errors };
}

/* ========= Excel 解析器 ========= */
function parseExcelRows(rows, titles) {
  const errors = [];
  const questions = [];
  
  rows.forEach((row, rowIndex) => {
    try {
      // 确保行长度与标题行一致
      const fields = [];
      for (let i = 0; i < titles.length; i++) {
        fields.push(row[i] || '');
      }
      
      // 至少需要有问题、至少一个选项和答案
      if (fields.length < 3) {
        throw new Error(`字段数量不足(至少需要3个字段,实际${fields.length}个)`);
      }
      
      // 动态查找字段位置
      const getFieldIndex = (fieldName) => {
        return titles.findIndex(t => t.toLowerCase().includes(fieldName.toLowerCase()));
      };
      
      const questionIndex = getFieldIndex('问题');
      const answerIndex = getFieldIndex('答案');
      const typeIndex = getFieldIndex('题目类型');
      const pointsIndex = getFieldIndex('题目分数');
      const explanationIndex = getFieldIndex('答案解析');
      const questionImageIndex = getFieldIndex('问题图片');
      const scoringModeIndex = getFieldIndex('评分规则');
      const blankHintPrefix = '填空项';
      const keywordPrefix = '关键词';
      
      // 验证必要字段是否存在
      if (questionIndex === -1) throw new Error('未找到"问题"字段');
      if (answerIndex === -1) throw new Error('未找到"答案"字段');
      
      // 提取问题
      const question = fields[questionIndex] || '';
      if (!question) throw new Error('问题内容为空');
      
      // 提取题目图片
      const questionImage = questionImageIndex !== -1 ? fields[questionImageIndex] : '';
      
      // 提取题目类型
      let type = 'multiple'; // 默认多选题
      if (typeIndex !== -1) {
        const typeStr = fields[typeIndex].toString().toLowerCase();
        if (typeStr === 'single' || typeStr === '单选题') {
          type = 'single';
        } else if (typeStr === 'truefalse' || typeStr === '判断题') {
          type = 'truefalse';
        } else if (typeStr === 'fillblank' || typeStr === '填空题') {
          type = 'fillblank';
        } else if (typeStr === 'essay' || typeStr === '解答题') {
          type = 'essay';
        }
      }
      
      // 提取评分规则
      let scoringMode = 'allOrNothing'; // 默认全对给分
      if (scoringModeIndex !== -1) {
        const mode = fields[scoringModeIndex].toString().toLowerCase();
        if (mode === 'perblank' || mode === '按空给分') {
          scoringMode = 'perBlank';
        } else if (mode === 'partialcredit' || mode === '部分给分') {
          scoringMode = 'partialCredit';
        }
      }
      
      // 提取选项
      let options = [];
      const optionPrefixes = ['A','B','C','D','E','F'];
      
      // 提取填空项提示
      let blankHints = [];
      for (let i = 0; i < 6; i++) {
        const hintIndex = getFieldIndex(`${blankHintPrefix}${i+1}`);
        if (hintIndex !== -1 && fields[hintIndex]) {
          blankHints.push(fields[hintIndex].toString());
        }
      }
      
      // 填空题特殊处理
      if (type === 'fillblank') {
        // 提取填空题答案(用|分隔不同空,用;分隔同一空的多个正确答案)
        let blankAnswers = [];
        let answers = fields[answerIndex] || '';
        
        // 修复:如果答案列为空,尝试使用填空项1列作为答案
        if (!answers.toString().trim() && blankHints.length > 0) {
          answers = blankHints[0];
          errors.push(`警告:第${rowIndex+2}行填空题的答案字段为空,已使用填空项1列的内容作为答案。`);
        }
        
        if (answers) {
          // 按|分割不同填空项
          const blankParts = answers.toString().split('|');
          blankParts.forEach(part => {
            // 按;分割同一空的不同正确答案
            const answersForBlank = part.split(';').map(a => a.trim()).filter(a => a);
            if (answersForBlank.length > 0) {
              blankAnswers.push(answersForBlank);
            }
          });
        }
        
        if (blankAnswers.length === 0) {
          throw new Error('填空题答案不能为空');
        }
        
        // 提取题目分数
        let points = 1; // 默认1分
        if (pointsIndex !== -1 && fields[pointsIndex]) {
          const pointsValue = parseInt(fields[pointsIndex]);
          if (!isNaN(pointsValue)) {
            points = pointsValue;
          }
        }
        
        // 提取答案解析
        let explanation = '';
        if (explanationIndex !== -1) {
          explanation = fields[explanationIndex].toString() || '';
        }
        
        const fillblankQuestion = {
          question: question,
          questionImage: questionImage,
          type: type,
          points: points,
          explanation: explanation,
          blankAnswers: blankAnswers,
          blankHints: blankHints,
          scoringMode: scoringMode,
          rawFields: fields // 保存原始字段
        };
        
        // 处理填空题占位符
        questions.push(processFillblankQuestion(fillblankQuestion));
      } 
      // 解答题特殊处理
      else if (type === 'essay') {
        // 提取关键词和分值
        let keywords = [];
        for (let i = 0; i < 5; i++) {
          const keywordIndex = getFieldIndex(`${keywordPrefix}${i+1}`);
          const pointsIndex = getFieldIndex(`${keywordPrefix}${i+1}分值`);
          
          if (keywordIndex !== -1 && pointsIndex !== -1 && 
              fields[keywordIndex] && fields[pointsIndex]) {
            const keyword = fields[keywordIndex].toString().trim();
            const points = parseInt(fields[pointsIndex]) || 0;
            
            if (keyword && points > 0) {
              keywords.push({ keyword, points });
            }
          }
        }
        
        // 提取题目分数
        let points = 1; // 默认1分
        if (pointsIndex !== -1 && fields[pointsIndex]) {
          const pointsValue = parseInt(fields[pointsIndex]);
          if (!isNaN(pointsValue)) {
            points = pointsValue;
          }
        }
        
        // 提取答案解析
        let explanation = '';
        if (explanationIndex !== -1) {
          explanation = fields[explanationIndex].toString() || '';
        }
        
        questions.push({
          question: question,
          questionImage: questionImage,
          type: type,
          points: points,
          explanation: explanation,
          keywords: keywords,
          scoringMode: scoringMode,
          rawFields: fields // 保存原始字段
        });
      } 
      // 其他题型
      else {
        // 其他题型处理
        optionPrefixes.forEach(prefix => {
          const optionIndex = getFieldIndex(`选项${prefix}`);
          const optionImageIndex = getFieldIndex(`选项${prefix}图片`);
          const optionText = optionIndex !== -1 ? fields[optionIndex].toString() : '';
          const optionImage = optionImageIndex !== -1 ? fields[optionImageIndex].toString() : '';
          
          // 如果选项文本或图片存在,则添加选项
          if (optionText || optionImage) {
            options.push({
              text: optionText,
              image: optionImage
            });
          }
        });
        
        if (options.length === 0) throw new Error('未找到任何有效选项');
        
        // 判断题特殊处理
        if (type === 'truefalse') {
          // 判断题强制设置为两个选项
          if (options.length < 2) {
            options = [
              { text: '正确', image: '' },
              { text: '错误', image: '' }
            ];
          } else {
            options = options.slice(0, 2);
          }
        }
        
        // 提取答案
        let answer = (fields[answerIndex] || '').toString().toUpperCase().replace(/[^A-F]/g, '');
        if (!answer) throw new Error('答案字段为空');
        
        // 生成选项标签(A, B, C...)
        const optionLabels = valid.slice(0, options.length);
        
        // 验证答案是否在有效选项范围内
        answer.split('').forEach(letter => {
          if (!optionLabels.includes(letter)) {
            throw new Error(`答案包含无效选项: ${letter},有效选项为${optionLabels.join(',')}`);
          }
        });
        
        // 提取题目分数
        let points = 1; // 默认1分
        if (pointsIndex !== -1 && fields[pointsIndex]) {
          const pointsValue = parseInt(fields[pointsIndex]);
          if (!isNaN(pointsValue)) {
            points = pointsValue;
          }
        }
        
        // 提取答案解析
        let explanation = '';
        if (explanationIndex !== -1) {
          explanation = fields[explanationIndex].toString() || '';
        }
        
        questions.push({
          question: question,
          questionImage: questionImage,
          options: options,
          optionLabels: optionLabels,
          correctAnswers: answer.split(''),
          type: type,
          points: points,
          explanation: explanation,
          rawFields: fields // 保存原始字段
        });
      }
      
    } catch (err) {
      errors.push(`第 ${rowIndex + 2} 行解析失败:${err.message}`);
    }
  });
  
  return { questions, errors };
}

/* ========= 开始答题 ========= */
function startQuiz() {
  // 确保有题目
  if (questions.length === 0) {
    showError('题库中没有题目,请重新导入文件');
    return;
  }
  
  // 隐藏文件导入部分
  fileImport.style.display = 'none';
  
  // 获取用户设置的题目数量
  const singleCount = parseInt(singleCountInput.value) || 0;
  const multipleCount = parseInt(multipleCountInput.value) || 0;
  const truefalseCount = parseInt(truefalseCountInput.value) || 0;
  const fillblankCount = parseInt(fillblankCountInput.value) || 0;
  const essayCount = parseInt(essayCountInput.value) || 0;
  
  // 抽取题目
  selectedQuestions = [];
  
  // 抽取单选题
  const selectedSingle = getRandomQuestions(questionGroups.single, singleCount);
  selectedQuestions = selectedQuestions.concat(selectedSingle);
  
  // 抽取多选题
  const selectedMultiple = getRandomQuestions(questionGroups.multiple, multipleCount);
  selectedQuestions = selectedQuestions.concat(selectedMultiple);
  
  // 抽取判断题
  const selectedTruefalse = getRandomQuestions(questionGroups.truefalse, truefalseCount);
  selectedQuestions = selectedQuestions.concat(selectedTruefalse);
  
  // 抽取填空题
  const selectedFillblank = getRandomQuestions(questionGroups.fillblank, fillblankCount);
  selectedQuestions = selectedQuestions.concat(selectedFillblank);
  
  // 抽取解答题
  const selectedEssay = getRandomQuestions(questionGroups.essay, essayCount);
  selectedQuestions = selectedQuestions.concat(selectedEssay);
  
  if (selectedQuestions.length === 0) {
    showError('未抽取到任何题目,请检查设置');
    return;
  }
  
  // 打乱题目顺序(如果用户选择了)
  if (shuffleCheckbox.checked) {
    selectedQuestions = shuffleArray(selectedQuestions);
  }
  
  // 初始化并显示答题界面
  current = score = answered = correct = 0;
  totalPoints = selectedQuestions.reduce((sum, q) => sum + q.points, 0);
  status = selectedQuestions.map((q) => {
    if (q.type === 'essay') {
      return {
        answered: false,
        score: 0,
        answerText: ''
      };
    } else if (q.type === 'fillblank') {
      return {
        answered: false,
        correct: false,
        selected: [],   // 选择题用
        blankAnswers: Array(q.blankAnswers?.length || 0).fill('') // 填空题用
      };
    } else {
      return {
        answered: false,
        correct: false,
        selected: []   // 选择题用
      };
    }
  });
  
  controls.classList.add('show');
  quiz.classList.add('show');
  answerSheet.classList.add('show');
  progressContainer.classList.add('show'); // 显示进度条
  
  // 构建答题卡(每种题型独立编号)
  buildAnswerSheet();
  renderQuestion(current);
  
  // 更新进度条
  updateProgress();
  
  // 启动考试计时器(如果启用了模拟考试模式)
  if (examMode) {
    startExamTimer();
  }
}

// 随机抽取题目
function getRandomQuestions(allQuestions, count) {
  if (count <= 0) return [];
  if (count >= allQuestions.length) return [...allQuestions];
  
  const shuffled = [...allQuestions].sort(() => 0.5 - Math.random());
  return shuffled.slice(0, count);
}

// 随机打乱数组
function shuffleArray(array) {
  const newArray = [...array];
  for (let i = newArray.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [newArray[i], newArray[j]] = [newArray[j], newArray[i]];
  }
  return newArray;
}

/* ---------- 分类答题卡 ---------- */
function buildAnswerSheet(){
  // 清空所有网格
  singleGrid.innerHTML = '';
  multipleGrid.innerHTML = '';
  truefalseGrid.innerHTML = '';
  fillblankGrid.innerHTML = '';
  essayGrid.innerHTML = '';
  
  // 重置统计数据
  singleTotalEl.textContent = '0';
  singleCorrectEl.textContent = '0';
  singleIncorrectEl.textContent = '0';
  
  multipleTotalEl.textContent = '0';
  multipleCorrectEl.textContent = '0';
  multipleIncorrectEl.textContent = '0';
  
  truefalseTotalEl.textContent = '0';
  truefalseCorrectEl.textContent = '0';
  truefalseIncorrectEl.textContent = '0';
  
  fillblankTotalEl.textContent = '0';
  fillblankCorrectEl.textContent = '0';
  fillblankIncorrectEl.textContent = '0';
  
  essayTotalEl.textContent = '0';
  essayCorrectEl.textContent = '0';
  essayIncorrectEl.textContent = '0';
  
  // 统计每种题型的题目数量
  const typeCounts = {
    single: 0,
    multiple: 0,
    truefalse: 0,
    fillblank: 0,
    essay: 0
  };
  
  // 创建题目按钮(每种题型独立编号)
  let questionIndex = 0;
  
  // 单选题答题卡
  const singleQuestions = selectedQuestions.filter(q => q.type === 'single');
  typeCounts.single = singleQuestions.length;
  singleQuestions.forEach((q, i) => {
    const btn = document.createElement('button');
    btn.className='answer-sheet-btn unanswered';
    btn.textContent = i+1;
    btn.onclick = ()=>{
      if(status[questionIndex].answered || current===questionIndex){
        renderQuestion(questionIndex);
      }else alert('请先完成当前题');
    };
    singleGrid.appendChild(btn);
    questionIndex++;
  });
  
  // 多选题答题卡
  const multipleQuestions = selectedQuestions.filter(q => q.type === 'multiple');
  typeCounts.multiple = multipleQuestions.length;
  multipleQuestions.forEach((q, i) => {
    const btn = document.createElement('button');
    btn.className='answer-sheet-btn unanswered';
    btn.textContent = i+1;
    btn.onclick = ()=>{
      if(status[questionIndex].answered || current===questionIndex){
        renderQuestion(questionIndex);
      }else alert('请先完成当前题');
    };
    multipleGrid.appendChild(btn);
    questionIndex++;
  });
  
  // 判断题答题卡
  const truefalseQuestions = selectedQuestions.filter(q => q.type === 'truefalse');
  typeCounts.truefalse = truefalseQuestions.length;
  truefalseQuestions.forEach((q, i) => {
    const btn = document.createElement('button');
    btn.className='answer-sheet-btn unanswered';
    btn.textContent = i+1;
    btn.onclick = ()=>{
      if(status[questionIndex].answered || current===questionIndex){
        renderQuestion(questionIndex);
      }else alert('请先完成当前题');
    };
    truefalseGrid.appendChild(btn);
    questionIndex++;
  });
  
  // 填空题答题卡
  const fillblankQuestions = selectedQuestions.filter(q => q.type === 'fillblank');
  typeCounts.fillblank = fillblankQuestions.length;
  fillblankQuestions.forEach((q, i) => {
    const btn = document.createElement('button');
    btn.className='answer-sheet-btn unanswered';
    btn.textContent = i+1;
    btn.onclick = ()=>{
      if(status[questionIndex].answered || current===questionIndex){
        renderQuestion(questionIndex);
      }else alert('请先完成当前题');
    };
    fillblankGrid.appendChild(btn);
    questionIndex++;
  });
  
  // 解答题答题卡
  const essayQuestions = selectedQuestions.filter(q => q.type === 'essay');
  typeCounts.essay = essayQuestions.length;
  essayQuestions.forEach((q, i) => {
    const btn = document.createElement('button');
    btn.className='answer-sheet-btn essay unanswered';
    btn.textContent = i+1;
    btn.onclick = ()=>{
      if(status[questionIndex].answered || current===questionIndex){
        renderQuestion(questionIndex);
      }else alert('请先完成当前题');
    };
    essayGrid.appendChild(btn);
    questionIndex++;
  });
  
  // 更新统计
  singleTotalEl.textContent = typeCounts.single;
  multipleTotalEl.textContent = typeCounts.multiple;
  truefalseTotalEl.textContent = typeCounts.truefalse;
  fillblankTotalEl.textContent = typeCounts.fillblank;
  essayTotalEl.textContent = typeCounts.essay;
  
  // 如果没有某种题型,隐藏对应的区域
  el('single-section').style.display = typeCounts.single > 0 ? 'block' : 'none';
  el('multiple-section').style.display = typeCounts.multiple > 0 ? 'block' : 'none';
  el('truefalse-section').style.display = typeCounts.truefalse > 0 ? 'block' : 'none';
  el('fillblank-section').style.display = typeCounts.fillblank > 0 ? 'block' : 'none';
  el('essay-section').style.display = typeCounts.essay > 0 ? 'block' : 'none';
  
  // 更新总题数
  totalEl.textContent = selectedQuestions.length;
  qTotal.textContent = `/ ${selectedQuestions.length}`;
}

/* ---------- 更新答题卡状态 ---------- */
function updateAnswerSheet() {
  // 重置统计数据
  let singleCorrect = 0, singleIncorrect = 0;
  let multipleCorrect = 0, multipleIncorrect = 0;
  let truefalseCorrect = 0, truefalseIncorrect = 0;
  let fillblankCorrect = 0, fillblankIncorrect = 0;
  let essayCorrect = 0, essayIncorrect = 0;
  
  // 更新所有按钮状态
  let questionIndex = 0;
  
  // 单选题
  const singleButtons = singleGrid.querySelectorAll('button');
  singleButtons.forEach((btn, i) => {
    const s = status[questionIndex];
    btn.className = 'answer-sheet-btn';
    
    if (questionIndex === current) {
      btn.classList.add('current');
    } else if (s.answered) {
      if (s.correct) {
        btn.classList.add('correct');
        singleCorrect++;
      } else {
        btn.classList.add('incorrect');
        singleIncorrect++;
      }
    } else {
      btn.classList.add('unanswered');
    }
    questionIndex++;
  });
  
  // 多选题
  const multipleButtons = multipleGrid.querySelectorAll('button');
  multipleButtons.forEach((btn, i) => {
    const s = status[questionIndex];
    btn.className = 'answer-sheet-btn';
    
    if (questionIndex === current) {
      btn.classList.add('current');
    } else if (s.answered) {
      if (s.correct) {
        btn.classList.add('correct');
        multipleCorrect++;
      } else {
        btn.classList.add('incorrect');
        multipleIncorrect++;
      }
    } else {
      btn.classList.add('unanswered');
    }
    questionIndex++;
  });
  
  // 判断题
  const truefalseButtons = truefalseGrid.querySelectorAll('button');
  truefalseButtons.forEach((btn, i) => {
    const s = status[questionIndex];
    btn.className = 'answer-sheet-btn';
    
    if (questionIndex === current) {
      btn.classList.add('current');
    } else if (s.answered) {
      if (s.correct) {
        btn.classList.add('correct');
        truefalseCorrect++;
      } else {
        btn.classList.add('incorrect');
        truefalseIncorrect++;
      }
    } else {
      btn.classList.add('unanswered');
    }
    questionIndex++;
  });
  
  // 填空题
  const fillblankButtons = fillblankGrid.querySelectorAll('button');
  fillblankButtons.forEach((btn, i) => {
    const s = status[questionIndex];
    btn.className = 'answer-sheet-btn';
    
    if (questionIndex === current) {
      btn.classList.add('current');
    } else if (s.answered) {
      if (s.correct) {
        btn.classList.add('correct');
        fillblankCorrect++;
      } else {
        btn.classList.add('incorrect');
        fillblankIncorrect++;
      }
    } else {
      btn.classList.add('unanswered');
    }
    questionIndex++;
  });
  
  // 解答题
  const essayButtons = essayGrid.querySelectorAll('button');
  essayButtons.forEach((btn, i) => {
    const s = status[questionIndex];
    btn.className = 'answer-sheet-btn essay';
    
    if (questionIndex === current) {
      btn.classList.add('current');
    } else if (s.answered) {
      // 解答题根据得分比例显示状态
      const q = selectedQuestions[questionIndex];
      const maxPoints = q.points;
      const earnedPoints = s.score;
      
      if (earnedPoints === maxPoints) {
        btn.classList.add('correct');
        essayCorrect++;
      } else if (earnedPoints > 0) {
        btn.classList.add('partial');
        essayIncorrect++;
      } else {
        btn.classList.add('incorrect');
        essayIncorrect++;
      }
    } else {
      btn.classList.add('unanswered');
    }
    questionIndex++;
  });
  
  // 更新统计显示
  singleCorrectEl.textContent = singleCorrect;
  singleIncorrectEl.textContent = singleIncorrect;
  
  multipleCorrectEl.textContent = multipleCorrect;
  multipleIncorrectEl.textContent = multipleIncorrect;
  
  truefalseCorrectEl.textContent = truefalseCorrect;
  truefalseIncorrectEl.textContent = truefalseIncorrect;
  
  fillblankCorrectEl.textContent = fillblankCorrect;
  fillblankIncorrectEl.textContent = fillblankIncorrect;
  
  essayCorrectEl.textContent = essayCorrect;
  essayIncorrectEl.textContent = essayIncorrect;
  
  // 更新总答题统计
  answered = status.filter(s => s.answered).length;
  correct = status.filter(s => {
    if (s.correct !== undefined) return s.correct; // 选择题
    if (s.score !== undefined) return s.score === selectedQuestions.find(q => q).points; // 解答题满分
    return false;
  }).length;
  
  answeredEl.textContent = answered;
  correctEl.textContent = correct;
}

/* ---------- 更新进度条 ---------- */
function updateProgress() {
  // 计算每种题型的进度
  const singleAnswered = status.filter((s, i) => 
    s.answered && selectedQuestions[i].type === 'single'
  ).length;
  
  const multipleAnswered = status.filter((s, i) => 
    s.answered && selectedQuestions[i].type === 'multiple'
  ).length;
  
  const truefalseAnswered = status.filter((s, i) => 
    s.answered && selectedQuestions[i].type === 'truefalse'
  ).length;
  
  const fillblankAnswered = status.filter((s, i) => 
    s.answered && selectedQuestions[i].type === 'fillblank'
  ).length;
  
  const essayAnswered = status.filter((s, i) => 
    s.answered && selectedQuestions[i].type === 'essay'
  ).length;
  
  // 更新进度值
  singleProgressEl.textContent = `${singleAnswered}/${questionGroups.single.length}`;
  multipleProgressEl.textContent = `${multipleAnswered}/${questionGroups.multiple.length}`;
  truefalseProgressEl.textContent = `${truefalseAnswered}/${questionGroups.truefalse.length}`;
  fillblankProgressEl.textContent = `${fillblankAnswered}/${questionGroups.fillblank.length}`;
  essayProgressEl.textContent = `${essayAnswered}/${questionGroups.essay.length}`;
  
  // 计算总进度
  const answeredCount = status.filter(s => s.answered).length;
  const progress = Math.round((answeredCount / selectedQuestions.length) * 100);
  progressFill.style.width = `${progress}%`;
}

/* ---------- 渲染题目 ---------- */
function renderQuestion(idx){
  if(idx<0||idx>=selectedQuestions.length) return;
  current = idx;
  const q = selectedQuestions[idx];
  
  // 设置题目类型
  let typeText = '';
  if (q.type === 'single') {
    typeText = '单选题';
  } else if (q.type === 'multiple') {
    typeText = '多选题';
  } else if (q.type === 'truefalse') {
    typeText = '判断题';
  } else if (q.type === 'fillblank') {
    typeText = '填空题';
  } else if (q.type === 'essay') {
    typeText = '解答题';
  }
  questionTypeTag.textContent = typeText;
  
  // 设置题目分数
  questionPoints.textContent = `${q.points}分`;
  
  qNum.textContent = `问题 ${idx+1}`;
  
  // 收集当前题目的所有图片(用于预览)
  const allImages = [];
  
  // 渲染题目图片 - 只在有图片URL时渲染
  qImageContainer.innerHTML = '';
  if (q.questionImage && q.questionImage.trim() !== '') {
    const imgContainer = document.createElement('div');
    imgContainer.className = 'image-container';
    
    const img = document.createElement('img');
    img.className = 'question-image';
    img.alt = '题目图片';
    img.src = q.questionImage;
    
    // 添加预览按钮
    const previewBtn = document.createElement('button');
    previewBtn.className = 'preview-btn';
    previewBtn.innerHTML = '<i class="fas fa-search-plus"></i> 预览';
    previewBtn.onclick = () => {
      const validImages = [q.questionImage, ...(q.options || []).map(o => o.image).filter(img => img && img.trim() !== '')];
      showPreview(q.questionImage, validImages);
    };
    
    imgContainer.appendChild(img);
    imgContainer.appendChild(previewBtn);
    qImageContainer.appendChild(imgContainer);
    
    allImages.push(q.questionImage);
  }
  
  // 显示或隐藏选项、填空题和解答题容器
  optionsContainer.style.display = ['single', 'multiple', 'truefalse'].includes(q.type) ? 'flex' : 'none';
  fillblankContainer.style.display = q.type === 'fillblank' ? 'block' : 'none';
  essayContainer.style.display = q.type === 'essay' ? 'block' : 'none';
  
  // 显示或隐藏评分规则
  if (q.type === 'fillblank' || q.type === 'essay') {
    scoringModeEl.style.display = 'inline-block';
    if (q.type === 'fillblank') {
      scoringModeEl.textContent = q.scoringMode === 'perBlank' ? '按空给分' : '全对给分';
      scoringModeEl.className = q.scoringMode === 'perBlank' ? 
        'blank-scoring-mode blank-scoring-per' : 'blank-scoring-mode blank-scoring-all';
    } else if (q.type === 'essay') {
      scoringModeEl.textContent = q.scoringMode === 'partialCredit' ? '部分给分' : '全对给分';
      scoringModeEl.className = q.scoringMode === 'partialCredit' ? 
        'scoring-mode scoring-partial' : 'scoring-mode scoring-all';
    }
  } else {
    scoringModeEl.style.display = 'none';
  }
  
  optionsContainer.innerHTML = '';
  fillblankContainer.innerHTML = '';
  essayAnswerBox.value = '';
  el('feedback').classList.remove('show');
  keywordFeedback.style.display = 'none';
  explanationContent.style.display = 'none';
  confirmBtn.disabled = false;
  nextBtn.disabled = !status[idx].answered;

  // 填空题特殊处理 - 内联输入框
  if (q.type === 'fillblank') {
    let questionHTML = q.question;
    const blankRegex = /<span class="blank-placeholder" data-index="(\d+)">(\d+).________<\/span>/g;
    
    let match;
    while ((match = blankRegex.exec(q.question)) !== null) {
      const blankIndex = parseInt(match[1]) - 1;
      const userAnswer = status[idx].blankAnswers[blankIndex] || '';
      const inputHtml = `<input type="text" class="inline-blank" data-index="${blankIndex}" 
                          value="${userAnswer}" 
                          placeholder="填写答案">`;
      questionHTML = questionHTML.replace(match[0], inputHtml);
    }
    
    qText.innerHTML = questionHTML;
    
    // 为内联输入框绑定事件
    setTimeout(() => {
      const blanks = qText.querySelectorAll('.inline-blank');
      blanks.forEach(input => {
        input.addEventListener('input', function() {
          const index = parseInt(this.dataset.index);
          status[idx].blankAnswers[index] = this.value.trim();
        });
      });
    }, 0);
  } 
  // 判断题特殊处理
  else if (q.type === 'truefalse') {
    qText.textContent = q.question;
    optionsContainer.innerHTML = `
      <div class="truefalse-container">
        <div class="truefalse-option" id="true-option">
          <span>&#10003;</span>
          <span>正确</span>
        </div>
        <div class="truefalse-option" id="false-option">
          <span>&#10007;</span>
          <span>错误</span>
        </div>
      </div>
    `;
    
    // 添加判断题事件监听
    const trueOption = el('true-option');
    const falseOption = el('false-option');
    
    trueOption.onclick = () => toggleTrueFalse(idx, 'A');
    falseOption.onclick = () => toggleTrueFalse(idx, 'B');
    
    // 设置选中状态
    if (status[idx].selected.includes('A')) {
      trueOption.classList.add('selected');
    }
    if (status[idx].selected.includes('B')) {
      falseOption.classList.add('selected');
    }
  } else if (q.type === 'essay') {
    // 解答题渲染
    qText.textContent = q.question;
    essayAnswerBox.value = status[idx].answerText || '';
    
    // 如果已答,显示反馈
    if (status[idx].answered) {
      showEssayFeedback(idx);
    }
  } else {
    // 其他题型渲染选项
    qText.textContent = q.question;
    q.optionLabels.forEach((lab, i) => {
      const optDiv = document.createElement('div');
      const sel = status[idx].selected.includes(lab);
      optDiv.className = `option ${sel ? 'selected' : ''}`;
      
      const option = q.options[i];
      let contentHtml = '';
      
      // 选项文本
      if (option.text) {
        contentHtml += `<div class="option-text">${option.text}</div>`;
      }
      
      // 选项图片
      if (option.image && option.image.trim() !== '') {
        contentHtml += `
          <div class="image-container" style="position: relative; margin-top: 15px;">
            <img src="${option.image}" class="option-image" alt="选项图片">
            <button class="preview-btn">
              <i class="fas fa-search-plus"></i> 预览
            </button>
          </div>
        `;
      }
      
      optDiv.innerHTML = `
        <div class="option-label">
          <span class="option-letter">${lab}</span>
          <div class="option-content">
            ${contentHtml}
          </div>
        </div>
      `;
      
      // 添加点击事件
      optDiv.onclick = ()=> toggleOption(idx,lab);
      optionsContainer.appendChild(optDiv);
      
      // 处理选项图片
      const imgContainer = optDiv.querySelector('.image-container');
      if (imgContainer) {
        const img = imgContainer.querySelector('img');
        const previewBtn = imgContainer.querySelector('.preview-btn');
        
        // 添加预览按钮事件
        previewBtn.onclick = (e) => {
          e.stopPropagation();
          const validImages = [q.questionImage, ...q.options.map(o => o.image).filter(img => img && img.trim() !== '')];
          showPreview(option.image, validImages);
        };
      }
    });
  }

  prevBtn.disabled = idx === 0;
  nextBtn.innerHTML = idx === selectedQuestions.length - 1 ? '<span>完成测验</span>' : '<span>下一题</span>';
  updateAnswerSheet();
}

// 判断题选项切换
function toggleTrueFalse(idx, option) {
  const s = status[idx].selected;
  // 清空所有选择(判断题只能选一个)
  s.length = 0;
  s.push(option);
  renderQuestion(idx);
}

// 其他题型选项切换
function toggleOption(idx,lab){
  const q = selectedQuestions[idx];
  const s = status[idx].selected;
  
  // 如果是单选题,先清除其他选择
  if (q.type === 'single') {
    s.length = 0;
  }
  
  const i = s.indexOf(lab);
  i>-1 ? s.splice(i,1) : s.push(lab);
  renderQuestion(idx);
}

function confirmAnswer(){
  const idx = current;
  const q = selectedQuestions[idx];
  const s = status[idx];
  
  // 填空题特殊处理
  if (q.type === 'fillblank') {
    // 收集内联输入框的值
    const blankInputs = qText.querySelectorAll('.inline-blank');
    blankInputs.forEach((input, i) => {
      s.blankAnswers[i] = input.value.trim();
    });
    
    // 检查是否所有空都已填写
    if (s.blankAnswers.some(answer => !answer)) {
      alert('请填写所有空白项');
      return;
    }
  } 
  // 解答题特殊处理
  else if (q.type === 'essay') {
    s.answerText = essayAnswerBox.value.trim();
    if (!s.answerText) {
      alert('请填写解答内容');
      return;
    }
  } 
  // 其他题型检查是否选择答案
  else {
    if(s.selected.length===0){ 
      alert('请至少选择一个答案'); 
      return; 
    }
  }

  // 检查答案是否正确
  const result = checkAnswer(q, s);
  const ok = result.ok;
  const earnedPoints = result.points;
  
  if(!s.answered){
    answered++;
    if(ok){ 
      correct++; 
    }
    score += earnedPoints;
  }else{
    const prevScore = q.type === 'essay' ? s.score : (s.correct ? q.points : 0);
    score -= prevScore;
    score += earnedPoints;
    
    if(ok && !s.correct){ 
      correct++; 
    }
    else if(!ok && s.correct){ 
      correct--; 
    }
  }
  
  s.answered = true; 
  s.correct = ok;
  if (q.type === 'essay') {
    s.score = earnedPoints;
  }
  
  showFeedback(q, s, earnedPoints);
  updateStats();
  confirmBtn.disabled=true;
  nextBtn.disabled=false;
  updateAnswerSheet();
  updateProgress();
}

// 关键词文本清理函数
function cleanKeywordText(str) {
  if (!str) return '';
  // 移除标点、空格和特殊字符,只保留中文、英文和数字
  return str.replace(/[^\w\u4e00-\u9fa5]/g, '').toLowerCase();
}

// 关键词匹配函数(支持部分匹配)
function matchKeyword(answer, keyword) {
  if (!answer || !keyword) return false;
  
  const cleanAnswer = cleanKeywordText(answer);
  const cleanKeyword = cleanKeywordText(keyword);
  
  // 如果清理后的关键词长度大于5,允许部分匹配
  if (cleanKeyword.length > 5) {
    // 计算关键词在答案中出现的比例
    let matchedChars = 0;
    for (const char of cleanKeyword) {
      if (cleanAnswer.includes(char)) {
        matchedChars++;
      }
    }
    
    // 如果匹配字符数达到关键词长度的80%,则认为匹配
    const matchThreshold = 0.8;
    return (matchedChars / cleanKeyword.length) >= matchThreshold;
  }
  
  // 短关键词要求完全包含
  return cleanAnswer.includes(cleanKeyword);
}

// 检查答案是否正确
function checkAnswer(q, s) {
  if (q.type === 'fillblank') {
    // 填空题检查
    if (q.scoringMode === 'allOrNothing') {
      // 全对给分模式:所有空都必须正确
      const allCorrect = q.blankAnswers.every((answers, i) => {
        return answers.includes(s.blankAnswers[i]);
      });
      return { 
        ok: allCorrect, 
        points: allCorrect ? q.points : 0 
      };
    } else {
      // 按空给分模式:计算正确空的数量
      const correctBlanks = q.blankAnswers.filter((answers, i) => {
        return answers.includes(s.blankAnswers[i]);
      }).length;
      const pointsPerBlank = q.points / q.blankAnswers.length;
      const earnedPoints = Math.round(correctBlanks * pointsPerBlank * 10) / 10;
      return { 
        ok: earnedPoints === q.points, 
        points: earnedPoints 
      };
    }
  } else if (q.type === 'essay') {
    // 解答题检查
    // 如果没有关键词,使用全文匹配
    if (!q.keywords || q.keywords.length === 0) {
      const isCorrect = s.answerText === q.fullAnswer;
      return { 
        ok: isCorrect, 
        points: isCorrect ? q.points : 0 
      };
    }
    
    // 使用关键词匹配
    let totalPoints = 0;
    
    if (q.scoringMode === 'allOrNothing') {
      // 全对给分模式:所有关键词都必须匹配
      const allMatched = q.keywords.every(kw => {
        return matchKeyword(s.answerText, kw.keyword);
      });
      totalPoints = allMatched ? q.points : 0;
    } else {
      // 部分给分模式:计算匹配关键词的总分
      q.keywords.forEach(kw => {
        if (matchKeyword(s.answerText, kw.keyword)) {
          totalPoints += kw.points;
        }
      });
      // 不超过题目总分
      totalPoints = Math.min(totalPoints, q.points);
    }
    
    return { 
      ok: totalPoints === q.points, 
      points: totalPoints 
    };
  } else {
    // 其他题型检查
    const isCorrect = JSON.stringify(s.selected.sort()) === JSON.stringify(q.correctAnswers.sort());
    return { 
      ok: isCorrect, 
      points: isCorrect ? q.points : 0 
    };
  }
}

function showFeedback(q, s, earnedPoints){
  const fb = el('feedback');
  
  if (q.type === 'fillblank') {
    // 填空题反馈
    let feedbackHTML = `<div>${earnedPoints > 0 ? '<span>&#10003;</span> 部分正确' : '<span>&#10007;</span> 不正确'}</div>`;
    feedbackHTML += `<div>得分: <strong>${earnedPoints}</strong> / ${q.points}</div>`;
    
    q.blankAnswers.forEach((answers, i) => {
      const userAnswer = s.blankAnswers[i] || '未填写';
      const isCorrect = answers.includes(userAnswer);
      
      feedbackHTML += `
        <div class="feedback-blank ${isCorrect ? 'correct' : 'incorrect'}">
          <div><strong>空 ${i+1}:</strong> ${userAnswer}</div>
          <div>${isCorrect ? '&#10003; 正确' : `&#10007; 正确答案: ${answers.join(' 或 ')}`}</div>
        </div>
      `;
    });
    
    fb.innerHTML = feedbackHTML;
  } else if (q.type === 'essay') {
    // 解答题反馈
    fb.innerHTML = earnedPoints > 0 
      ? `<div><span>&#10003;</span> 部分正确,得分: ${earnedPoints}/${q.points}</div>` 
      : `<div><span>&#10007;</span> 不正确,得分: 0/${q.points}</div>`;
    
    // 显示关键词反馈
    if (q.keywords && q.keywords.length > 0) {
      keywordFeedback.style.display = 'block';
      keywordFeedback.innerHTML = '<div style="font-weight:600; margin-bottom:10px;">关键词匹配情况:</div>';
      
      q.keywords.forEach(kw => {
        const isMatched = matchKeyword(s.answerText, kw.keyword);
        const cleanedKeyword = cleanKeywordText(kw.keyword);
        const cleanedAnswer = cleanKeywordText(s.answerText);
        
        keywordFeedback.innerHTML += `
          <div class="keyword-item ${isMatched ? 'correct' : 'incorrect'}">
            <div class="keyword-text">${kw.keyword}</div>
            <div class="keyword-points">${isMatched ? '+' : ''}${kw.points}分</div>
            <div class="keyword-status">${isMatched ? '&#10003;' : '&#10007;'}</div>
            <div class="keyword-match-detail">
              匹配详情: 关键词 <strong>${cleanedKeyword}</strong> 
              ${isMatched ? '在答案中被找到' : '未在答案中找到'}
            </div>
          </div>
        `;
      });
    }
  } else {
    // 其他题型反馈
    fb.innerHTML = earnedPoints > 0 
      ? `<span>&#10003;</span> 正确! +${q.points}分` 
      : `<span>&#10007;</span> 不正确,正确答案是 ${q.correctAnswers.join('、')}`;
  }
  
  fb.className = `feedback ${earnedPoints > 0 ? 'feedback-success' : 'feedback-error'} show`;
  
  // 显示答案解析
  if (q.explanation) {
    explanationContent.textContent = q.explanation;
    explanationContent.style.display = 'block';
  }
}

// 解答题反馈显示
function showEssayFeedback(idx) {
  const q = selectedQuestions[idx];
  const s = status[idx];
  
  if (s.answered) {
    showFeedback(q, s, s.score);
  }
}

function go(dir){
  if(dir===1 && current===selectedQuestions.length-1) return showResults();
  const next = current + dir;
  if(next>=0 && next<selectedQuestions.length) renderQuestion(next);
}

function updateStats(){
  answeredEl.textContent = answered;
  correctEl.textContent = correct;
  scoreEl.textContent = score;
}

function showResults(){
  quiz.classList.remove('show');
  controls.classList.remove('show');
  results.classList.add('show');
  finalScore.textContent = score;
  finalTotal.textContent = totalPoints;
  
  // 清除考试计时器
  if (examTimer) {
    clearInterval(examTimer);
    examTimer = null;
  }
  timerContainer.style.display = 'none';
}

function restart(){ 
  results.classList.remove('show'); 
  startQuiz();
}

function selectNewFile(){
  results.classList.remove('show');
  answerSheet.classList.remove('show');
  progressContainer.classList.remove('show'); // 隐藏进度条
  fileImport.style.display='block';
  fileUpload.value='';
  el('file-info').classList.remove('show');
  startQuizSection.style.display = 'none';
  debugInfo.classList.remove('show');
  importStatus.classList.remove('show');
}

function retryFile(){
  errorSec.classList.remove('show');
  fileImport.style.display='block';
  fileUpload.value='';
  el('file-info').classList.remove('show');
  startQuizSection.style.display = 'none';
  debugInfo.classList.remove('show');
  importStatus.classList.remove('show');
}

function showError(msg){
  el('error-message').textContent = msg;
  el('error-debug-details').textContent = parsingErrors.length 
    ? parsingErrors.join('\n') 
    : msg;
  el('error-debug-info').classList.toggle('show', parsingErrors.length > 0);
  
  // 显示错误详情
  errorDetailsContent.textContent = parsingErrors.length 
    ? parsingErrors.join('\n\n') 
    : msg;
  
  fileImport.classList.remove('show');
  fileImport.style.display='none';
  errorSec.classList.add('show');
  importStatus.classList.remove('show');
}

/* ========= 导出测试结果功能 ========= */
function exportResults() {
  // 收集错题
  const wrongQuestions = [];
  status.forEach((s, index) => {
    const q = selectedQuestions[index];
    const isCorrect = q.type === 'essay' ? s.score === q.points : s.correct;
    
    if (!isCorrect) {
      wrongQuestions.push({
        question: q,
        status: s,
        index: index + 1
      });
    }
  });

  // 生成导出HTML内容
  const exportHTML = `
  <!DOCTYPE html>
  <html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试结果报告</title>
    <style>
      body {
        font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
        background-color: #f5f7fa;
        color: #2c3e50;
        line-height: 1.6;
        margin: 0;
        padding: 20px;
      }
      .export-container {
        max-width: 800px;
        margin: 40px auto;
        padding: 30px;
        background: white;
        border-radius: 16px;
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
      }
      .export-header {
        text-align: center;
        margin-bottom: 30px;
        padding-bottom: 20px;
        border-bottom: 1px solid #eee;
      }
      .export-title {
        font-size: 2.2rem;
        background: linear-gradient(to right, #8e44ad, #3498db);
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
        margin-bottom: 10px;
      }
      .stats-grid {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 20px;
        margin-bottom: 30px;
      }
      .stat-card {
        background: #f8f9ff;
        border-radius: 12px;
        padding: 20px;
        text-align: center;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
      }
      .stat-value {
        font-size: 2.2rem;
        font-weight: 700;
        margin: 10px 0;
      }
      .stat-label {
        color: #64748b;
        font-size: 1rem;
      }
      .wrong-questions-section {
        margin-top: 40px;
      }
      .section-title {
        font-size: 1.5rem;
        font-weight: 700;
        color: #8e44ad;
        margin-bottom: 20px;
        display: flex;
        align-items: center;
        gap: 12px;
        padding-bottom: 10px;
        border-bottom: 2px solid #f0f2f5;
      }
      .wrong-question {
        background: #fef6ff;
        border-radius: 12px;
        padding: 25px;
        margin-bottom: 25px;
        border-left: 4px solid #e74c3c;
        position: relative;
      }
      .question-header-export {
        display: flex;
        justify-content: space-between;
        margin-bottom: 15px;
      }
      .question-type-export {
        display: inline-block;
        padding: 6px 14px;
        background: rgba(231, 76, 60, 0.1);
        color: #e74c3c;
        font-size: 0.9rem;
        font-weight: 600;
        border-radius: 50px;
      }
      .question-text-export {
        font-size: 1.25rem;
        font-weight: 600;
        margin-bottom: 20px;
        color: #2c3e50;
        line-height: 1.5;
      }
      .export-options-container {
        margin-bottom: 20px;
      }
      .export-option {
        padding: 15px;
        border: 1px solid #e5e7eb;
        border-radius: 10px;
        margin-bottom: 12px;
        background: white;
      }
      .export-option.correct {
        border-color: #10B981;
        background: rgba(16, 185, 129, 0.05);
      }
      .export-option.incorrect {
        border-color: #e74c3c;
        background: rgba(231, 76, 60, 0.05);
      }
      .option-label-export {
        display: flex;
        align-items: center;
      }
      .option-letter-export {
        flex-shrink: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 28px;
        height: 28px;
        border-radius: 50%;
        margin-right: 12px;
        font-weight: 600;
        font-size: 1rem;
      }
      .export-option.correct .option-letter-export {
        background: #10B981;
        color: #fff;
      }
      .export-option.incorrect .option-letter-export {
        background: #e74c3c;
        color: #fff;
      }
      .explanation-content-export {
        padding: 20px;
        background: #f8f9ff;
        border-radius: 12px;
        line-height: 1.7;
        margin-top: 20px;
        border-left: 4px solid #3498db;
      }
      .points-badge-export {
        background: rgba(231, 111, 81, 0.15);
        color: #e76f51;
        padding: 6px 14px;
        border-radius: 50px;
        font-size: 0.95rem;
        font-weight: 600;
        display: inline-block;
      }
      .footer-note {
        text-align: center;
        margin-top: 40px;
        color: #7f8c8d;
        font-size: 0.95rem;
        padding-top: 20px;
        border-top: 1px solid #eee;
      }
      .blank-answer-container {
        margin-top: 15px;
      }
      .blank-answer-row {
        display: flex;
        align-items: center;
        margin-bottom: 10px;
        gap: 10px;
      }
      .blank-number-export {
        width: 28px;
        height: 28px;
        border-radius: 50%;
        background: #9b59b6;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: 600;
        flex-shrink: 0;
      }
      .export-blank-answer {
        display: flex;
        align-items: center;
        gap: 10px;
      }
      .export-blank-input {
        background: white;
        border: 1px solid #e5e7eb;
        padding: 8px 15px;
        border-radius: 8px;
        font-weight: 500;
      }
      .export-blank-correct {
        background: #e6fffa;
        color: #0d9488;
        border-color: #0d9488;
      }
      .export-blank-incorrect {
        background: #ffebee;
        color: #e53935;
        border-color: #e53935;
      }
      .export-blank-label {
        font-weight: 600;
        min-width: 80px;
      }
      .scoring-mode-export {
        display: inline-block;
        padding: 6px 14px;
        border-radius: 50px;
        font-weight: 600;
        font-size: 0.9rem;
        margin-left: 15px;
      }
      .scoring-per {
        background: rgba(46, 204, 113, 0.15);
        color: #2ecc71;
      }
      .scoring-all {
        background: rgba(231, 76, 60, 0.15);
        color: #e74c3c;
      }
      .scoring-partial {
        background: rgba(241, 196, 15, 0.15);
        color: #f39c12;
      }
      .essay-answer-export {
        background: #f8f9ff;
        border-radius: 8px;
        padding: 15px;
        margin-top: 15px;
        border: 1px solid #e5e7eb;
      }
      .keyword-item-export {
        display: flex;
        align-items: center;
        padding: 8px;
        margin: 5px 0;
        border-radius: 8px;
        font-size: 0.95rem;
      }
      .keyword-item-export.correct {
        background: #e6fffa;
      }
      .keyword-item-export.incorrect {
        background: #ffebee;
      }
    </style>
  </head>
  <body>
    <div class="export-container">
      <div class="export-header">
        <h1 class="export-title">测试结果分析报告</h1>
        <p>${new Date().toLocaleDateString()} | ${filenameEl.textContent || '未命名测试'}</p>
      </div>
      
      <div class="stats-grid">
        <div class="stat-card">
          <div class="stat-value">${selectedQuestions.length}</div>
          <div class="stat-label">总题数</div>
        </div>
        <div class="stat-card">
          <div class="stat-value">${wrongQuestions.length}</div>
          <div class="stat-label">错题数</div>
        </div>
        <div class="stat-card">
          <div class="stat-value">${score}/${totalPoints}</div>
          <div class="stat-label">得分/总分</div>
        </div>
      </div>
      
      <div class="wrong-questions-section">
        <h2 class="section-title">
          <i class="fas fa-exclamation-circle"></i>
          错题分析 (${wrongQuestions.length}题)
        </h2>
        
        ${wrongQuestions.length > 0 ? wrongQuestions.map(q => renderWrongQuestion(q)).join('') : 
          `<div style="text-align: center; padding: 30px; background: #f8f9ff; border-radius: 12px;">
            <i class="fas fa-check-circle" style="font-size: 3rem; color: #2ecc71; margin-bottom: 20px;"></i>
            <h3>太棒了!本次测试没有错题</h3>
            <p>继续保持,你已掌握所有知识点</p>
          </div>`
        }
      </div>
      
      <div class="footer-note">
        <p>本报告由增强版答题系统生成 | ${new Date().toLocaleString()}</p>
      </div>
    </div>
  </body>
  </html>
  `;

  // 创建并下载文件
  const blob = new Blob([exportHTML], { type: 'text/html' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `测试报告_${new Date().toISOString().slice(0, 10)}.html`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

// 渲染单个错题
function renderWrongQuestion(q) {
  const question = q.question;
  const selected = q.status.selected;
  const blankAnswers = q.status.blankAnswers || [];
  const answerText = q.status.answerText || '';
  
  return `
  <div class="wrong-question">
    <div class="question-header-export">
      <div class="question-type-export">${getQuestionTypeText(question.type)}</div>
      <div class="points-badge-export">${question.points}分</div>
      ${question.type === 'fillblank' ? 
        `<span class="scoring-mode-export ${question.scoringMode === 'perBlank' ? 'scoring-per' : 'scoring-all'}">
          ${question.scoringMode === 'perBlank' ? '按空给分' : '全对给分'}
        </span>` : 
      question.type === 'essay' ? 
        `<span class="scoring-mode-export ${question.scoringMode === 'partialCredit' ? 'scoring-partial' : 'scoring-all'}">
          ${question.scoringMode === 'partialCredit' ? '部分给分' : '全对给分'}
        </span>` : ''
      }
    </div>
    
    <div class="question-text-export">
      <strong>${q.index}.</strong> ${question.question}
    </div>
    
    ${question.type === 'fillblank' ? renderFillblankAnswers(question, blankAnswers) : 
      question.type === 'essay' ? renderEssayAnswer(question, answerText) : 
      renderOptions(question, selected)}
    
    ${question.explanation ? `
      <div class="explanation-content-export">
        <strong>解析:</strong> ${question.explanation}
      </div>
    ` : ''}
  </div>
  `;
}

// 渲染填空题答案
function renderFillblankAnswers(q, userAnswers) {
  let html = '<div class="blank-answer-container">';
  
  q.blankAnswers.forEach((answers, i) => {
    const userAnswer = userAnswers[i] || '未填写';
    const isCorrect = answers.includes(userAnswer);
    
    html += `
      <div class="blank-answer-row">
        <div class="blank-number-export">${i + 1}</div>
        <div class="export-blank-answer">
          <span class="export-blank-label">您的答案:</span>
          <span class="export-blank-input ${isCorrect ? 'export-blank-correct' : 'export-blank-incorrect'}">${userAnswer}</span>
        </div>
        <div class="export-blank-answer">
          <span class="export-blank-label">正确答案:</span>
          <span class="export-blank-input">${answers.join(' 或 ')}</span>
        </div>
      </div>
    `;
  });
  
  html += '</div>';
  return html;
}

// 渲染解答题答案
function renderEssayAnswer(q, answerText) {
  let html = `
    <div class="essay-answer-export">
      <div><strong>您的解答:</strong></div>
      <div style="margin-top: 10px; padding: 10px; background: #f1f5f9; border-radius: 8px;">${answerText}</div>
    </div>
  `;
  
  if (q.keywords && q.keywords.length > 0) {
    html += '<div style="margin-top: 20px;"><strong>关键词匹配情况:</strong></div>';
    
    q.keywords.forEach(kw => {
      const isMatched = matchKeyword(answerText, kw.keyword);
      
      html += `
        <div class="keyword-item-export ${isMatched ? 'correct' : 'incorrect'}">
          <div style="flex: 1;">${kw.keyword}</div>
          <div style="min-width: 60px; text-align: right;">${isMatched ? '+' : ''}${kw.points}分</div>
          <div style="margin-left: 10px; font-size: 1.2rem;">${isMatched ? '&#10003;' : '&#10007;'}</div>
        </div>
      `;
    });
  }
  
  return html;
}

// 渲染选择题选项
function renderOptions(q, selected) {
  let optionsHtml = '<div class="export-options-container">';
  
  q.optionLabels.forEach((lab, i) => {
    const isCorrect = q.correctAnswers.includes(lab);
    const isSelected = selected.includes(lab);
    const option = q.options[i];
    let optionClass = '';
    if (isCorrect) optionClass = 'correct';
    else if (isSelected) optionClass = 'incorrect';
    
    optionsHtml += `
      <div class="export-option ${optionClass}">
        <div class="option-label-export">
          <span class="option-letter-export">${lab}</span>
          <div class="option-text">${option.text || ''}</div>
        </div>
        ${option.image && option.image.trim() !== '' ? 
          `<div style="margin-top: 12px;">
            <img src="${option.image}" style="max-width: 100%; max-height: 200px; border-radius: 8px; border: 1px solid #e5e7eb;">
          </div>` : ''
        }
      </div>
    `;
  });
  
  optionsHtml += '</div>';
  
  return optionsHtml + `
    <div style="display: flex; gap: 20px; margin-bottom: 15px;">
      <div style="flex: 1; background: rgba(231, 76, 60, 0.08); padding: 12px; border-radius: 8px;">
        <strong>您的答案:</strong> ${selected.join(', ') || '未作答'}
      </div>
      <div style="flex: 1; background: rgba(16, 185, 129, 0.08); padding: 12px; border-radius: 8px;">
        <strong>正确答案:</strong> ${q.correctAnswers.join(', ')}
      </div>
    </div>
  `;
}

// 获取题目类型文本
function getQuestionTypeText(type) {
  const types = {
    'single': '单选题',
    'multiple': '多选题',
    'truefalse': '判断题',
    'fillblank': '填空题',
    'essay': '解答题'
  };
  return types[type] || '未知题型';
}

/* ========= 导出错题集为Excel ========= */
function exportWrongQuestionsExcel() {
  // 收集错题
  const wrongQuestions = [];
  status.forEach((s, index) => {
    const q = selectedQuestions[index];
    const isCorrect = q.type === 'essay' ? s.score === q.points : s.correct;
    
    if (!isCorrect) {
      wrongQuestions.push({
        question: q,
        status: s,
        index: index + 1
      });
    }
  });

  if (wrongQuestions.length === 0) {
    alert('恭喜!本次测试没有错题,无需导出。');
    return;
  }

  // 准备Excel数据
  const wb = XLSX.utils.book_new();
  
  // 创建工作表数据
  const wsData = [globalTitles]; // 使用原始标题行作为表头
  
  // 添加错题数据
  wrongQuestions.forEach(wq => {
    const q = wq.question;
    
    // 使用原始字段数据(如果存在)
    if (q.rawFields) {
      wsData.push(q.rawFields);
    } 
    // 否则动态构建字段数据
    else {
      const row = [];
      
      // 动态映射字段
      const fieldMap = {
        '问题': q.question,
        '问题图片': q.questionImage || '',
        '题目类型': q.type,
        '题目分数': q.points,
        '答案解析': q.explanation || '',
        '答案': q.type === 'fillblank' ? 
                q.blankAnswers.map(arr => arr.join(';')).join('|') : 
                q.type === 'essay' ? '' : q.correctAnswers.join(''),
        '评分规则': q.type === 'fillblank' || q.type === 'essay' ? q.scoringMode : ''
      };
      
      // 添加选项字段
      for (let i = 0; i < 6; i++) {
        const prefix = valid[i];
        if (prefix) {
          fieldMap[`选项${prefix}`] = q.options && q.options[i] ? q.options[i].text : '';
          fieldMap[`选项${prefix}图片`] = q.options && q.options[i] ? q.options[i].image : '';
        }
      }
      
      // 添加填空提示字段
      if (q.type === 'fillblank' && q.blankHints) {
        q.blankHints.forEach((hint, idx) => {
          fieldMap[`填空项${idx + 1}`] = hint;
        });
      }
      
      // 添加关键词字段
      if (q.type === 'essay' && q.keywords) {
        q.keywords.forEach((kw, idx) => {
          fieldMap[`关键词${idx + 1}`] = kw.keyword;
          fieldMap[`关键词${idx + 1}分值`] = kw.points;
        });
      }
      
      // 按照原始标题顺序构建行
      globalTitles.forEach(title => {
        row.push(fieldMap[title] || '');
      });
      
      wsData.push(row);
    }
  });
  
  // 创建工作表
  const ws = XLSX.utils.aoa_to_sheet(wsData);
  
  // 添加工作表到工作簿
  XLSX.utils.book_append_sheet(wb, ws, '错题集');
  
  // 生成Excel文件并下载
  XLSX.writeFile(wb, `错题集_${new Date().toISOString().slice(0, 10)}.xlsx`);
}

/* ========= 模拟考试模式功能 ========= */
function toggleExamMode() {
  examMode = examModeToggle.checked;
  examDurationInput.disabled = !examMode;
  
  // 更新考试时长
  if (examMode) {
    examDuration = parseInt(examDurationInput.value) || 30;
  }
}

function startExamTimer() {
  // 清除现有计时器
  if (examTimer) {
    clearInterval(examTimer);
  }
  
  // 显示计时器
  timerContainer.style.display = 'flex';
  
  // 设置初始剩余时间(秒)
  remainingTime = examDuration * 60;
  
  // 更新计时器显示
  updateTimerDisplay();
  
  // 启动计时器
  examTimer = setInterval(() => {
    remainingTime--;
    updateTimerDisplay();
    
    // 最后5分钟警告
    if (remainingTime === 5 * 60) {
      timerValue.classList.add('timer-warning');
      alert('考试剩余5分钟!');
    }
    
    // 考试结束
    if (remainingTime <= 0) {
      clearInterval(examTimer);
      timerValue.textContent = "00:00";
      alert('考试时间到!系统将自动提交试卷。');
      forceSubmitExam();
    }
  }, 1000);
}

function updateTimerDisplay() {
  const minutes = Math.floor(remainingTime / 60).toString().padStart(2, '0');
  const seconds = (remainingTime % 60).toString().padStart(2, '0');
  timerValue.textContent = `${minutes}:${seconds}`;
}

function forceSubmitExam() {
  // 自动提交所有未答题目
  for (let i = 0; i < selectedQuestions.length; i++) {
    if (!status[i].answered) {
      // 如果是填空题,尝试获取答案
      if (selectedQuestions[i].type === 'fillblank') {
        const blankInputs = document.querySelectorAll('.inline-blank');
        blankInputs.forEach((input, index) => {
          status[i].blankAnswers[index] = input.value.trim();
        });
      }
      // 如果是解答题,获取答案文本
      else if (selectedQuestions[i].type === 'essay') {
        status[i].answerText = essayAnswerBox.value.trim();
      }
      
      // 标记为已答
      status[i].answered = true;
      
      // 检查答案
      const result = checkAnswer(selectedQuestions[i], status[i]);
      status[i].correct = result.ok;
      if (selectedQuestions[i].type === 'essay') {
        status[i].score = result.points;
      }
      
      // 更新统计
      if (result.ok) {
        correct++;
      }
      score += result.points;
    }
  }
  
  // 更新统计
  answered = selectedQuestions.length;
  updateStats();
  updateAnswerSheet();
  
  // 显示结果
  showResults();
}

// 初始化页面状态
function initPage() {
  fileImport.style.display = 'block';
  quiz.classList.remove('show');
  results.classList.remove('show');
  errorSec.classList.remove('show');
  answerSheet.classList.remove('show');
  progressContainer.classList.remove('show');
  controls.classList.remove('show');
  debugInfo.classList.remove('show');
  startQuizSection.style.display = 'none';
  importStatus.classList.remove('show');
  timerContainer.style.display = 'none';
  
  // 为考试时长输入框添加验证
  examDurationInput.addEventListener('change', function() {
    let value = parseInt(this.value);
    if (isNaN(value)) value = 30;
    if (value < 1) value = 1;
    if (value > 180) value = 180;
    this.value = value;
    examDuration = value;
  });
}

window.addEventListener('load', initPage);
</script>
</body>
</html>


题库制作工具

屏幕截图_8-8-2025_03248.png

源码

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>题库制作工具</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <script src="https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js"></script>
    <style>
        /* 原有样式保持不变 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
            color: #333;
            line-height: 1.6;
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            padding: 30px 0;
            margin-bottom: 30px;
        }
        
        h1 {
            font-size: 2.8rem;
            font-weight: 700;
            background: linear-gradient(90deg, #4361ee, #3a0ca3);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
            margin-bottom: 10px;
        }
        
        .subtitle {
            color: #6c757d;
            font-size: 1.2rem;
            max-width: 700px;
            margin: 0 auto;
        }
        
        .card {
            background: white;
            border-radius: 16px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
            padding: 30px;
            margin-bottom: 30px;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }
        
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.12);
        }
        
        .card-title {
            font-size: 1.5rem;
            color: #3a0ca3;
            margin-bottom: 20px;
            padding-bottom: 15px;
            border-bottom: 2px solid #f0f2f5;
            display: flex;
            align-items: center;
        }
        
        .card-title i {
            margin-right: 10px;
            color: #4361ee;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #495057;
        }
        
        input, textarea, select {
            width: 100%;
            padding: 14px;
            border: 2px solid #e1e5eb;
            border-radius: 10px;
            font-size: 1rem;
            transition: border-color 0.3s;
        }
        
        textarea {
            min-height: 120px;
            resize: vertical;
        }
        
        input:focus, textarea:focus, select:focus {
            border-color: #4361ee;
            outline: none;
            box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.15);
        }
        
        .option-row {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            gap: 10px;
        }
        
        .option-input {
            flex: 1;
        }
        
        .option-actions {
            display: flex;
            gap: 8px;
        }
        
        .btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            padding: 12px 24px;
            border-radius: 10px;
            font-weight: 600;
            font-size: 1rem;
            cursor: pointer;
            transition: all 0.3s ease;
            border: none;
            gap: 8px;
        }
        
        .btn i {
            font-size: 1.1rem;
        }
        
        .btn-primary {
            background: #4361ee;
            color: white;
        }
        
        .btn-primary:hover {
            background: #3a0ca3;
            transform: translateY(-2px);
        }
        
        .btn-success {
            background: #2a9d8f;
            color: white;
        }
        
        .btn-success:hover {
            background: #21867a;
            transform: translateY(-2px);
        }
        
        .btn-danger {
            background: #e76f51;
            color: white;
        }
        
        .btn-danger:hover {
            background: #d45d3f;
            transform: translateY(-2px);
        }
        
        .btn-outline {
            background: transparent;
            border: 2px solid #4361ee;
            color: #4361ee;
        }
        
        .btn-outline:hover {
            background: #f0f4ff;
        }
        
        .btn-sm {
            padding: 8px 15px;
            font-size: 0.9rem;
        }
        
        .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none !important;
        }
        
        .actions {
            display: flex;
            gap: 15px;
            flex-wrap: wrap;
            margin-top: 20px;
        }
        
        .question-list {
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
        }
        
        .question-list th {
            background: #f8f9fa;
            padding: 15px;
            text-align: left;
            color: #495057;
            font-weight: 600;
            border-bottom: 2px solid #e9ecef;
        }
        
        .question-list td {
            padding: 15px;
            border-bottom: 1px solid #e9ecef;
            vertical-align: top;
        }
        
        .question-list tr:hover td {
            background: #f8f9ff;
        }
        
        .question-text {
            max-width: 300px;
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
        }
        
        .options-preview {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
        }
        
        .option-tag {
            background: #e7f4ff;
            color: #1a73e8;
            padding: 5px 12px;
            border-radius: 20px;
            font-size: 0.85rem;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .option-tag.correct {
            background: #e6f7ee;
            color: #0a9d58;
        }
        
        .list-actions {
            display: flex;
            gap: 10px;
        }
        
        .action-btn {
            padding: 8px;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s;
            background: #f8f9fa;
            border: 1px solid #e1e5eb;
            color: #495057;
        }
        
        .action-btn:hover {
            background: #edf2ff;
            color: #4361ee;
            border-color: #d0d9ff;
        }
        
        .preview-card {
            background: #f8f9ff;
            border: 2px dashed #d0d9ff;
            padding: 25px;
            border-radius: 12px;
            margin-top: 20px;
        }
        
        .preview-title {
            font-size: 1.2rem;
            color: #4361ee;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .preview-question {
            font-size: 1.3rem;
            font-weight: 600;
            margin-bottom: 20px;
            color: #212529;
        }
        
        .preview-options {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 15px;
        }
        
        .preview-option {
            padding: 15px;
            border: 2px solid #e1e5eb;
            border-radius: 10px;
            background: white;
            display: flex;
            align-items: center;
            gap: 15px;
            transition: all 0.2s;
            cursor: default;
        }
        
        .preview-option.correct {
            border-color: #2a9d8f;
            background: #f0faf7;
        }
        
        .option-letter {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            background: #f0f4ff;
            color: #4361ee;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 700;
            flex-shrink: 0;
        }
        
        .preview-option.correct .option-letter {
            background: #2a9d8f;
            color: white;
        }
        
        .empty-state {
            text-align: center;
            padding: 40px 20px;
            color: #6c757d;
        }
        
        .empty-state i {
            font-size: 3rem;
            margin-bottom: 20px;
            color: #ced4da;
        }
        
        .counter {
            display: flex;
            justify-content: space-between;
            margin-top: 20px;
            padding-top: 20px;
            border-top: 2px solid #f0f2f5;
            font-weight: 600;
            color: #495057;
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .counter div {
            background: #f8f9ff;
            padding: 8px 15px;
            border-radius: 8px;
            border: 1px solid #e1e5eb;
        }
        
        .counter span {
            color: #4361ee;
        }
        
        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 15px 25px;
            border-radius: 10px;
            background: white;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            display: flex;
            align-items: center;
            gap: 15px;
            transform: translateX(150%);
            transition: transform 0.4s ease;
            z-index: 1000;
        }
        
        .notification.show {
            transform: translateX(0);
        }
        
        .notification.success {
            border-left: 4px solid #2a9d8f;
        }
        
        .notification.error {
            border-left: 4px solid #e76f51;
        }
        
        .notification i {
            font-size: 1.5rem;
        }
        
        .notification.success i {
            color: #2a9d8f;
        }
        
        .notification.error i {
            color: #e76f51;
        }
        
        .notification-content h3 {
            margin-bottom: 5px;
        }
        
        .highlight {
            animation: highlight 1.5s ease;
        }
        
        @keyframes highlight {
            0% { background-color: rgba(67, 97, 238, 0.2); }
            100% { background-color: transparent; }
        }
        
        .question-type {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
        }
        
        .type-option {
            flex: 1;
            text-align: center;
            padding: 15px;
            border-radius: 10px;
            background: #f8f9fa;
            cursor: pointer;
            border: 2px solid #e1e5eb;
            transition: all 0.3s;
        }
        
        .type-option.selected {
            border-color: #4361ee;
            background: #eef2ff;
            box-shadow: 0 5px 15px rgba(67, 97, 238, 0.1);
        }
        
        .type-option i {
            font-size: 1.5rem;
            margin-bottom: 10px;
            color: #4361ee;
        }
        
        .type-option.selected i {
            color: #3a0ca3;
        }
        
        .points-input {
            display: flex;
            align-items: center;
            gap: 10px;
            background: #f8f9fa;
            padding: 15px;
            border-radius: 10px;
        }
        
        .points-input input {
            max-width: 80px;
        }
        
        .points-label {
            font-weight: 600;
        }
        
        .points-hint {
            color: #6c757d;
            font-size: 0.9rem;
        }
        
        .badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 20px;
            font-size: 0.8rem;
            font-weight: 600;
        }
        
        .badge-single {
            background: rgba(67, 97, 238, 0.15);
            color: #4361ee;
        }
        
        .badge-multiple {
            background: rgba(42, 157, 143, 0.15);
            color: #2a9d8f;
        }
        
        .badge-truefalse {
            background: rgba(231, 111, 81, 0.15);
            color: #e76f51;
        }
        
        .badge-fillblank {
            background: rgba(155, 89, 182, 0.15);
            color: #9b59b6;
        }
        
        .badge-essay {
            background: rgba(241, 196, 15, 0.15);
            color: #f39c12;
        }
        
        .badge-points {
            background: rgba(231, 111, 81, 0.15);
            color: #e76f51;
        }
        
        /* 新布局样式 - 优化部分 */
        .import-export-actions {
            display: flex;
            flex-direction: column;
            gap: 15px;
            width: 100%;
            margin-top: 20px;
        }
        
        .actions-row {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            align-items: center;
            width: 100%;
        }
        
        .action-group {
            display: flex;
            flex: 1;
            min-width: 120px;
            height: 48px;
        }
        
        .filename-group {
            flex: 1;
            min-width: 180px;
            max-width: 300px;
            height: 48px;
        }
        
        .filename-group input {
            padding: 12px 15px;
            height: 100%;
            min-width: 250px;
        }
        
        .encoding-group {
            min-width: 130px;
            max-width: 150px;
            height: 48px;
        }
        
        .encoding-group select {
            padding: 12px 15px;
            padding-right: 35px;
            border-radius: 10px;
            background: #f8f9fa;
            border: 2px solid #4361ee;
            color: #4361ee;
            font-weight: 600;
            cursor: pointer;
            appearance: none;
            position: relative;
            height: 100%;
            width: 100%;
        }
        
        .btn-group {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
            flex: 1;
        }
        
        .btn-group .btn {
            flex: 1;
            min-width: 120px;
            width: 100%;
            height: 48px;
            padding: 0 15px;
        }
        
        /* 图片相关样式 */
        .image-container {
            margin-top: 10px;
            position: relative;
            display: none;
            background: #f8f9ff;
            padding: 15px;
            border-radius: 10px;
            border: 1px solid #e1e5eb;
        }
        
        .image-preview {
            max-width: 100%;
            max-height: 200px;
            border-radius: 8px;
            margin-top: 10px;
            display: none;
            border: 1px solid #e1e5eb;
            overflow: auto;
        }
        
        .image-preview img {
            max-width: 100%;
            max-height: 200px;
            display: block;
        }
        
        .remove-image-btn {
            position: absolute;
            top: 5px;
            right: 5px;
            background: rgba(231, 111, 81, 0.8);
            color: white;
            border: none;
            border-radius: 50%;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 0.8rem;
        }
        
        .add-image-btn {
            margin-top: 8px;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 8px 12px;
            background: #f0f4ff;
            border: 1px dashed #4361ee;
            border-radius: 8px;
            color: #4361ee;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .add-image-btn:hover {
            background: #e1e9ff;
        }
        
        .option-image-container {
            margin-top: 8px;
            position: relative;
            display: none;
            background: #f8f9ff;
            padding: 10px;
            border-radius: 8px;
            border: 1px solid #e1e5eb;
        }
        
        .option-image-preview {
            max-width: 100%;
            max-height: 100px;
            border-radius: 6px;
            margin-top: 8px;
            display: none;
            border: 1px solid #e1e5eb;
            overflow: auto;
        }
        
        .option-image-preview img {
            max-width: 100%;
            max-height: 100px;
            display: block;
        }
        
        .image-input {
            margin-top: 8px;
        }
        
        .image-label {
            display: flex;
            align-items: center;
            gap: 8px;
            font-weight: 600;
            color: #4361ee;
        }
        
        .option-image-label {
            font-size: 0.9rem;
            margin-top: 8px;
        }
        
        .preview-image {
            max-width: 100%;
            max-height: 300px;
            border-radius: 8px;
            margin: 15px 0;
            display: block;
            border: 1px solid #e1e5eb;
        }
        
        .option-preview-image {
            max-width: 100%;
            max-height: 100px;
            border-radius: 6px;
            margin-top: 8px;
        }
        
        .question-text-with-image {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        
        .option-with-image {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        
        /* 图片选项样式 */
        .image-option {
            border: 2px solid #e1e5eb;
            border-radius: 10px;
            padding: 10px;
            text-align: center;
            transition: all 0.2s;
            cursor: pointer;
            position: relative;
            overflow: hidden;
            height: 150px;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }
        
        .image-option:hover {
            border-color: #4361ee;
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        
        .image-option.selected {
            border-color: #4361ee;
            background-color: #f0f4ff;
        }
        
        .image-option.correct {
            border-color: #2a9d8f;
            background-color: #e6f7ee;
        }
        
        .option-image {
            max-height: 100px;
            max-width: 100%;
            object-fit: contain;
            margin: 0 auto;
            flex-grow: 1;
        }
        
        .option-image-label {
            font-size: 0.9rem;
            margin-top: 5px;
            font-weight: 600;
            color: #4361ee;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        
        .image-option .option-letter {
            position: absolute;
            top: 5px;
            left: 5px;
            width: 28px;
            height: 28px;
            font-size: 0.9rem;
        }
        
        .image-option-preview {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
            gap: 15px;
            margin-top: 15px;
        }
        
        .image-option-preview-item {
            border: 2px solid #e1e5eb;
            border-radius: 10px;
            padding: 10px;
            text-align: center;
            height: 120px;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }
        
        .image-option-preview-item img {
            max-height: 80px;
            max-width: 100%;
            object-fit: contain;
            margin: 0 auto;
        }
        
        .image-option-preview-label {
            font-size: 0.8rem;
            margin-top: 5px;
            font-weight: 600;
            color: #4361ee;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        
        .option-type-toggle {
            display: flex;
            gap: 10px;
            margin-top: 10px;
        }
        
        .option-type-btn {
            flex: 1;
            padding: 8px;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s;
            background: #f8f9fa;
            border: 2px solid #e1e5eb;
            text-align: center;
            font-size: 0.9rem;
        }
        
        .option-type-btn.selected {
            background: #eef2ff;
            border-color: #4361ee;
            color: #4361ee;
            font-weight: 600;
        }
        
        /* 填空题样式 */
        #blanks-section {
            display: none;
            background: #f8f9ff;
            padding: 15px;
            border-radius: 12px;
            border: 1px solid #e1e5eb;
            margin-bottom: 15px;
        }
        
        .blank-row {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 12px;
            padding: 12px;
            background: white;
            border-radius: 8px;
            border: 1px solid #e1e5eb;
        }
        
        .blank-row .blank-number {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            background: #9b59b6;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            flex-shrink: 0;
        }
        
        .blank-input {
            flex: 1;
        }
        
        .blank-points {
            width: 100px;
        }
        
        .scoring-mode {
            display: flex;
            gap: 15px;
            margin-bottom: 15px;
        }
        
        .mode-option {
            flex: 1;
            padding: 12px;
            border-radius: 8px;
            background: #f8f9fa;
            border: 2px solid #e1e5eb;
            cursor: pointer;
            text-align: center;
            transition: all 0.2s;
        }
        
        .mode-option.selected {
            background: #f0e6ff;
            border-color: #9b59b6;
            color: #9b59b6;
            font-weight: 600;
        }
        
        .mode-option i {
            margin-right: 5px;
            color: #9b59b6;
        }
        
        .preview-blank {
            display: flex;
            flex-direction: column;
            gap: 10px;
            background: white;
            border-radius: 8px;
            padding: 15px;
            border: 1px solid #e1e5eb;
            margin-bottom: 10px;
        }
        
        .preview-blank-header {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .preview-blank-number {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: #9b59b6;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            flex-shrink: 0;
        }
        
        .preview-blank-content {
            padding-left: 38px;
        }
        
        .blank-answer {
            background: #f0e6ff;
            padding: 5px 10px;
            border-radius: 4px;
            margin-top: 5px;
            display: inline-block;
        }
        
        /* 填空题增强样式 */
        .question-text-editor {
            position: relative;
        }
        
        .insert-blank-toolbar {
            display: flex;
            gap: 10px;
            margin-top: 10px;
            flex-wrap: wrap;
            display: none; /* 默认隐藏 */
        }
        
        .insert-blank-btn {
            padding: 8px 15px;
            background: #eef2ff;
            border: 1px solid #d0d9ff;
            border-radius: 6px;
            color: #4361ee;
            cursor: pointer;
            font-size: 0.95rem;
            display: flex;
            align-items: center;
            gap: 5px;
            transition: all 0.2s;
        }
        
        .insert-blank-btn:hover {
            background: #dce5ff;
            transform: translateY(-2px);
        }
        
        .blank-preview {
            background: #f8f9ff;
            padding: 15px;
            border-radius: 10px;
            margin-top: 15px;
            border: 1px solid #e1e5eb;
        }
        
        .blank-preview-title {
            font-weight: 600;
            color: #4361ee;
            margin-bottom: 10px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .blank-preview-content {
            line-height: 1.6;
            font-size: 1.1rem;
            padding: 10px;
        }
        
        /* 优化填空项占位符样式 */
        .blank-placeholder {
            display: inline-block;
            position: relative;
            color: #9b59b6;
            font-weight: 600;
            background: rgba(155, 89, 182, 0.08);
            border-bottom: 2px solid #9b59b6;
            padding: 0 8px;
            border-radius: 4px;
            margin: 0 2px;
        }

        .blank-answer-reveal {
            display: inline-block;
            position: relative;
            color: #2a9d8f;
            font-weight: 600;
            background: rgba(42, 157, 143, 0.08);
            border-bottom: 2px solid #2a9d8f;
            padding: 0 8px;
            border-radius: 4px;
            margin: 0 2px;
        }

        .show-answers-btn {
            margin-top: 15px;
        }
        
        /* 功能说明卡片 */
        .feature-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }
        
        .feature-card {
            background: white;
            border-radius: 12px;
            padding: 20px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
            transition: transform 0.3s ease;
        }
        
        .feature-card:hover {
            transform: translateY(-5px);
        }
        
        .feature-icon {
            width: 60px;
            height: 60px;
            background: #f0f4ff;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-bottom: 15px;
            font-size: 1.5rem;
            color: #4361ee;
        }
        
        .feature-title {
            font-size: 1.2rem;
            margin-bottom: 10px;
            color: #3a0ca3;
        }
        
        /* 拖拽排序样式 */
        .question-list tr.dragging {
            background-color: #f0f7ff;
            opacity: 0.8;
        }
        
        .question-list tr.drag-over {
            border-top: 2px solid #4361ee;
        }
        
        .drag-handle {
            cursor: move;
            padding: 8px;
            color: #6c757d;
            opacity: 0.6;
            transition: all 0.2s;
        }
        
        .drag-handle:hover {
            color: #4361ee;
            opacity: 1;
        }
        
        /* 解答题样式 */
        #essay-section {
            display: none;
            background: #f8f9ff;
            padding: 15px;
            border-radius: 12px;
            border: 1px solid #e1e5eb;
            margin-bottom: 15px;
        }
        
        .keyword-row {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 12px;
            padding: 12px;
            background: white;
            border-radius: 8px;
            border: 1px solid #e1e5eb;
        }
        
        .keyword-row .keyword-number {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            background: #f39c12;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            flex-shrink: 0;
        }
        
        .keyword-input {
            flex: 1;
        }
        
        .keyword-points {
            width: 100px;
        }
        
        .preview-keyword {
            display: flex;
            flex-direction: column;
            gap: 10px;
            background: white;
            border-radius: 8px;
            padding: 15px;
            border: 1px solid #e1e5eb;
            margin-bottom: 10px;
        }
        
        .preview-keyword-header {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .preview-keyword-number {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: #f39c12;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            flex-shrink: 0;
        }
        
        .preview-keyword-content {
            padding-left: 38px;
        }
        
        .keyword-answer {
            background: #fef9e7;
            padding: 5px 10px;
            border-radius: 4px;
            margin-top: 5px;
            display: inline-block;
        }
        
        /* 解答题评分规则 */
        .essay-scoring-mode {
            display: flex;
            gap: 15px;
            margin-bottom: 15px;
        }
        
        /* 解答题分数高亮 */
        .essay-points {
            background: rgba(241, 196, 15, 0.2);
            border: 1px solid #f39c12;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            .actions {
                flex-direction: column;
            }
            
            .btn {
                width: 100%;
            }
            
            .question-list {
                display: block;
                overflow-x: auto;
            }
            
            .preview-options {
                grid-template-columns: 1fr;
            }
            
            .option-row {
                flex-direction: column;
                align-items: flex-start;
            }
            
            .option-actions {
                width: 100%;
                justify-content: space-between;
            }
            
            .import-export-actions {
                flex-direction: column;
            }
            
            .action-group, .filename-group, .encoding-group {
                width: 100%;
                max-width: 100%;
            }
            
            .question-type {
                flex-direction: column;
            }
            
            .truefalse-options {
                flex-direction: column;
            }
            
            .preview-image {
                max-height: 200px;
            }
            
            .image-preview {
                max-height: 150px;
            }
            
            .image-option-preview {
                grid-template-columns: repeat(2, 1fr);
            }
            
            .blank-row, .keyword-row {
                flex-direction: column;
                align-items: stretch;
            }
            
            .blank-points, .keyword-points {
                width: 100%;
            }
            
            .scoring-mode, .essay-scoring-mode {
                flex-direction: column;
            }
            
            .insert-blank-toolbar {
                flex-direction: column;
            }
            
            .insert-blank-btn {
                width: 100%;
                justify-content: center;
            }
            
            /* 移动端按钮优化 */
            .actions-row {
                flex-direction: column;
            }
            
            .action-group {
                min-width: 100%;
                max-width: 100%;
            }
            
            .file-encoding-group {
                flex-direction: column;
                gap: 10px;
            }
            
            .btn-group {
                margin-left: 0;
                width: 100%;
            }
        }
        
        /* 新增布局优化 */
        .file-encoding-group {
            display: flex;
            gap: 15px;
            width: 100%;
        }
        
        /* 导入导出区域优化 */
        .import-export-row {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            align-items: center;
            width: 100%;
            margin-bottom: 15px;
        }
        
        .import-section {
            display: flex;
            gap: 15px;
            align-items: center;
        }
        
        .filename-section {
            flex-grow: 1;
            max-width: 350px;
        }
        
        .export-section {
            display: flex;
            gap: 15px;
            align-items: center;
            margin-left: auto;
        }
        
        /* 优化后的操作区域 */
        .import-export-container {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            align-items: center;
        }
        
        .filename-container {
            flex: 1;
            min-width: 200px;
            max-width: 300px;
        }
        
        .encoding-container {
            min-width: 120px;
            max-width: 140px;
        }
        
        .buttons-container {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            flex: 1;
        }
        
        .action-button {
            flex: 1;
            min-width: 150px;
            height: 48px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0 15px;
        }
        
        /* 题目统计卡片 */
        .stats-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
            gap: 15px;
            margin-top: 20px;
        }
        
        .stat-card {
            background: white;
            border-radius: 12px;
            padding: 15px;
            text-align: center;
            box-shadow: 0 4px 10px rgba(0,0,0,0.05);
            position: relative;
            border-left: 4px solid #4361ee;
        }
        
        .stat-value {
            font-size: 1.8rem;
            font-weight: 700;
            color: #3a0ca3;
            margin: 10px 0;
        }
        
        .stat-label {
            color: #6c757d;
            font-size: 0.9rem;
        }
        
        /* 解答题提示 */
        .essay-hint {
            background: #fff8e6;
            border-left: 4px solid #f39c12;
            padding: 10px 15px;
            border-radius: 0 8px 8px 0;
            margin-bottom: 15px;
            font-size: 0.9rem;
        }
        
        /* 判断题选项样式修复 */
        .truefalse-options {
            display: flex;
            gap: 15px;
            margin-top: 10px;
        }
        
        .truefalse-option {
            flex: 1;
            text-align: center;
            padding: 15px;
            border-radius: 10px;
            background: #f8f9fa;
            cursor: pointer;
            border: 2px solid #e1e5eb;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
        }
        
        .truefalse-option.selected {
            border-color: #4361ee;
            background: #eef2ff;
            box-shadow: 0 5px 15px rgba(67, 97, 238, 0.1);
        }
        
        .truefalse-option:hover {
            border-color: #4361ee;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>题库制作工具</h1>
            <p class="subtitle">支持Excel/CSV导入导出,题目和选项添加图片</p>
        </header>
        
        <div class="card">
            <h2 class="card-title"><i class="fas fa-plus-circle"></i> 添加新题目</h2>
            
            <div class="form-group question-text-editor">
                <label for="question">问题内容 <span style="font-weight:normal;color:#6c757d">(使用 {1}、{2} 等标记填空位置)</span></label>
                <textarea id="question" placeholder="输入问题描述..."></textarea>
                
                <!-- 插入填空项按钮 -->
                <div class="insert-blank-toolbar" id="insert-blank-toolbar">
                    <div class="insert-blank-btn" id="insert-blank-1">
                        <i class="fas fa-underline"></i> 插入填空项 1
                    </div>
                    <div class="insert-blank-btn" id="insert-blank-2">
                        <i class="fas fa-underline"></i> 插入填空项 2
                    </div>
                    <div class="insert-blank-btn" id="insert-blank-3">
                        <i class="fas fa-underline"></i> 插入填空项 3
                    </div>
                </div>
                
                <div class="add-image-btn" id="add-question-image-btn">
                    <i class="fas fa-image"></i> 添加题目图片
                </div>
                <div class="image-container" id="question-image-container">
                    <label class="image-label">
                        <i class="fas fa-link"></i> 图片URL:
                    </label>
                    <input type="text" id="question-image-url" class="image-input" placeholder="输入图片URL">
                    <button class="remove-image-btn" id="remove-question-image-btn">
                        <i class="fas fa-times"></i>
                    </button>
                    <div class="image-preview" id="question-image-preview"></div>
                </div>
                
                <!-- 题目预览区域 -->
                <div class="blank-preview">
                    <div class="blank-preview-title">
                        <i class="fas fa-eye"></i> 题目预览
                    </div>
                    <div class="blank-preview-content" id="question-preview"></div>
                </div>
            </div>
            
            <div class="form-group">
                <label>题目类型</label>
                <div class="question-type">
                    <div class="type-option selected" id="single-type">
                        <i class="fas fa-dot-circle"></i>
                        <h3>单选题</h3>
                        <p>只能选择一个正确答案</p>
                    </div>
                    <div class="type-option" id="multiple-type">
                        <i class="fas fa-check-double"></i>
                        <h3>多选题</h3>
                        <p>可选择一个或多个正确答案</p>
                    </div>
                    <div class="type-option" id="truefalse-type">
                        <i class="fas fa-check-circle"></i>
                        <h3>判断题</h3>
                        <p>判断正确或错误</p>
                    </div>
                    <div class="type-option" id="fillblank-type">
                        <i class="fas fa-pen"></i>
                        <h3>填空题</h3>
                        <p>填写正确答案</p>
                    </div>
                    <div class="type-option" id="essay-type">
                        <i class="fas fa-file-alt"></i>
                        <h3>解答题</h3>
                        <p>详细解答问题</p>
                    </div>
                </div>
            </div>
            
            <div class="form-group">
                <label>题目分数</label>
                <div class="points-input">
                    <span class="points-label">分值:</span>
                    <input type="number" id="question-points" min="1" max="10" value="3">
                    <span class="points-hint" id="points-hint">(1-10分)</span>
                </div>
            </div>
            
            <div class="form-group" id="options-section">
                <label>选项设置</label>
                <div id="options-container">
                    <!-- 选项会动态添加到这里 -->
                </div>
                <button id="add-option-btn" class="btn btn-outline" style="margin-top: 10px;">
                    <i class="fas fa-plus"></i> 添加选项
                </button>
            </div>
            
            <div class="form-group" id="truefalse-section" style="display: none;">
                <label>判断题选项</label>
                <div class="truefalse-options">
                    <div class="truefalse-option" id="true-option" data-value="true">
                        <i class="fas fa-check-circle"></i>
                        <span>正确</span>
                    </div>
                    <div class="truefalse-option" id="false-option" data-value="false">
                        <i class="fas fa-times-circle"></i>
                        <span>错误</span>
                    </div>
                </div>
            </div>
            
            <!-- 填空题设置区域 -->
            <div id="blanks-section" style="display: none;">
                <div class="form-group">
                    <label>评分规则</label>
                    <div class="scoring-mode">
                        <div class="mode-option" id="per-blank-mode">
                            <i class="fas fa-check-square"></i> 按空给分
                        </div>
                        <div class="mode-option selected" id="all-or-nothing-mode">
                            <i class="fas fa-ban"></i> 全对给分
                        </div>
                    </div>
                </div>
                
                <div class="form-group">
                    <label>填空项设置</label>
                    <div id="blanks-container">
                        <!-- 填空项会动态添加到这里 -->
                    </div>
                    <button id="add-blank-btn" class="btn btn-outline" style="margin-top: 10px;">
                        <i class="fas fa-plus"></i> 添加填空项
                    </button>
                </div>
            </div>
            
            <!-- 解答题设置区域 -->
            <div id="essay-section" style="display: none;">
                <div class="essay-hint">
                    <i class="fas fa-info-circle"></i> 解答题可以设置评分关键词(可选),也可以只提供完整答案
                </div>
                
                <!-- 新增:解答题评分规则 -->
                <div class="form-group">
                    <label>评分规则</label>
                    <div class="essay-scoring-mode">
                        <div class="mode-option selected" id="partial-credit-mode">
                            <i class="fas fa-percentage"></i> 按关键词给分
                        </div>
                        <div class="mode-option" id="all-or-nothing-essay-mode">
                            <i class="fas fa-ban"></i> 全对给分
                        </div>
                    </div>
                </div>
                
                <div class="form-group">
                    <label for="essay-answer">完整答案 <span style="font-weight:normal;color:#6c757d">(必填)</span></label>
                    <textarea id="essay-answer" placeholder="输入问题的完整答案..."></textarea>
                </div>
                
                <div class="form-group">
                    <label>评分关键词设置 <span style="font-weight:normal;color:#6c757d">(可选)</span></label>
                    <div id="keywords-container">
                        <!-- 评分关键词会动态添加到这里 -->
                    </div>
                    <button id="add-keyword-btn" class="btn btn-outline" style="margin-top: 10px;">
                        <i class="fas fa-plus"></i> 添加关键词
                    </button>
                </div>
            </div>
            
            <div class="form-group">
                <label for="explanation">答案解析 <span class="hint">(可选)</span></label>
                <textarea id="explanation" placeholder="输入题目解析、解题思路或知识点..."></textarea>
            </div>
            
            <div class="actions">
                <button id="add-question-btn" class="btn btn-primary">
                    <i class="fas fa-save"></i> 保存题目
                </button>
                <button id="preview-btn" class="btn btn-outline">
                    <i class="fas fa-eye"></i> 预览题目
                </button>
                <button id="reset-btn" class="btn btn-outline">
                    <i class="fas fa-redo"></i> 重置表单
                </button>
            </div>
            
            <div id="preview-section" class="preview-card" style="display: none;">
                <div class="preview-title">
                    <i class="fas fa-search"></i> 题目预览
                </div>
                <div id="preview-question-container">
                    <!-- 预览内容会动态生成 -->
                </div>
                <div id="preview-blanks">
                    <!-- 预览内容会动态生成 -->
                </div>
                <div id="preview-keywords">
                    <!-- 预览内容会动态生成 -->
                </div>
                <button id="show-answers-btn" class="btn btn-outline show-answers-btn" style="display: none;">
                    <i class="fas fa-eye"></i> 显示答案
                </button>
                <div id="preview-explanation" style="display: none; margin-top: 20px; padding: 15px; background: #f8f9ff; border-radius: 10px; border-left: 4px solid #4361ee;">
                    <div style="font-weight: 600; color: #4361ee; margin-bottom: 10px; display: flex; align-items: center; gap: 10px;">
                        <i class="fas fa-lightbulb"></i> 答案解析
                    </div>
                    <div id="explanation-content"></div>
                </div>
            </div>
        </div>
        
        <div class="card">
            <h2 class="card-title"><i class="fas fa-list"></i> 题目列表</h2>
            
            <div class="stats-container">
                <div class="stat-card">
                    <div class="stat-value" id="total-count">0</div>
                    <div class="stat-label">题目总数</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value" id="total-points">0</div>
                    <div class="stat-label">总分数</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value" id="image-count">0</div>
                    <div class="stat-label">含图片题目</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value" id="essay-count">0</div>
                    <div class="stat-label">解答题数量</div>
                </div>
            </div>
            
            <div id="questions-table">
                <table class="question-list">
                    <thead>
                        <tr>
                            <th width="5%"></th>
                            <th width="5%">#</th>
                            <th width="20%">问题</th>
                            <th width="20%">选项/关键词</th>
                            <th width="15%">类型</th>
                            <th width="10%">分数</th>
                            <th width="15%">操作</th>
                        </tr>
                    </thead>
                    <tbody id="questions-list">
                        <tr id="empty-row">
                            <td colspan="7" class="empty-state">
                                <i class="fas fa-inbox"></i>
                                <h3>题库为空</h3>
                                <p>请添加题目或导入文件</p>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            
            <div class="counter">
                <div>单选题: <span id="single-count">0</span></div>
                <div>多选题: <span id="multiple-count">0</span></div>
                <div>判断题: <span id="truefalse-count">0</span></div>
                <div>填空题: <span id="fillblank-count">0</span></div>
                <div>解答题: <span id="essay-count2">0</span></div>
            </div>
            
            <!-- 优化后的操作按钮区域 -->
            <div class="import-export-actions">
                <div class="import-export-container">
                    <div class="filename-container">
                        <input type="text" id="export-filename" class="filename-input" placeholder="输入文件名" value="我的题库">
                    </div>
                    
                    <div class="encoding-container">
                        <select id="common-encoding">
                            <option value="utf-8">UTF-8</option>
                            <option value="gbk">GBK</option>
                        </select>
                    </div>
                    
                    <div class="buttons-container">
                        <button id="import-btn" class="btn btn-outline action-button">
                            <i class="fas fa-file-import"></i> 导入题库
                        </button>
                        <button id="export-excel-btn" class="btn btn-success action-button" disabled>
                            <i class="fas fa-file-excel"></i> 导出Excel
                        </button>
                        <button id="export-csv-btn" class="btn btn-success action-button" disabled>
                            <i class="fas fa-file-csv"></i> 导出CSV
                        </button>
                        <button id="clear-all-btn" class="btn btn-danger action-button" disabled>
                            <i class="fas fa-trash"></i> 清空题库
                        </button>
                    </div>
                </div>
                <input type="file" id="import-file" accept=".xlsx, .xls, .csv" style="display:none;">
            </div>
            
            <div class="feature-cards">
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-file-export"></i>
                    </div>
                    <h3 class="feature-title">多种格式支持</h3>
                    <p>支持Excel和CSV格式导入导出,方便与其他系统集成和交换数据。</p>
                </div>
                
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-image"></i>
                    </div>
                    <h3 class="feature-title">图片题目支持</h3>
                    <p>题目和选项均可添加图片,特别适合数学、化学等需要公式和图像的科目。</p>
                </div>
                
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-edit"></i>
                    </div>
                    <h3 class="feature-title">解答题增强</h3>
                    <p>解答题支持完整答案和评分关键词(可选),适用于各种主观题评分场景。</p>
                </div>
            </div>
        </div>
    </div>
    
    <div class="notification" id="notification">
        <i class="fas fa-check-circle"></i>
        <div class="notification-content">
            <h3>操作成功</h3>
            <p id="notification-message">题目已添加到题库</p>
        </div>
    </div>
    
    <script>
        // 全局变量
        let questions = [];
        let optionCounter = 0;
        let blankCounter = 0;
        let keywordCounter = 0;
        let currentType = 'single'; // 默认改为单选题
        let currentPoints = 3;
        let truefalseAnswer = 'true';
        let blankScoringMode = 'allOrNothing';
        let essayScoringMode = 'partialCredit'; // 解答题评分规则(新增)
        let dragSrcEl = null; // 当前拖动的元素
        let dragStartIndex = -1; // 拖动起始索引
        
        // DOM 元素
        const questionInput = document.getElementById('question');
        const essayAnswerInput = document.getElementById('essay-answer');
        const explanationInput = document.getElementById('explanation');
        const pointsInput = document.getElementById('question-points');
        const optionsContainer = document.getElementById('options-container');
        const optionsSection = document.getElementById('options-section');
        const truefalseSection = document.getElementById('truefalse-section');
        const blanksSection = document.getElementById('blanks-section');
        const essaySection = document.getElementById('essay-section');
        const blanksContainer = document.getElementById('blanks-container');
        const keywordsContainer = document.getElementById('keywords-container');
        const addOptionBtn = document.getElementById('add-option-btn');
        const addBlankBtn = document.getElementById('add-blank-btn');
        const addKeywordBtn = document.getElementById('add-keyword-btn');
        const addQuestionBtn = document.getElementById('add-question-btn');
        const previewBtn = document.getElementById('preview-btn');
        const resetBtn = document.getElementById('reset-btn');
        const exportExcelBtn = document.getElementById('export-excel-btn');
        const exportCsvBtn = document.getElementById('export-csv-btn');
        const clearAllBtn = document.getElementById('clear-all-btn');
        const importBtn = document.getElementById('import-btn');
        const importFile = document.getElementById('import-file');
        const commonEncoding = document.getElementById('common-encoding');
        const exportFilename = document.getElementById('export-filename');
        const questionsList = document.getElementById('questions-list');
        const emptyRow = document.getElementById('empty-row');
        const previewSection = document.getElementById('preview-section');
        const previewQuestionContainer = document.getElementById('preview-question-container');
        const previewOptions = document.getElementById('preview-options');
        const previewBlanks = document.getElementById('preview-blanks');
        const previewKeywords = document.getElementById('preview-keywords');
        const previewExplanation = document.getElementById('preview-explanation');
        const explanationContent = document.getElementById('explanation-content');
        const notification = document.getElementById('notification');
        const totalCountEl = document.getElementById('total-count');
        const singleCountEl = document.getElementById('single-count');
        const multipleCountEl = document.getElementById('multiple-count');
        const truefalseCountEl = document.getElementById('truefalse-count');
        const fillblankCountEl = document.getElementById('fillblank-count');
        const essayCountEl = document.getElementById('essay-count');
        const essayCountEl2 = document.getElementById('essay-count2');
        const totalPointsEl = document.getElementById('total-points');
        const imageCountEl = document.getElementById('image-count');
        const singleTypeBtn = document.getElementById('single-type');
        const multipleTypeBtn = document.getElementById('multiple-type');
        const truefalseTypeBtn = document.getElementById('truefalse-type');
        const fillblankTypeBtn = document.getElementById('fillblank-type');
        const essayTypeBtn = document.getElementById('essay-type');
        const trueOption = document.getElementById('true-option');
        const falseOption = document.getElementById('false-option');
        const perBlankModeBtn = document.getElementById('per-blank-mode');
        const allOrNothingModeBtn = document.getElementById('all-or-nothing-mode');
        const partialCreditModeBtn = document.getElementById('partial-credit-mode'); // 新增
        const allOrNothingEssayModeBtn = document.getElementById('all-or-nothing-essay-mode'); // 新增
        const questionImageContainer = document.getElementById('question-image-container');
        const questionImageUrl = document.getElementById('question-image-url');
        const questionImagePreview = document.getElementById('question-image-preview');
        const addQuestionImageBtn = document.getElementById('add-question-image-btn');
        const removeQuestionImageBtn = document.getElementById('remove-question-image-btn');
        const questionPreviewEl = document.getElementById('question-preview');
        const showAnswersBtn = document.getElementById('show-answers-btn');
        const insertBlankToolbar = document.getElementById('insert-blank-toolbar');
        const pointsHint = document.getElementById('points-hint');
        
        // 初始化
        function init() {
            // 添加初始选项(单选题需要两个选项)
            addOption();
            addOption();
            
            // 更新预览
            updateQuestionPreview();
            
            // 事件监听
            addOptionBtn.addEventListener('click', addOption);
            addBlankBtn.addEventListener('click', addBlank);
            addKeywordBtn.addEventListener('click', addKeyword);
            addQuestionBtn.addEventListener('click', addQuestion);
            previewBtn.addEventListener('click', togglePreview);
            resetBtn.addEventListener('click', resetForm);
            exportExcelBtn.addEventListener('click', exportExcel);
            exportCsvBtn.addEventListener('click', exportCSV);
            clearAllBtn.addEventListener('click', clearAllQuestions);
            importBtn.addEventListener('click', () => importFile.click());
            importFile.addEventListener('change', handleFileImport);
            
            // 题目类型切换
            singleTypeBtn.addEventListener('click', () => setQuestionType('single'));
            multipleTypeBtn.addEventListener('click', () => setQuestionType('multiple'));
            truefalseTypeBtn.addEventListener('click', () => setQuestionType('truefalse'));
            fillblankTypeBtn.addEventListener('click', () => setQuestionType('fillblank'));
            essayTypeBtn.addEventListener('click', () => setQuestionType('essay'));
            
            // 判断题选项选择
            trueOption.addEventListener('click', () => selectTrueFalseOption('true'));
            falseOption.addEventListener('click', () => selectTrueFalseOption('false'));
            
            // 填空题评分规则选择
            perBlankModeBtn.addEventListener('click', () => setBlankScoringMode('perBlank'));
            allOrNothingModeBtn.addEventListener('click', () => setBlankScoringMode('allOrNothing'));
            
            // 解答题评分规则选择(新增)
            partialCreditModeBtn.addEventListener('click', () => setEssayScoringMode('partialCredit'));
            allOrNothingEssayModeBtn.addEventListener('click', () => setEssayScoringMode('allOrNothing'));
            
            // 分数输入监听
            pointsInput.addEventListener('change', function() {
                let value = parseInt(this.value);
                if (isNaN(value)) value = 1;
                if (value < 1) value = 1;
                
                // 解答题没有上限,其他题型上限为10分
                if (currentType !== 'essay' && value > 10) {
                    value = 10;
                }
                
                this.value = value;
                currentPoints = value;
            });
            
            // 题目图片URL输入监听
            questionImageUrl.addEventListener('input', function() {
                const url = this.value.trim();
                if (url) {
                    questionImagePreview.innerHTML = `<img src="${url}" alt="题目图片预览">`;
                    questionImagePreview.style.display = 'block';
                } else {
                    questionImagePreview.style.display = 'none';
                }
            });
            
            // 添加题目图片按钮
            addQuestionImageBtn.addEventListener('click', function() {
                questionImageContainer.style.display = 'block';
                this.style.display = 'none';
            });
            
            // 移除题目图片按钮
            removeQuestionImageBtn.addEventListener('click', function() {
                questionImageContainer.style.display = 'none';
                questionImageUrl.value = '';
                questionImagePreview.style.display = 'none';
                addQuestionImageBtn.style.display = 'inline-flex';
            });
            
            // 题目文本输入监听
            questionInput.addEventListener('input', updateQuestionPreview);
            
            // 插入填空项按钮
            document.querySelectorAll('.insert-blank-btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    const blankNum = this.id.split('-')[2];
                    insertBlank(blankNum);
                });
            });
            
            // 显示答案按钮
            showAnswersBtn.addEventListener('click', toggleAnswers);
            
            // 初始渲染题目列表
            renderQuestionList();
            
            // 初始化判断题选项
            selectTrueFalseOption(truefalseAnswer);
        }
        
        // 在题目中插入填空项标记
        function insertBlank(blankNum) {
            const textarea = questionInput;
            const startPos = textarea.selectionStart;
            const endPos = textarea.selectionEnd;
            const text = textarea.value;
            
            // 创建填空标记
            const blankMark = `{${blankNum}}`;
            
            // 插入填空标记
            textarea.value = text.substring(0, startPos) + blankMark + text.substring(endPos);
            
            // 设置光标位置
            textarea.selectionStart = startPos + blankMark.length;
            textarea.selectionEnd = startPos + blankMark.length;
            
            // 更新预览
            updateQuestionPreview();
            
            // 聚焦到文本框
            textarea.focus();
        }
        
        // 更新题目预览
        function updateQuestionPreview() {
            const text = questionInput.value;
            
            // 替换填空标记为带序号的占位符(显示为"1、________")
            const previewText = text.replace(/\{(\d+)\}/g, (match, p1) => {
                return `<span class="blank-placeholder">${p1}、${'________'.repeat(2)}</span>`;
            });
            
            questionPreviewEl.innerHTML = previewText;
        }
        
        // 设置题目类型
        function setQuestionType(type) {
            currentType = type;
            
            // 更新UI
            singleTypeBtn.classList.toggle('selected', type === 'single');
            multipleTypeBtn.classList.toggle('selected', type === 'multiple');
            truefalseTypeBtn.classList.toggle('selected', type === 'truefalse');
            fillblankTypeBtn.classList.toggle('selected', type === 'fillblank');
            essayTypeBtn.classList.toggle('selected', type === 'essay');
            
            // 根据题目类型显示不同的选项区域
            if (type === 'truefalse') {
                optionsSection.style.display = 'none';
                truefalseSection.style.display = 'block';
                blanksSection.style.display = 'none';
                essaySection.style.display = 'none';
                insertBlankToolbar.style.display = 'none';
                
                // 初始化判断题选项
                selectTrueFalseOption(truefalseAnswer);
            } else if (type === 'fillblank') {
                optionsSection.style.display = 'none';
                truefalseSection.style.display = 'none';
                blanksSection.style.display = 'block';
                essaySection.style.display = 'none';
                insertBlankToolbar.style.display = 'flex';
            } else if (type === 'essay') {
                optionsSection.style.display = 'none';
                truefalseSection.style.display = 'none';
                blanksSection.style.display = 'none';
                essaySection.style.display = 'block';
                insertBlankToolbar.style.display = 'none';
            } else {
                optionsSection.style.display = 'block';
                truefalseSection.style.display = 'none';
                blanksSection.style.display = 'none';
                essaySection.style.display = 'none';
                insertBlankToolbar.style.display = 'none';
            }
            
            // 如果是单选题,确保只有一个正确答案
            if (type === 'single') {
                let foundCorrect = false;
                document.querySelectorAll('.option-row input[type="checkbox"]').forEach(checkbox => {
                    if (foundCorrect) {
                        checkbox.checked = false;
                    } else if (checkbox.checked) {
                        foundCorrect = true;
                    }
                });
            }
            
            // 更新分数输入框限制
            if (type === 'essay') {
                pointsInput.removeAttribute('max');
                pointsHint.textContent = '(1分以上)';
                pointsInput.parentElement.classList.add('essay-points');
            } else {
                pointsInput.setAttribute('max', '10');
                pointsHint.textContent = '(1-10分)';
                pointsInput.parentElement.classList.remove('essay-points');
                
                // 如果当前分数大于10,修正为10
                if (parseInt(pointsInput.value) > 10) {
                    pointsInput.value = 10;
                    currentPoints = 10;
                }
            }
        }
        
        // 设置填空题评分规则
        function setBlankScoringMode(mode) {
            blankScoringMode = mode;
            
            // 更新UI
            perBlankModeBtn.classList.toggle('selected', mode === 'perBlank');
            allOrNothingModeBtn.classList.toggle('selected', mode === 'allOrNothing');
            
            // 显示/隐藏每个填空项的分值输入框
            document.querySelectorAll('.blank-points').forEach(input => {
                input.style.display = mode === 'perBlank' ? 'block' : 'none';
            });
        }
        
        // 设置解答题评分规则(新增)
        function setEssayScoringMode(mode) {
            essayScoringMode = mode;
            
            // 更新UI
            partialCreditModeBtn.classList.toggle('selected', mode === 'partialCredit');
            allOrNothingEssayModeBtn.classList.toggle('selected', mode === 'allOrNothing');
        }
        
        // 选择判断题答案
        function selectTrueFalseOption(value) {
            truefalseAnswer = value;
            
            // 更新UI
            trueOption.classList.toggle('selected', value === 'true');
            falseOption.classList.toggle('selected', value === 'false');
        }
        
        // 添加新选项
        function addOption() {
            if (optionCounter >= 6) {
                showNotification('最多只能添加6个选项', 'error');
                return;
            }
            
            const optionId = optionCounter;
            const optionRow = document.createElement('div');
            optionRow.className = 'option-row';
            optionRow.innerHTML = `
                <div class="option-input">
                    <input type="text" id="option-${optionId}" placeholder="选项内容(可选)">
                    <div class="add-image-btn add-option-image-btn" data-id="${optionId}">
                        <i class="fas fa-image"></i> 添加选项图片
                    </div>
                    <div class="option-image-container" id="option-image-container-${optionId}" style="display: none;">
                        <label class="option-image-label">
                            <i class="fas fa-link"></i> 选项图片URL:
                        </label>
                        <input type="text" id="option-image-url-${optionId}" class="image-input" placeholder="输入图片URL">
                        <div class="option-image-preview" id="option-image-preview-${optionId}"></div>
                    </div>
                </div>
                <div class="option-actions">
                    <label class="option-checkbox">
                        <input type="checkbox" id="correct-${optionId}"> 正确答案
                    </label>
                    <button class="action-btn delete-option" data-id="${optionId}">
                        <i class="fas fa-trash"></i>
                    </button>
                </div>
            `;
            
            optionsContainer.appendChild(optionRow);
            
            // 添加事件监听
            const deleteBtn = optionRow.querySelector('.delete-option');
            deleteBtn.addEventListener('click', function() {
                if (optionCounter <= 2) {
                    showNotification('至少需要两个选项', 'error');
                    return;
                }
                
                optionRow.remove();
                optionCounter--;
            });
            
            // 添加选项图片按钮事件
            const addOptionImageBtn = optionRow.querySelector('.add-option-image-btn');
            addOptionImageBtn.addEventListener('click', function() {
                const id = this.getAttribute('data-id');
                const container = document.getElementById(`option-image-container-${id}`);
                container.style.display = 'block';
                this.style.display = 'none';
            });
            
            // 选项图片URL输入监听
            const optionImageUrl = document.getElementById(`option-image-url-${optionId}`);
            const optionImagePreview = document.getElementById(`option-image-preview-${optionId}`);
            
            optionImageUrl.addEventListener('input', function() {
                const url = this.value.trim();
                if (url) {
                    optionImagePreview.innerHTML = `<img src="${url}" alt="选项图片预览">`;
                    optionImagePreview.style.display = 'block';
                } else {
                    optionImagePreview.style.display = 'none';
                }
            });
            
            optionCounter++;
        }
        
        // 添加新填空项
        function addBlank() {
            if (blankCounter >= 6) {
                showNotification('最多只能添加6个填空项', 'error');
                return;
            }
            
            const blankId = blankCounter;
            const blankRow = document.createElement('div');
            blankRow.className = 'blank-row';
            blankRow.innerHTML = `
                <div class="blank-number">${blankCounter + 1}</div>
                <div class="blank-input">
                    <input type="text" id="blank-${blankId}" placeholder="填空项正确答案">
                </div>
                <input type="number" id="blank-points-${blankId}" class="blank-points" min="1" value="1" ${blankScoringMode === 'allOrNothing' ? 'style="display: none;"' : ''}>
                <button class="action-btn delete-blank" data-id="${blankId}">
                    <i class="fas fa-trash"></i>
                </button>
            `;
            
            blanksContainer.appendChild(blankRow);
            
            // 添加事件监听
            const deleteBtn = blankRow.querySelector('.delete-blank');
            deleteBtn.addEventListener('click', function() {
                if (blankCounter <= 1) {
                    showNotification('至少需要一个填空项', 'error');
                    return;
                }
                
                blankRow.remove();
                blankCounter--;
                
                // 更新编号
                document.querySelectorAll('.blank-row').forEach((row, index) => {
                    row.querySelector('.blank-number').textContent = index + 1;
                });
            });
            
            // 分数输入监听 - 移除上限限制
            const pointsInput = document.getElementById(`blank-points-${blankId}`);
            pointsInput.addEventListener('change', function() {
                let value = parseInt(this.value);
                if (isNaN(value)) value = 1;
                if (value < 1) value = 1;
                this.value = value;
            });
            
            blankCounter++;
        }
        
        // 添加评分关键词
        function addKeyword() {
            if (keywordCounter >= 10) {
                showNotification('最多只能添加10个关键词', 'error');
                return;
            }
            
            const keywordId = keywordCounter;
            const keywordRow = document.createElement('div');
            keywordRow.className = 'keyword-row';
            keywordRow.innerHTML = `
                <div class="keyword-number">${keywordCounter + 1}</div>
                <div class="keyword-input">
                    <input type="text" id="keyword-${keywordId}" placeholder="评分关键词">
                </div>
                <input type="number" id="keyword-points-${keywordId}" class="keyword-points" min="1" max="10" value="1">
                <button class="action-btn delete-keyword" data-id="${keywordId}">
                    <i class="fas fa-trash"></i>
                </button>
            `;
            
            keywordsContainer.appendChild(keywordRow);
            
            // 添加事件监听
            const deleteBtn = keywordRow.querySelector('.delete-keyword');
            deleteBtn.addEventListener('click', function() {
                keywordRow.remove();
                keywordCounter--;
                
                // 更新编号
                document.querySelectorAll('.keyword-row').forEach((row, index) => {
                    row.querySelector('.keyword-number').textContent = index + 1;
                });
            });
            
            // 分数输入监听
            const pointsInput = document.getElementById(`keyword-points-${keywordId}`);
            pointsInput.addEventListener('change', function() {
                let value = parseInt(this.value);
                if (isNaN(value)) value = 1;
                if (value < 1) value = 1;
                if (value > 10) value = 10;
                this.value = value;
            });
            
            keywordCounter++;
        }
        
        // 添加新题目
        function addQuestion() {
            const questionText = questionInput.value.trim();
            const essayAnswer = essayAnswerInput.value.trim();
            const explanation = explanationInput.value.trim();
            const questionImage = questionImageUrl.value.trim();
            
            // 验证问题
            if (!questionText) {
                showNotification('请输入问题内容', 'error');
                return;
            }
            
            // 收集选项
            const options = [];
            let correctAnswers = [];
            let hasOptions = false;
            let blanks = [];
            let keywords = [];
            
            if (currentType === 'truefalse') {
                // 判断题特殊处理
                options.push({
                    text: '正确',
                });
                options.push({
                    text: '错误',
                });
                correctAnswers = [truefalseAnswer === 'true' ? 'A' : 'B'];
            } else if (currentType === 'fillblank') {
                // 填空题处理
                document.querySelectorAll('.blank-row').forEach((row, index) => {
                    const blankInput = row.querySelector('input[type="text"]');
                    const blankValue = blankInput ? blankInput.value.trim() : '';
                    const pointsInput = row.querySelector('input[type="number"]');
                    const points = pointsInput ? parseInt(pointsInput.value) : 0;
                    
                    if (blankValue) {
                        hasOptions = true;
                        blanks.push({
                            answer: blankValue,
                            points: points
                        });
                    }
                });
                
                if (blanks.length === 0) {
                    showNotification('请至少输入一个填空项', 'error');
                    return;
                }
            } else if (currentType === 'essay') {
                // 解答题处理
                document.querySelectorAll('.keyword-row').forEach((row, index) => {
                    const keywordInput = row.querySelector('input[type="text"]');
                    const keywordValue = keywordInput ? keywordInput.value.trim() : '';
                    const pointsInput = row.querySelector('input[type="number"]');
                    const points = pointsInput ? parseInt(pointsInput.value) : 0;
                    
                    if (keywordValue) {
                        hasOptions = true;
                        keywords.push({
                            keyword: keywordValue,
                            points: points
                        });
                    }
                });
                
                // 解答题完整答案是必填项
                if (!essayAnswer) {
                    showNotification('请输入完整答案', 'error');
                    return;
                }
            } else {
                // 遍历所有选项行
                document.querySelectorAll('.option-row').forEach((row, index) => {
                    const optionInput = row.querySelector('input[type="text"]');
                    const optionValue = optionInput ? optionInput.value.trim() : '';
                    const correctCheckbox = row.querySelector('input[type="checkbox"]');
                    const optionImageUrl = row.querySelector('.option-image-container input[type="text"]');
                    const optionImage = optionImageUrl ? optionImageUrl.value.trim() : '';
                    
                    if (optionValue || optionImage) {
                        hasOptions = true;
                        options.push({
                            text: optionValue,
                            image: optionImage
                        });
                        
                        if (correctCheckbox && correctCheckbox.checked) {
                            // 正确答案使用字母表示 (A, B, C...)
                            correctAnswers.push(String.fromCharCode(65 + index));
                        }
                    }
                });
                
                if (!hasOptions) {
                    showNotification('请至少输入一个选项或添加选项图片', 'error');
                    return;
                }
                
                if (correctAnswers.length === 0) {
                    showNotification('请至少选择一个正确答案', 'error');
                    return;
                }
                
                // 如果是单选题,但选择了多个答案
                if (currentType === 'single' && correctAnswers.length > 1) {
                    showNotification('单选题只能选择一个正确答案', 'error');
                    return;
                }
            }
            
            // 创建题目对象
            const question = {
                id: Date.now(), // 唯一ID
                text: questionText,
                image: questionImage,
                explanation: explanation,
                type: currentType,
                points: currentPoints,
                options: options,
                correct: correctAnswers,
                blanks: blanks,
                essayAnswer: essayAnswer,
                keywords: keywords,
                blankScoringMode: blankScoringMode,
                essayScoringMode: essayScoringMode // 新增解答题评分规则
            };
            
            // 添加到题库
            questions.push(question);
            
            // 更新UI
            renderQuestionList();
            resetForm();
            showNotification('题目已添加到题库');
            
            // 启用按钮
            exportExcelBtn.disabled = false;
            exportCsvBtn.disabled = false;
            clearAllBtn.disabled = false;
        }
        
        // 渲染题目列表
        function renderQuestionList() {
            // 隐藏空状态
            if (emptyRow) emptyRow.style.display = questions.length ? 'none' : '';
            
            // 清空列表
            questionsList.innerHTML = '';
            
            if (questions.length === 0) {
                questionsList.appendChild(emptyRow);
                emptyRow.style.display = '';
                return;
            }
            
            // 添加题目
            let singleCount = 0;
            let multipleCount = 0;
            let truefalseCount = 0;
            let fillblankCount = 0;
            let essayCount = 0;
            let imageCount = 0;
            let totalPoints = 0;
            
            questions.forEach((q, index) => {
                // 统计题目类型
                if (q.type === 'single') singleCount++;
                else if (q.type === 'multiple') multipleCount++;
                else if (q.type === 'truefalse') truefalseCount++;
                else if (q.type === 'fillblank') fillblankCount++;
                else if (q.type === 'essay') essayCount++;
                
                // 统计题目图片
                if (q.image) imageCount++;
                
                // 统计总分
                totalPoints += q.points;
                
                const row = document.createElement('tr');
                row.setAttribute('data-id', q.id);
                row.setAttribute('data-index', index);
                row.draggable = true; // 启用拖拽
                
                if (index === questions.length - 1) {
                    row.classList.add('highlight');
                }
                
                // 生成选项预览
                let optionsHtml = '';
                
                if (q.type === 'fillblank') {
                    // 填空题预览
                    optionsHtml = `<div class="options-preview">`;
                    q.blanks.forEach((blank, idx) => {
                        optionsHtml += `
                            <div class="option-tag">
                                ${idx+1}. ${blank.answer}
                            </div>
                        `;
                    });
                    optionsHtml += `</div>`;
                } else if (q.type === 'truefalse') {
                    // 判断题特殊显示
                    q.options.forEach((opt, optIndex) => {
                        const isCorrect = q.correct.includes(String.fromCharCode(65 + optIndex));
                        optionsHtml += `
                            <div class="option-tag ${isCorrect ? 'correct' : ''}">
                                ${opt.text} ${isCorrect ? '<i class="fas fa-check"></i>' : ''}
                            </div>
                        `;
                    });
                } else if (q.type === 'essay') {
                    // 解答题关键词预览
                    if (q.keywords && q.keywords.length > 0) {
                        optionsHtml = `<div class="options-preview">`;
                        q.keywords.forEach((kw, idx) => {
                            optionsHtml += `
                                <div class="option-tag">
                                    ${kw.keyword} (${kw.points}分)
                                </div>
                            `;
                        });
                        optionsHtml += `</div>`;
                    } else {
                        optionsHtml = `<div class="option-tag">无关键词</div>`;
                    }
                } else {
                    // 选择题预览
                    q.options.forEach((opt, optIndex) => {
                        const isCorrect = q.correct.includes(String.fromCharCode(65 + optIndex));
                        
                        let optionContent = `
                            <div class="option-tag ${isCorrect ? 'correct' : ''}">
                        `;
                        
                        if (opt.image) {
                            optionContent += `
                                <div class="image-option-preview-item">
                                    <img src="${opt.image}" alt="选项图片">
                                    <div class="image-option-preview-label">${opt.text || '图片选项'}</div>
                                </div>
                            `;
                        } else {
                            optionContent += `
                                ${String.fromCharCode(65 + optIndex)}: ${opt.text || ''}
                                ${isCorrect ? '<i class="fas fa-check"></i>' : ''}
                            `;
                        }
                        
                        optionContent += `</div>`;
                        optionsHtml += optionContent;
                    });
                }
                
                // 题目类型显示
                let typeBadge = '';
                if (q.type === 'single') {
                    typeBadge = '<span class="badge badge-single">单选题</span>';
                } else if (q.type === 'multiple') {
                    typeBadge = '<span class="badge badge-multiple">多选题</span>';
                } else if (q.type === 'truefalse') {
                    typeBadge = '<span class="badge badge-truefalse">判断题</span>';
                } else if (q.type === 'fillblank') {
                    typeBadge = '<span class="badge badge-fillblank">填空题</span>';
                } else if (q.type === 'essay') {
                    typeBadge = '<span class="badge badge-essay">解答题</span>';
                }
                
                // 问题内容显示(含图片)
                let questionContent = '';
                if (q.type === 'fillblank') {
                    // 对于填空题,替换填空标记为占位符(显示为"1、________")
                    const previewText = q.text.replace(/\{(\d+)\}/g, (match, p1) => {
                        return `<span class="blank-placeholder">${p1}、${'________'.repeat(2)}</span>`;
                    });
                    questionContent = `<div>${previewText}</div>`;
                } else {
                    questionContent = `<div class="question-text">${q.text}</div>`;
                }
                
                if (q.image) {
                    questionContent = `
                        <div class="question-text-with-image">
                            ${questionContent}
                            <img src="${q.image}" alt="题目图片" style="max-width: 100px; max-height: 60px;">
                        </div>
                    `;
                }
                
                row.innerHTML = `
                    <td class="drag-handle" title="拖动排序"><i class="fas fa-grip-vertical"></i></td>
                    <td>${index + 1}</td>
                    <td class="question-text">${questionContent}</td>
                    <td>
                        ${optionsHtml}
                    </td>
                    <td>
                        ${typeBadge}
                    </td>
                    <td>
                        <span class="badge badge-points ${q.type === 'essay' ? 'essay-points' : ''}">${q.points}分</span>
                    </td>
                    <td>
                        <div class="list-actions">
                            <button class="action-btn edit-btn" data-id="${q.id}">
                                <i class="fas fa-edit"></i>
                            </button>
                            <button class="action-btn delete-btn" data-id="${q.id}">
                                <i class="fas fa-trash"></i>
                            </button>
                        </div>
                    </td>
                `;
                
                questionsList.appendChild(row);
            });
            
            // 添加事件监听
            document.querySelectorAll('.edit-btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    const id = this.getAttribute('data-id');
                    editQuestion(id);
                });
            });
            
            document.querySelectorAll('.delete-btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    const id = this.getAttribute('data-id');
                    deleteQuestion(id);
                });
            });
            
            // 添加拖拽事件监听
            setupDragAndDrop();
            
            // 更新计数
            totalCountEl.textContent = questions.length;
            singleCountEl.textContent = singleCount;
            multipleCountEl.textContent = multipleCount;
            truefalseCountEl.textContent = truefalseCount;
            fillblankCountEl.textContent = fillblankCount;
            essayCountEl.textContent = essayCount;
            essayCountEl2.textContent = essayCount;
            totalPointsEl.textContent = totalPoints;
            imageCountEl.textContent = imageCount;
        }
        
        // 设置拖拽排序功能
        function setupDragAndDrop() {
            const rows = document.querySelectorAll('#questions-list tr:not(.empty-state)');
            
            rows.forEach(row => {
                row.addEventListener('dragstart', handleDragStart);
                row.addEventListener('dragover', handleDragOver);
                row.addEventListener('dragenter', handleDragEnter);
                row.addEventListener('dragleave', handleDragLeave);
                row.addEventListener('drop', handleDrop);
                row.addEventListener('dragend', handleDragEnd);
            });
        }
        
        // 拖拽开始
        function handleDragStart(e) {
            dragSrcEl = this;
            dragStartIndex = parseInt(this.getAttribute('data-index'));
            this.classList.add('dragging');
            
            // 设置拖拽效果
            e.dataTransfer.effectAllowed = 'move';
            e.dataTransfer.setData('text/html', this.outerHTML);
        }
        
        // 拖拽经过
        function handleDragOver(e) {
            if (e.preventDefault) {
                e.preventDefault(); // 允许放置
            }
            
            e.dataTransfer.dropEffect = 'move';
            return false;
        }
        
        // 拖拽进入
        function handleDragEnter(e) {
            this.classList.add('drag-over');
        }
        
        // 拖拽离开
        function handleDragLeave(e) {
            this.classList.remove('drag-over');
        }
        
        // 放置
        function handleDrop(e) {
            e.stopPropagation(); // 阻止冒泡
            e.preventDefault();
            
            if (dragSrcEl !== this) {
                const dragEndIndex = parseInt(this.getAttribute('data-index'));
                
                // 交换数组中的元素
                [questions[dragStartIndex], questions[dragEndIndex]] = 
                [questions[dragEndIndex], questions[dragStartIndex]];
                
                // 重新渲染题目列表
                renderQuestionList();
            }
            
            return false;
        }
        
        // 拖拽结束
        function handleDragEnd(e) {
            // 移除所有行的拖拽样式
            document.querySelectorAll('#questions-list tr').forEach(row => {
                row.classList.remove('dragging');
                row.classList.remove('drag-over');
            });
        }
        
        // 编辑题目
        function editQuestion(id) {
            const question = questions.find(q => q.id == id);
            if (!question) return;
            
            // 填充表单
            questionInput.value = question.text;
            essayAnswerInput.value = question.essayAnswer || '';
            explanationInput.value = question.explanation || '';
            pointsInput.value = question.points;
            currentPoints = question.points;
            
            // 设置题目图片
            if (question.image) {
                questionImageUrl.value = question.image;
                questionImagePreview.innerHTML = `<img src="${question.image}" alt="题目图片预览">`;
                questionImagePreview.style.display = 'block';
                questionImageContainer.style.display = 'block';
                addQuestionImageBtn.style.display = 'none';
            }
            
            // 设置题目类型
            setQuestionType(question.type);
            
            // 更新预览
            updateQuestionPreview();
            
            // 判断题特殊处理
            if (question.type === 'truefalse') {
                // 设置判断题答案
                const answer = question.correct[0];
                truefalseAnswer = answer === 'A' ? 'true' : 'false';
                selectTrueFalseOption(truefalseAnswer);
            } else if (question.type === 'fillblank') {
                // 设置填空题
                setBlankScoringMode(question.blankScoringMode || 'allOrNothing');
                
                // 清空填空项
                blanksContainer.innerHTML = '';
                blankCounter = 0;
                
                // 添加填空项
                question.blanks.forEach(blank => {
                    addBlank();
                    
                    const blankInput = document.getElementById(`blank-${blankCounter - 1}`);
                    const pointsInput = document.getElementById(`blank-points-${blankCounter - 1}`);
                    
                    if (blankInput) {
                        blankInput.value = blank.answer || '';
                        
                        if (pointsInput) {
                            pointsInput.value = blank.points || 1;
                        }
                    }
                });
            } else if (question.type === 'essay') {
                // 设置解答题
                setEssayScoringMode(question.essayScoringMode || 'partialCredit');
                
                // 清空关键词
                keywordsContainer.innerHTML = '';
                keywordCounter = 0;
                
                // 添加关键词
                question.keywords.forEach(kw => {
                    addKeyword();
                    
                    const keywordInput = document.getElementById(`keyword-${keywordCounter - 1}`);
                    const pointsInput = document.getElementById(`keyword-points-${keywordCounter - 1}`);
                    
                    if (keywordInput) {
                        keywordInput.value = kw.keyword || '';
                        
                        if (pointsInput) {
                            pointsInput.value = kw.points || 1;
                        }
                    }
                });
            } else {
                // 清空选项
                optionsContainer.innerHTML = '';
                optionCounter = 0;
                
                // 添加选项
                question.options.forEach((opt, index) => {
                    addOption();
                    
                    const optionInput = document.getElementById(`option-${optionCounter - 1}`);
                    const correctCheckbox = document.getElementById(`correct-${optionCounter - 1}`);
                    const optionImageInput = document.getElementById(`option-image-url-${optionCounter - 1}`);
                    const optionImagePreview = document.getElementById(`option-image-preview-${optionCounter - 1}`);
                    
                    if (optionInput) {
                        optionInput.value = opt.text || '';
                        
                        // 设置选项图片
                        if (opt.image) {
                            optionImageInput.value = opt.image;
                            optionImagePreview.innerHTML = `<img src="${opt.image}" alt="选项图片预览">`;
                            optionImagePreview.style.display = 'block';
                            document.getElementById(`option-image-container-${optionCounter - 1}`).style.display = 'block';
                            document.querySelector(`[data-id="${optionCounter - 1}"].add-option-image-btn`).style.display = 'none';
                        }
                        
                        // 设置正确答案
                        const isCorrect = question.correct.includes(String.fromCharCode(65 + index));
                        if (correctCheckbox) {
                            correctCheckbox.checked = isCorrect;
                        }
                    }
                });
            }
            
            // 删除原始题目
            deleteQuestion(id);
            
            // 滚动到顶部
            window.scrollTo(0, 0);
        }
        
        // 删除题目
        function deleteQuestion(id) {
            questions = questions.filter(q => q.id != id);
            renderQuestionList();
            
            if (questions.length === 0) {
                if (emptyRow) emptyRow.style.display = '';
                exportExcelBtn.disabled = true;
                exportCsvBtn.disabled = true;
                clearAllBtn.disabled = true;
            }
        }
        
        // 重置表单
        function resetForm() {
            questionInput.value = '';
            essayAnswerInput.value = '';
            explanationInput.value = '';
            optionsContainer.innerHTML = '';
            blanksContainer.innerHTML = '';
            keywordsContainer.innerHTML = '';
            optionCounter = 0;
            blankCounter = 0;
            keywordCounter = 0;
            previewSection.style.display = 'none';
            currentPoints = 1;
            pointsInput.value = 1;
            setQuestionType('single');
            truefalseAnswer = 'true';
            selectTrueFalseOption('true');
            setBlankScoringMode('allOrNothing');
            setEssayScoringMode('partialCredit'); // 重置为按关键词给分
            
            // 重置题目图片
            questionImageUrl.value = '';
            questionImagePreview.style.display = 'none';
            questionImageContainer.style.display = 'none';
            addQuestionImageBtn.style.display = 'inline-flex';
            
            // 更新预览
            updateQuestionPreview();
            
            // 重新添加两个选项(单选题)
            addOption();
            addOption();
        }
        
        // 切换预览
        function togglePreview() {
            const questionText = questionInput.value.trim();
            const essayAnswer = essayAnswerInput.value.trim();
            const explanation = explanationInput.value.trim();
            const questionImage = questionImageUrl.value.trim();
            
            if (!questionText) {
                showNotification('请输入问题内容', 'error');
                return;
            }
            
            // 收集选项
            const options = [];
            let correctAnswers = [];
            let blanks = [];
            let keywords = [];
            
            if (currentType === 'truefalse') {
                // 判断题特殊处理
                options.push({
                    text: '正确',
                });
                options.push({
                    text: '错误',
                });
                correctAnswers = [truefalseAnswer === 'true' ? 'A' : 'B'];
            } else if (currentType === 'fillblank') {
                // 填空题处理
                document.querySelectorAll('.blank-row').forEach((row, index) => {
                    const blankInput = row.querySelector('input[type="text"]');
                    const blankValue = blankInput ? blankInput.value.trim() : '';
                    const pointsInput = row.querySelector('input[type="number"]');
                    const points = pointsInput ? parseInt(pointsInput.value) : 0;
                    
                    if (blankValue) {
                        blanks.push({
                            answer: blankValue,
                            points: points,
                            index: index + 1
                        });
                    }
                });
                
                if (blanks.length === 0) {
                    showNotification('请至少输入一个填空项', 'error');
                    return;
                }
            } else if (currentType === 'essay') {
                // 解答题处理
                document.querySelectorAll('.keyword-row').forEach((row, index) => {
                    const keywordInput = row.querySelector('input[type="text"]');
                    const keywordValue = keywordInput ? keywordInput.value.trim() : '';
                    const pointsInput = row.querySelector('input[type="number"]');
                    const points = pointsInput ? parseInt(pointsInput.value) : 0;
                    
                    if (keywordValue) {
                        keywords.push({
                            keyword: keywordValue,
                            points: points,
                            index: index + 1
                        });
                    }
                });
                
                if (!essayAnswer) {
                    showNotification('请输入完整答案', 'error');
                    return;
                }
            } else {
                let hasOptions = false;
                
                // 遍历所有选项行
                document.querySelectorAll('.option-row').forEach((row, index) => {
                    const optionInput = row.querySelector('input[type="text"]');
                    const optionValue = optionInput ? optionInput.value.trim() : '';
                    const correctCheckbox = row.querySelector('input[type="checkbox"]');
                    const optionImageUrl = row.querySelector('.option-image-container input[type="text"]');
                    const optionImage = optionImageUrl ? optionImageUrl.value.trim() : '';
                    
                    if (optionValue || optionImage) {
                        hasOptions = true;
                        options.push({
                            text: optionValue,
                            image: optionImage
                        });
                        
                        if (correctCheckbox && correctCheckbox.checked) {
                            correctAnswers.push(index);
                        }
                    }
                });
                
                if (!hasOptions) {
                    showNotification('请至少输入一个选项或添加选项图片', 'error');
                    return;
                }
                
                if (correctAnswers.length === 0) {
                    showNotification('请至少选择一个正确答案', 'error');
                    return;
                }
                
                // 如果是单选题,但选择了多个答案
                if (currentType === 'single' && correctAnswers.length > 1) {
                    showNotification('单选题只能选择一个正确答案', 'error');
                    return;
                }
            }
            
            // 更新预览
            previewQuestionContainer.innerHTML = '';
            previewBlanks.innerHTML = '';
            previewKeywords.innerHTML = '';
            previewExplanation.style.display = 'none';
            showAnswersBtn.style.display = 'none';
            
            // 预览题目类型和分数
            const typeInfo = document.createElement('div');
            typeInfo.style.marginBottom = '15px';
            typeInfo.style.display = 'flex';
            typeInfo.style.gap = '15px';
            
            let typeBadge = '';
            if (currentType === 'single') {
                typeBadge = '<span class="badge badge-single">单选题</span>';
            } else if (currentType === 'multiple') {
                typeBadge = '<span class="badge badge-multiple">多选题</span>';
            } else if (currentType === 'truefalse') {
                typeBadge = '<span class="badge badge-truefalse">判断题</span>';
            } else if (currentType === 'fillblank') {
                typeBadge = '<span class="badge badge-fillblank">填空题</span>';
            } else if (currentType === 'essay') {
                typeBadge = '<span class="badge badge-essay">解答题</span>';
            }
            
            let scoringInfo = '';
            if (currentType === 'fillblank') {
                scoringInfo = blankScoringMode === 'perBlank' 
                    ? '<span class="badge" style="background: rgba(46, 204, 113, 0.15); color: #2ecc71;">按空给分</span>' 
                    : '<span class="badge" style="background: rgba(231, 76, 60, 0.15); color: #e74c3c;">全对给分</span>';
            } else if (currentType === 'essay') {
                scoringInfo = essayScoringMode === 'partialCredit' 
                    ? '<span class="badge" style="background: rgba(46, 204, 113, 0.15); color: #2ecc71;">按关键词给分</span>' 
                    : '<span class="badge" style="background: rgba(231, 76, 60, 0.15); color: #e74c3c;">全对给分</span>';
            }
            
            typeInfo.innerHTML = `
                ${typeBadge}
                ${scoringInfo}
                <span class="badge badge-points ${currentType === 'essay' ? 'essay-points' : ''}">${currentPoints}分</span>
            `;
            
            // 预览问题
            const questionPreview = document.createElement('div');
            questionPreview.className = 'preview-question';
            
            if (currentType === 'fillblank') {
                // 对于填空题,替换填空标记为占位符(显示为"1、________")
                const previewText = questionText.replace(/\{(\d+)\}/g, (match, p1) => {
                    return `<span class="blank-placeholder">${p1}、${'________'.repeat(2)}</span>`;
                });
                questionPreview.innerHTML = previewText;
            } else {
                questionPreview.textContent = questionText;
            }
            
            previewQuestionContainer.appendChild(typeInfo);
            previewQuestionContainer.appendChild(questionPreview);
            
            // 预览题目图片
            if (questionImage) {
                const imagePreview = document.createElement('img');
                imagePreview.src = questionImage;
                imagePreview.alt = '题目图片预览';
                imagePreview.className = 'preview-image';
                previewQuestionContainer.appendChild(imagePreview);
            }
            
            // 预览选项
            if (currentType === 'fillblank') {
                previewBlanks.style.display = 'block';
                showAnswersBtn.style.display = 'block';
                showAnswersBtn.innerHTML = '<i class="fas fa-eye"></i> 显示答案';
                
                blanks.forEach((blank, index) => {
                    const blankEl = document.createElement('div');
                    blankEl.className = 'preview-blank';
                    blankEl.innerHTML = `
                        <div class="preview-blank-header">
                            <div class="preview-blank-number">${index + 1}</div>
                            <div>填空项 ${index + 1}</div>
                        </div>
                        <div class="preview-blank-content">
                            <div>正确答案: <span class="blank-answer">${blank.answer}</span></div>
                            ${blankScoringMode === 'perBlank' ? `<div>分值: ${blank.points}分</div>` : ''}
                        </div>
                    `;
                    previewBlanks.appendChild(blankEl);
                });
            } else if (currentType === 'essay') {
                // 解答题预览
                previewKeywords.style.display = 'block';
                
                // 预览完整答案
                const answerPreview = document.createElement('div');
                answerPreview.className = 'preview-card';
                answerPreview.innerHTML = `
                    <div class="preview-title">
                        <i class="fas fa-file-alt"></i> 完整答案
                    </div>
                    <div style="margin-top: 15px; padding: 15px; background: #fffaf0; border-radius: 8px; border: 1px solid #ffeeba;">
                        ${essayAnswer.replace(/\n/g, '<br>')}
                    </div>
                `;
                previewQuestionContainer.appendChild(answerPreview);
                
                // 预览评分关键词
                if (keywords.length > 0) {
                    const keywordsPreview = document.createElement('div');
                    keywordsPreview.className = 'preview-card';
                    keywordsPreview.innerHTML = `
                        <div class="preview-title">
                            <i class="fas fa-key"></i> 评分关键词
                        </div>
                        <div id="keywords-preview-list" style="margin-top: 15px;"></div>
                    `;
                    previewQuestionContainer.appendChild(keywordsPreview);
                    
                    const keywordsList = keywordsPreview.querySelector('#keywords-preview-list');
                    
                    keywords.forEach((kw, index) => {
                        const keywordEl = document.createElement('div');
                        keywordEl.className = 'preview-keyword';
                        keywordEl.innerHTML = `
                            <div class="preview-keyword-header">
                                <div class="preview-keyword-number">${index + 1}</div>
                                <div>关键词 ${index + 1}</div>
                            </div>
                            <div class="preview-keyword-content">
                                <div>关键词: <span class="keyword-answer">${kw.keyword}</span></div>
                                <div>分值: ${kw.points}分</div>
                            </div>
                        `;
                        keywordsList.appendChild(keywordEl);
                    });
                }
            } else {
                previewBlanks.style.display = 'none';
                const optionsContainer = document.createElement('div');
                optionsContainer.className = 'preview-options';
                previewQuestionContainer.appendChild(optionsContainer);
                
                options.forEach((opt, index) => {
                    const isCorrect = correctAnswers.includes(index);
                    
                    if (currentType === 'truefalse') {
                        // 判断题特殊显示
                        const optionEl = document.createElement('div');
                        optionEl.className = `preview-option ${isCorrect ? 'correct' : ''}`;
                        optionEl.innerHTML = `
                            <div class="option-letter">${index === 0 ? '√' : '×'}</div>
                            <div>${opt.text}</div>
                        `;
                        optionsContainer.appendChild(optionEl);
                    } else {
                        // 图片选项显示
                        const optionEl = document.createElement('div');
                        optionEl.className = `image-option ${isCorrect ? 'correct' : ''}`;
                        
                        let content = `
                            <div class="option-letter">${String.fromCharCode(65 + index)}</div>
                        `;
                        
                        if (opt.image) {
                            content += `
                                <img src="${opt.image}" alt="选项图片" class="option-image">
                            `;
                        }
                        
                        if (opt.text) {
                            content += `
                                <div class="option-image-label">${opt.text}</div>
                            `;
                        }
                        
                        optionEl.innerHTML = content;
                        optionsContainer.appendChild(optionEl);
                    }
                });
            }
            
            // 预览答案解析
            if (explanation) {
                explanationContent.textContent = explanation;
                previewExplanation.style.display = 'block';
            }
            
            previewSection.style.display = 'block';
        }
        
        // 切换答案显示
        function toggleAnswers() {
            const questionText = questionInput.value.trim();
            const blanks = [];
            
            // 收集填空项
            document.querySelectorAll('.blank-row').forEach((row, index) => {
                const blankInput = row.querySelector('input[type="text"]');
                const blankValue = blankInput ? blankInput.value.trim() : '';
                
                if (blankValue) {
                    blanks.push({
                        answer: blankValue,
                        index: index + 1
                    });
                }
            });
            
            const questionPreview = previewQuestionContainer.querySelector('.preview-question');
            
            if (showAnswersBtn.textContent.includes('显示')) {
                // 显示答案
                const previewText = questionText.replace(/\{(\d+)\}/g, (match, p1) => {
                    const index = parseInt(p1);
                    const blank = blanks.find(b => b.index === index);
                    if (blank) {
                        return `<span class="blank-answer-reveal">${blank.answer}</span>`;
                    }
                    return match;
                });
                questionPreview.innerHTML = previewText;
                showAnswersBtn.innerHTML = '<i class="fas fa-eye-slash"></i> 隐藏答案';
            } else {
                // 隐藏答案
                const previewText = questionText.replace(/\{(\d+)\}/g, (match, p1) => {
                    return `<span class="blank-placeholder">${p1}、${'________'.repeat(2)}</span>`;
                });
                questionPreview.innerHTML = previewText;
                showAnswersBtn.innerHTML = '<i class="fas fa-eye"></i> 显示答案';
            }
        }
        
        // 清空所有题目
        function clearAllQuestions() {
            if (!confirm('确定要清空所有题目吗?此操作不可恢复。')) return;
            
            questions = [];
            renderQuestionList();
            if (emptyRow) emptyRow.style.display = '';
            exportExcelBtn.disabled = true;
            exportCsvBtn.disabled = true;
            clearAllBtn.disabled = true;
            showNotification('已清空题库');
        }
        
        // 导出Excel
        function exportExcel() {
            if (questions.length === 0) {
                showNotification('题库为空,无法导出', 'error');
                return;
            }
            
            // 创建工作簿
            const wb = XLSX.utils.book_new();
            wb.SheetNames.push("题库");
            
            // 准备数据
            const data = [
                // 标题行
                ["问题", "问题图片", "选项A", "选项A图片", "选项B", "选项B图片", "选项C", "选项C图片", "选项D", "选项D图片", "选项E", "选项E图片", "选项F", "选项F图片", "答案", "题目类型", "题目分数", "答案解析", "填空项1", "填空项1分值", "填空项2", "填空项2分值", "填空项3", "填空项3分值", "填空项4", "填空项4分值", "填空项5", "填空项5分值", "填空项6", "填空项6分值", "完整答案", "关键词1", "关键词1分值", "关键词2", "关键词2分值", "关键词3", "关键词3分值", "关键词4", "关键词4分值", "关键词5", "关键词5分值", "评分规则"]
            ];
            
            questions.forEach(q => {
                // 添加问题
                const row = [q.text || "", q.image || ""];
                
                // 添加选项(最多6个)
                for (let i = 0; i < 6; i++) {
                    if (i < q.options.length) {
                        // 选项文本
                        const text = q.options[i].text || "";
                        row.push(text);
                        
                        // 选项图片
                        const image = q.options[i].image || "";
                        row.push(image);
                    } else {
                        // 空选项(文本和图片)
                        row.push("");
                        row.push("");
                    }
                }
                
                // 添加答案
                row.push(q.correct.join(''));
                
                // 添加题目类型
                row.push(q.type);
                
                // 添加题目分数
                row.push(q.points);
                
                // 添加答案解析
                row.push(q.explanation || "");
                
                // 添加填空项(最多6个)
                for (let i = 0; i < 6; i++) {
                    if (i < (q.blanks ? q.blanks.length : 0)) {
                        // 填空项答案
                        const answer = q.blanks[i].answer || "";
                        row.push(answer);
                        
                        // 填空项分值
                        const points = q.blanks[i].points || "";
                        row.push(points);
                    } else {
                        // 空填空项(答案和分值)
                        row.push("");
                        row.push("");
                    }
                }
                
                // 添加完整答案(解答题)
                row.push(q.type === 'essay' ? q.essayAnswer || "" : "");
                
                // 添加关键词(最多5个)
                for (let i = 0; i < 5; i++) {
                    if (i < (q.keywords ? q.keywords.length : 0)) {
                        // 关键词
                        const keyword = q.keywords[i].keyword || "";
                        row.push(keyword);
                        
                        // 关键词分值
                        const points = q.keywords[i].points || "";
                        row.push(points);
                    } else {
                        // 空关键词(关键词和分值)
                        row.push("");
                        row.push("");
                    }
                }
                
                // 添加评分规则(修改:解答题使用partialCredit)
                const scoringMode = q.type === 'essay' ? 
                    (q.essayScoringMode || 'partialCredit') : 
                    (q.blankScoringMode || "");
                row.push(scoringMode);
                
                data.push(row);
            });
            
            // 创建工作表
            const ws = XLSX.utils.aoa_to_sheet(data);
            wb.Sheets["题库"] = ws;
            
            // 获取文件名
            let filename = exportFilename.value.trim();
            if (!filename) {
                filename = `题库_${new Date().toLocaleDateString()}`;
            } else {
                // 移除可能存在的.xlsx扩展名
                if (filename.toLowerCase().endsWith('.xlsx')) {
                    filename = filename.substring(0, filename.length - 5);
                }
            }
            filename += '.xlsx';
            
            // 导出Excel文件
            XLSX.writeFile(wb, filename);
            
            showNotification(`Excel文件已导出: ${filename}`);
        }
        
        // 导出CSV
        function exportCSV() {
            if (questions.length === 0) {
                showNotification('题库为空,无法导出', 'error');
                return;
            }
            
            // 创建CSV内容
            let csvContent = '问题,问题图片,选项A,选项A图片,选项B,选项B图片,选项C,选项C图片,选项D,选项D图片,选项E,选项E图片,选项F,选项F图片,答案,题目类型,题目分数,答案解析,填空项1,填空项1分值,填空项2,填空项2分值,填空项3,填空项3分值,填空项4,填空项4分值,填空项5,填空项5分值,填空项6,填空项6分值,完整答案,关键词1,关键词1分值,关键词2,关键词2分值,关键词3,关键词3分值,关键词4,关键词4分值,关键词5,关键词5分值,评分规则\n';
            
            questions.forEach(q => {
                // 添加问题
                csvContent += `"${q.text.replace(/"/g, '""')}",`;
                
                // 添加问题图片
                csvContent += `"${q.image ? q.image.replace(/"/g, '""') : ''}",`;
                
                // 添加选项(最多6个)
                for (let i = 0; i < 6; i++) {
                    if (i < q.options.length) {
                        // 选项文本
                        const text = q.options[i].text || '';
                        csvContent += `"${text.replace(/"/g, '""')}",`;
                        
                        // 选项图片
                        const image = q.options[i].image || '';
                        csvContent += `"${image.replace(/"/g, '""')}",`;
                    } else {
                        // 空选项(文本和图片)
                        csvContent += ',';
                        csvContent += ',';
                    }
                }
                
                // 添加答案
                csvContent += `${q.correct.join('')},`;
                
                // 添加题目类型
                csvContent += `${q.type},`;
                
                // 添加题目分数
                csvContent += `${q.points},`;
                
                // 添加答案解析
                csvContent += `"${q.explanation ? q.explanation.replace(/"/g, '""') : ''}",`;
                
                // 添加填空项(最多6个)
                for (let i = 0; i < 6; i++) {
                    if (i < (q.blanks ? q.blanks.length : 0)) {
                        // 填空项答案
                        const answer = q.blanks[i].answer || '';
                        csvContent += `"${answer.replace(/"/g, '""')}",`;
                        
                        // 填空项分值
                        const points = q.blanks[i].points || '';
                        csvContent += `${points},`;
                    } else {
                        // 空填空项(答案和分值)
                        csvContent += ',';
                        csvContent += ',';
                    }
                }
                
                // 添加完整答案(解答题)
                csvContent += `"${q.type === 'essay' ? (q.essayAnswer || '').replace(/"/g, '""') : ''}",`;
                
                // 添加关键词(最多5个)
                for (let i = 0; i < 5; i++) {
                    if (i < (q.keywords ? q.keywords.length : 0)) {
                        // 关键词
                        const keyword = q.keywords[i].keyword || '';
                        csvContent += `"${keyword.replace(/"/g, '""')}",`;
                        
                        // 关键词分值
                        const points = q.keywords[i].points || '';
                        csvContent += `${points},`;
                    } else {
                        // 空关键词(关键词和分值)
                        csvContent += ',';
                        csvContent += ',';
                    }
                }
                
                // 添加评分规则(修改:解答题使用partialCredit)
                const scoringMode = q.type === 'essay' ? 
                    (q.essayScoringMode || 'partialCredit') : 
                    (q.blankScoringMode || '');
                csvContent += `${scoringMode}\n`;
            });
            
            // 获取选择的编码格式
            const encoding = commonEncoding.value;
            
            // 获取文件名
            let filename = exportFilename.value.trim();
            if (!filename) {
                filename = `题库_${new Date().toLocaleDateString()}`;
            } else {
                // 移除可能存在的.csv扩展名
                if (filename.toLowerCase().endsWith('.csv')) {
                    filename = filename.substring(0, filename.length - 4);
                }
            }
            filename += '.csv';
            
            // 创建Blob对象
            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.setAttribute('href', url);
            link.setAttribute('download', filename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            
            showNotification(`CSV文件已导出: ${filename}`);
        }
        
        // 处理文件导入
        function handleFileImport(e) {
            const file = e.target.files[0];
            if (!file) return;
            
            const reader = new FileReader();
            
            reader.onload = function(event) {
                try {
                    const data = event.target.result;
                    
                    // 根据文件扩展名判断格式
                    if (file.name.toLowerCase().endsWith('.xlsx') || file.name.toLowerCase().endsWith('.xls')) {
                        // Excel文件处理
                        handleExcelImport(data);
                    } else if (file.name.toLowerCase().endsWith('.csv')) {
                        // CSV文件处理
                        handleCSVImport(data);
                    } else {
                        showNotification('不支持的文件格式', 'error');
                    }
                } catch (error) {
                    console.error('导入失败:', error);
                    showNotification('导入失败,请检查文件格式', 'error');
                }
            };
            
            reader.onerror = function() {
                showNotification('文件读取失败', 'error');
            };
            
            // 读取文件
            if (file.name.toLowerCase().endsWith('.xlsx') || file.name.toLowerCase().endsWith('.xls')) {
                reader.readAsArrayBuffer(file);
            } else {
                reader.readAsText(file, 'UTF-8');
            }
        }
        
        // 处理Excel导入
        function handleExcelImport(data) {
            try {
                const workbook = XLSX.read(data, { type: 'array' });
                
                // 获取第一个工作表
                const firstSheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[firstSheetName];
                
                // 将工作表转换为JSON
                const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
                
                // 检查标题行
                if (jsonData.length === 0 || jsonData[0][0] !== "问题") {
                    showNotification('Excel格式不正确,缺少标题行', 'error');
                    return;
                }
                
                // 跳过标题行
                const parsedQuestions = [];
                for (let i = 1; i < jsonData.length; i++) {
                    const row = jsonData[i];
                    if (!row || row.length === 0) continue;
                    
                    // 提取问题
                    const questionText = row[0] || "";
                    const questionImage = row[1] || "";
                    
                    // 提取选项(最多6个)
                    const options = [];
                    for (let j = 0; j < 6; j++) {
                        const textIndex = 2 + j * 2;
                        const imageIndex = textIndex + 1;
                        
                        if (textIndex < row.length && (row[textIndex] || row[imageIndex])) {
                            options.push({
                                text: row[textIndex] || "",
                                image: row[imageIndex] || ""
                            });
                        }
                    }
                    
                    // 提取答案
                    const answers = (row[14] || "").toString().toUpperCase().split('');
                    
                    // 提取题目类型(第15列)
                    let type = "multiple"; // 默认多选题
                    if (row.length >= 16 && row[15]) {
                        const typeStr = row[15].toString().toLowerCase();
                        if (typeStr === "single") {
                            type = "single";
                        } else if (typeStr === "truefalse") {
                            type = "truefalse";
                        } else if (typeStr === "fillblank") {
                            type = "fillblank";
                        } else if (typeStr === "essay") {
                            type = "essay";
                        }
                    }
                    
                    // 提取题目分数(第16列)
                    let points = 1; // 默认1分
                    if (row.length >= 17 && row[16]) {
                        const pointsValue = parseInt(row[16]);
                        if (!isNaN(pointsValue)) {
                            points = pointsValue;
                        }
                    }
                    
                    // 提取答案解析(第17列)
                    const explanation = row[17] || "";
                    
                    // 提取填空项
                    const blanks = [];
                    let blankScoringMode = "allOrNothing";
                    
                    if (type === "fillblank") {
                        // 提取填空项(最多6个)
                        for (let j = 0; j < 6; j++) {
                            const answerIndex = 18 + j * 2;
                            const pointsIndex = answerIndex + 1;
                            
                            if (answerIndex < row.length && row[answerIndex]) {
                                blanks.push({
                                    answer: row[answerIndex] || "",
                                    points: parseInt(row[pointsIndex]) || 1
                                });
                            }
                        }
                    }
                    
                    // 提取完整答案(第30列)
                    const essayAnswer = row.length >= 31 ? row[30] || "" : "";
                    
                    // 提取关键词
                    const keywords = [];
                    if (type === "essay") {
                        // 提取关键词(最多5个)
                        for (let j = 0; j < 5; j++) {
                            const keywordIndex = 31 + j * 2;
                            const pointsIndex = keywordIndex + 1;
                            
                            if (keywordIndex < row.length && row[keywordIndex]) {
                                keywords.push({
                                    keyword: row[keywordIndex] || "",
                                    points: parseInt(row[pointsIndex]) || 1
                                });
                            }
                        }
                    }
                    
                    // 提取评分规则(最后列)
                    let essayScoringMode = "partialCredit"; // 解答题默认按关键词给分
                    if (row.length >= 41 && row[40]) {
                        essayScoringMode = row[40] || "partialCredit";
                    }
                    
                    // 创建题目对象
                    const question = {
                        id: Date.now() + i, // 唯一ID
                        text: questionText,
                        image: questionImage,
                        explanation: explanation,
                        type: type,
                        points: points,
                        options: options,
                        correct: answers,
                        blanks: blanks,
                        essayAnswer: essayAnswer,
                        keywords: keywords,
                        blankScoringMode: blankScoringMode,
                        essayScoringMode: essayScoringMode // 新增解答题评分规则
                    };
                    
                    parsedQuestions.push(question);
                }
                
                if (parsedQuestions.length > 0) {
                    // 添加到题库
                    questions = questions.concat(parsedQuestions);
                    renderQuestionList();
                    
                    // 启用按钮
                    exportExcelBtn.disabled = false;
                    exportCsvBtn.disabled = false;
                    clearAllBtn.disabled = false;
                    
                    showNotification(`成功导入 ${parsedQuestions.length} 道题目`);
                } else {
                    showNotification('未找到有效的题目数据', 'error');
                }
            } catch (error) {
                console.error('导入Excel失败:', error);
                showNotification('导入失败,请检查文件格式', 'error');
            }
        }
        
        // 处理CSV导入
        function handleCSVImport(csvText) {
            try {
                // 解析CSV内容
                const parsedQuestions = parseCSV(csvText);
                
                if (parsedQuestions.length > 0) {
                    // 添加到题库
                    questions = questions.concat(parsedQuestions);
                    renderQuestionList();
                    
                    // 启用按钮
                    exportExcelBtn.disabled = false;
                    exportCsvBtn.disabled = false;
                    clearAllBtn.disabled = false;
                    
                    showNotification(`成功导入 ${parsedQuestions.length} 道题目`);
                } else {
                    showNotification('未找到有效的题目数据', 'error');
                }
            } catch (error) {
                console.error('导入CSV失败:', error);
                showNotification('导入失败,请检查文件格式', 'error');
            }
        }
        
        // 解析CSV内容
        function parseCSV(csvText) {
            const questions = [];
            const lines = csvText.split('\n');
            
            // 检查标题行
            if (lines.length === 0 || !lines[0].startsWith('问题,问题图片')) {
                showNotification('CSV格式不正确,缺少标题行', 'error');
                return [];
            }
            
            // 跳过标题行
            for (let i = 1; i < lines.length; i++) {
                const line = lines[i].trim();
                if (!line) continue; // 跳过空行
                
                // 分割CSV行
                const fields = parseCSVLine(line);
                
                // 检查字段数量
                if (fields.length < 17) {
                    console.warn(`跳过第 ${i+1} 行: 字段数量不足`, fields);
                    continue;
                }
                
                // 提取问题
                const questionText = fields[0];
                const questionImage = fields[1];
                
                // 提取选项(最多6个)
                const options = [];
                for (let j = 0; j < 6; j++) {
                    const textIndex = 2 + j * 2;
                    const imageIndex = textIndex + 1;
                    
                    if (textIndex < fields.length && (fields[textIndex] || fields[imageIndex])) {
                        options.push({
                            text: fields[textIndex] || '',
                            image: fields[imageIndex] || ''
                        });
                    }
                }
                
                // 提取答案
                const answers = fields[14].toUpperCase().split('');
                
                // 提取题目类型(第15列)
                let type = 'multiple'; // 默认多选题
                if (fields.length >= 16 && fields[15]) {
                    const typeStr = fields[15].toLowerCase();
                    if (typeStr === 'single') {
                        type = 'single';
                    } else if (typeStr === 'truefalse') {
                        type = 'truefalse';
                    } else if (typeStr === 'fillblank') {
                        type = 'fillblank';
                    } else if (typeStr === 'essay') {
                        type = 'essay';
                    }
                }
                
                // 提取题目分数(第16列)
                let points = 1; // 默认1分
                if (fields.length >= 17 && fields[16]) {
                    const pointsValue = parseInt(fields[16]);
                    if (!isNaN(pointsValue)) {
                        points = pointsValue;
                    }
                }
                
                // 提取答案解析(第17列)
                let explanation = '';
                if (fields.length >= 18) {
                    explanation = fields[17];
                }
                
                // 提取填空项
                const blanks = [];
                let blankScoringMode = 'allOrNothing';
                
                if (type === 'fillblank') {
                    // 提取填空项(最多6个)
                    for (let j = 0; j < 6; j++) {
                        const answerIndex = 18 + j * 2;
                        const pointsIndex = answerIndex + 1;
                        
                        if (answerIndex < fields.length && fields[answerIndex]) {
                            blanks.push({
                                answer: fields[answerIndex] || '',
                                points: parseInt(fields[pointsIndex]) || 1
                            });
                        }
                    }
                }
                
                // 提取完整答案(第30列)
                const essayAnswer = fields.length >= 31 ? fields[30] || "" : "";
                
                // 提取关键词
                const keywords = [];
                if (type === 'essay') {
                    // 提取关键词(最多5个)
                    for (let j = 0; j < 5; j++) {
                        const keywordIndex = 31 + j * 2;
                        const pointsIndex = keywordIndex + 1;
                        
                        if (keywordIndex < fields.length && fields[keywordIndex]) {
                            keywords.push({
                                keyword: fields[keywordIndex] || '',
                                points: parseInt(fields[pointsIndex]) || 1
                            });
                        }
                    }
                }
                
                // 提取评分规则(最后列)
                let essayScoringMode = "partialCredit"; // 解答题默认按关键词给分
                if (fields.length >= 41 && fields[40]) {
                    essayScoringMode = fields[40];
                }
                
                // 创建题目对象
                const question = {
                    id: Date.now() + i, // 唯一ID
                    text: questionText,
                    image: questionImage || '',
                    explanation: explanation,
                    type: type,
                    points: points,
                    options: options,
                    correct: answers,
                    blanks: blanks,
                    essayAnswer: essayAnswer,
                    keywords: keywords,
                    blankScoringMode: blankScoringMode,
                    essayScoringMode: essayScoringMode // 新增解答题评分规则
                };
                
                questions.push(question);
            }
            
            return questions;
        }
        
        // 解析CSV行
        function parseCSVLine(line) {
            const fields = [];
            let currentField = '';
            let inQuotes = false;
            let escapeNext = false;
            
            for (let i = 0; i < line.length; i++) {
                const char = line[i];
                
                if (escapeNext) {
                    currentField += char;
                    escapeNext = false;
                    continue;
                }
                
                if (char === '"') {
                    if (inQuotes && line[i + 1] === '"') {
                        // 转义引号
                        currentField += '"';
                        i++; // 跳过下一个引号
                    } else {
                        inQuotes = !inQuotes;
                    }
                    continue;
                }
                
                if (char === ',' && !inQuotes) {
                    fields.push(currentField);
                    currentField = '';
                    continue;
                }
                
                if (char === '\\') {
                    escapeNext = true;
                    continue;
                }
                
                currentField += char;
            }
            
            // 添加最后一个字段
            fields.push(currentField);
            
            return fields;
        }
        
        // 显示通知
        function showNotification(message, type = 'success') {
            const content = notification.querySelector('#notification-message');
            content.textContent = message;
            
            notification.className = 'notification';
            notification.classList.add('show', type);
            
            // 更新图标
            const icon = notification.querySelector('i');
            if (type === 'error') {
                icon.className = 'fas fa-exclamation-circle';
            } else {
                icon.className = 'fas fa-check-circle';
            }
            
            setTimeout(() => {
                notification.classList.remove('show');
            }, 3000);
        }
        
        // 初始化应用
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html>


成品

增强版答题系统-2025.10.7.zip (45.92 KB, 下载次数: 400)

到此为止,除非有Bug不再更新

免费评分

参与人数 6吾爱币 +5 热心值 +6 收起 理由
lane_lm + 1 + 1 我很赞同!
gztf + 1 + 1 谢谢@Thanks!
四君子 + 1 + 1 热心回复!
shaunkelly + 1 + 1 我很赞同!
zhurujun043 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
TNB + 1 谢谢@Thanks!

查看全部评分

TzzFly 发表于 2025-10-4 18:33
Zzz0 发表于 2025-10-4 09:51
你提供一下题库文件,我才好测试

又弄了一个题试了一下也不行,这是题https://v2flyme.lanzoum.com/iXDam37myawj
xtkeji 发表于 2025-8-2 20:17
 楼主| xiaozhangben 发表于 2025-8-2 19:38
少污污 发表于 2025-8-2 19:15
可能提供些,CSV 题库 ? 我也想刷刷题~~

用excel版题库直接另存为csv格式。具体格式见图片。你想刷什么自己弄哈。
zhurujun043 发表于 2025-8-3 11:21
Zzz0 发表于 2025-8-3 10:51
用DeepSeek改进了你的答题系统

请问这个题库是即时出现答案还是最后提交以后出现答案,我希望是提交试卷以后出现全部的答题情况,有对有错,那样让自己记得更牢。
头像被屏蔽
dongfangguniang 发表于 2025-8-2 18:51
提示: 作者被禁止或删除 内容自动屏蔽
13319937326 发表于 2025-8-2 19:00
楼主,我来抢生意来了

少污污 发表于 2025-8-2 19:15
可能提供些,CSV 题库 ? 我也想刷刷题~~
 楼主| xiaozhangben 发表于 2025-8-2 19:16
13319937326 发表于 2025-8-2 19:00
楼主,我来抢生意来了

我最近才注册的账号,对论坛不太了解。说实话,我没看明白你在说啥
青春作伴 发表于 2025-8-2 19:16
楼上的,你抢生意的图片显不出来
13319937326 发表于 2025-8-2 19:24
我这均能正常显示
具体时间截图显示
QQ20250802-192210.png
QQ20250802-192237.png
long8586 发表于 2025-8-2 19:26
相当不错的工具。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-28 22:37

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表