<template>
  <div class="generate-panel">
    <PageHeader
      title="AI智能出题系统"
      description="基于AI技术自动生成高质量试题"
    />

    <StatsRow :stats="examTypeStats" />

    <div class="config-panel">
      <ContentCard title="智能出题配置">
        <template #header>
          <h2 class="card-title">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
              <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
              <line x1="8" y1="21" x2="16" y2="21"></line>
              <line x1="12" y1="17" x2="12" y2="21"></line>
            </svg>
            智能出题配置
          </h2>
        </template>

        <div class="form-content">
          <div class="form-item form-item--full">
            <label class="form-label">选择制度文件 <span class="required-mark">*</span></label>

            <!-- 从文件管理跳转过来的文件信息提示 -->
            <div v-if="isFileFromReadModule" class="file-from-read-module-banner">
              <div class="banner-icon">📄</div>
              <div class="banner-content">
                <div class="banner-title">已从文件管理选择文件</div>
                <div class="banner-file-info">
                  <strong>{{ selectedDocData?.title || selectedDocData?.rawFileName }}</strong>
                  <span class="version-badge">v{{ selectedDocData?.version }}</span>
                  <span class="collection-badge">{{ selectedCollectionName }}</span>
                </div>
              </div>
              <button class="banner-change-btn" @click="clearFileFromReadModule">
                更换文件
              </button>
            </div>

            <!-- 文件选择器（当没有从文件管理跳转时显示） -->
            <FileSelector
              v-else
              v-model="selectedDoc"
              @change="onDocSelected"
              @collection-change="onCollectionChange"
              :show-drop-zone="false"
              placeholder="先选择知识库，再选择制度文件..."
            />

            <div v-if="selectedCollectionName && !isFileFromReadModule" class="collection-info">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
                <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
              </svg>
              <span>当前知识库: <strong>{{ selectedCollectionName }}</strong></span>
            </div>
            <div v-if="selectedDocData && !isFileFromReadModule" class="selected-file-info">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                <polyline points="14 2 14 8 20 8"></polyline>
              </svg>
              <span>{{ selectedDocData.title || selectedDocData.rawFileName }}</span>
              <span>v{{ selectedDocData.version }}</span>
            </div>
          </div>

          <div class="form-item">
            <label class="form-label">难度等级</label>
            <select v-model="difficulty" class="form-select">
              <option :value="1">简单</option>
              <option :value="2">中等</option>
              <option :value="3">困难</option>
            </select>
          </div>

          <div class="form-item form-item--total">
            <label class="form-label">总计题数</label>
            <div class="total-display">
              <strong>{{ totalQuestionCount }}</strong> 题
            </div>
          </div>

          <div class="form-item form-item--full">
            <label class="form-label">题型与数量配置</label>
            <div class="type-count-grid">
              <div class="type-count-item" v-for="qt in questionTypeOptions" :key="qt.value">
                <label class="checkbox-label" :class="{ active: questionTypeCounts[qt.value] > 0 }">
                  <input type="checkbox" :checked="questionTypeCounts[qt.value] > 0" @change="toggleQuestionType(qt.value)" />
                  {{ qt.label }}
                </label>
                <input
                  type="number"
                  v-model.number="questionTypeCounts[qt.value]"
                  min="0"
                  max="50"
                  class="form-input-sm"
                  :disabled="questionTypeCounts[qt.value] <= 0"
                  placeholder="0"
                />
              </div>
            </div>
          </div>

          <div class="action-bar">
            <button class="btn btn-primary btn-start" @click="startTaskGeneration" :disabled="!canStartTask">
              <svg v-if="!hasActiveTasks" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                <path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"></path>
                <path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"></path>
              </svg>
              <svg v-else class="btn-spin" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <circle cx="12" cy="12" r="10" stroke-dasharray="30 40" stroke-dashoffset="0"/>
              </svg>
              {{ hasActiveTasks ? `出题中 (${activeTasks.length})...` : '开始出题' }}
            </button>
            <button class="btn btn-secondary" @click="generatedQuestions = []">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                <polyline points="3 6 5 6 21 6"></polyline>
                <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
              </svg>
              清空结果
            </button>
          </div>
        </div>
      </ContentCard>
    </div>

    <!-- 出题任务栏 -->
    <TaskBar
      :tasks="tasks"
      @remove="removeTask"
      @clear-completed="clearCompleted"
      @clear-all="clearAll"
    />

    <div class="result-panel">
      <ContentCard title="待审核题目列表">
        <div v-if="generatedQuestions.length === 0" class="empty-state">
          <div class="empty-icon">✎</div>
          <p>暂无生成的题目</p>
          <p class="empty-hint">请先选择文件并配置题型数量，然后点击"开始生成题目"</p>
        </div>

        <div v-else class="question-list">
          <div v-for="(q, index) in pagedQuestions" :key="(currentPage - 1) * pageSize + index" class="question-item">
            <div class="question-header">
              <span class="question-number">第{{ (currentPage - 1) * pageSize + index + 1 }}题</span>
              <span :class="['type-badge', q.type]">{{ getTypeLabel(q.type) }}</span>
              <span v-if="q.status === 'pending'" class="status-badge pending">待审核</span>
            </div>

            <div class="question-content">{{ q.stem }}</div>

            <div v-if="(q.type === 'single_choice' || q.type === 'multiple_choice') && q.options && q.options.length > 0" class="question-options">
              <div v-for="opt in q.options" :key="opt.key" class="option-item" :class="{ correct: opt.isCorrect }">
                <span class="option-key">{{ opt.key }}.</span>
                <span class="option-text">{{ opt.text }}</span>
                <span v-if="opt.isCorrect" class="correct-badge">✓ 正确答案</span>
              </div>
            </div>

            <div v-if="q.type === 'true_false'" class="question-options">
              <div class="option-item" :class="{ correct: q.answer === 'T' || q.answer === 'true' }">
                <span>正确 (T)</span>
                <span v-if="q.answer === 'T' || q.answer === 'true'" class="correct-badge">✓ 正确答案</span>
              </div>
              <div class="option-item" :class="{ correct: q.answer === 'F' || q.answer === 'false' }">
                <span>错误 (F)</span>
                <span v-if="q.answer === 'F' || q.answer === 'false'" class="correct-badge">✓ 正确答案</span>
              </div>
            </div>

            <div v-if="q.type === 'fill_blank'" class="question-answer-section">
              <div class="answer-label">参考答案：</div>
              <div class="answer-content">{{ q.answer || '未设置' }}</div>
            </div>

            <div v-if="q.type === 'subjective'" class="question-answer-section">
              <div class="answer-label">参考答案：</div>
              <div class="answer-content">{{ q.answer || '未设置' }}</div>
            </div>

            <div class="question-actions">
              <button
                class="q-action-btn approve"
                :disabled="reviewingId === q.id"
                @click="approveQuestion(q)"
              >
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <polyline points="20 6 9 17 4 12"></polyline>
                </svg>
                {{ reviewingId === q.id ? '处理中...' : '通过' }}
              </button>
              <button
                class="q-action-btn reject"
                :disabled="reviewingId === q.id"
                @click="rejectQuestion(q)"
              >
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <line x1="18" y1="6" x2="6" y2="18"></line>
                  <line x1="6" y1="6" x2="18" y2="18"></line>
                </svg>
                {{ reviewingId === q.id ? '处理中...' : '不通过' }}
              </button>
              <button class="q-action-btn edit" @click="editQuestion(q)">
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                </svg>
                编辑
              </button>
            </div>
          </div>

          <div v-if="generatedQuestions.length > pageSize" class="pagination-wrapper">
            <a-pagination
              v-model:current="currentPage"
              :page-size="pageSize"
              :total="generatedQuestions.length"
              :show-size-changer="false"
              size="small"
              @change="onPageChange"
            />
          </div>
        </div>
      </ContentCard>
    </div>
  </div>

  <!-- 题目编辑弹窗 -->
  <Teleport to="body">
    <div v-if="editModalVisible" class="edit-overlay" @click.self="closeEditModal">
      <div class="edit-dialog">
        <div class="edit-header">
          <h3>编辑题目</h3>
          <button class="close-btn" @click="closeEditModal">×</button>
        </div>
        <div class="edit-body">
          <div class="edit-field">
            <label>题干</label>
            <textarea v-model="editForm.stem" class="edit-textarea" rows="3"></textarea>
          </div>
          <div class="edit-field">
            <label>难度等级</label>
            <select v-model="editForm.difficulty" class="edit-select">
              <option :value="1">简单</option>
              <option :value="2">中等</option>
              <option :value="3">困难</option>
            </select>
          </div>

          <!-- 选择题：选项列表 + 正确答案标记 -->
          <template v-if="editingQuestion && (editingQuestion.type === 'single_choice' || editingQuestion.type === 'multiple_choice')">
            <div class="edit-field">
              <label>选项与答案</label>
              <div class="gp-options-edit-list">
                <div v-for="(opt, idx) in editForm.options" :key="idx" class="gp-option-edit-row">
                  <span class="gp-option-key">{{ opt.key }}</span>
                  <input v-model="opt.text" type="text" class="gp-option-input" :placeholder="'选项' + opt.key + '内容'" />
                  <button
                    :class="['gp-correct-toggle', { active: opt.isCorrect }]"
                    @click="setCorrectOption(idx)"
                    :title="opt.isCorrect ? '取消正确答案' : '设为正确答案'"
                  >
                    {{ opt.isCorrect ? '✓ 正确' : '设为正确' }}
                  </button>
                </div>
              </div>
              <p class="gp-edit-hint">{{ editingQuestion.type === 'single_choice' ? '单选题只能有一个正确答案' : '多选题可设置多个正确答案' }}</p>
            </div>
          </template>

          <!-- 判断题：可视化选项框 -->
          <template v-if="editingQuestion && editingQuestion.type === 'true_false'">
            <div class="edit-field">
              <label>正确答案</label>
              <div class="gp-tf-answer">
                <button
                  :class="['gp-tf-box', { active: editForm.answer === 'T' }]"
                  @click="editForm.answer = 'T'"
                >✓ 正确</button>
                <button
                  :class="['gp-tf-box', { active: editForm.answer === 'F' }]"
                  @click="editForm.answer = 'F'"
                >✗ 错误</button>
              </div>
            </div>
          </template>

          <!-- 填空题：填空栏结构 + 答案预览 -->
          <template v-if="editingQuestion && editingQuestion.type === 'fill_blank'">
            <div class="edit-field">
              <label>参考答案</label>
              <p class="gp-edit-hint" style="margin-bottom: 8px;">多个填空答案请用逗号 <code>,</code> 分隔，如：<code>北京,故宫,1949</code></p>
              <textarea v-model="editForm.answer" class="edit-textarea" rows="3" placeholder="输入参考答案，多空用逗号分隔..."></textarea>
              <div v-if="blankPreviewList.length > 0" class="gp-blank-preview">
                <span class="gp-preview-label">已识别 {{ blankPreviewList.length }} 个填空：</span>
                <span v-for="(b, i) in blankPreviewList" :key="i" class="gp-preview-chip">
                  <span class="gp-chip-index">{{ i + 1 }}</span>{{ b }}
                </span>
              </div>
            </div>
          </template>

          <!-- 简答题：大尺寸输入框 -->
          <template v-if="editingQuestion && editingQuestion.type === 'subjective'">
            <div class="edit-field">
              <label>参考答案</label>
              <textarea v-model="editForm.answer" class="edit-textarea gp-subjective-textarea" rows="6" placeholder="输入参考答案..."></textarea>
            </div>
          </template>
        </div>
        <div class="edit-footer">
          <button class="btn btn-secondary" @click="closeEditModal">取消</button>
          <button class="btn btn-primary" :disabled="savingEdit" @click="saveEdit">
            {{ savingEdit ? '保存中...' : '保存修改' }}
          </button>
        </div>
      </div>
    </div>
  </Teleport>
</template>

<script setup>
import { ref, reactive, computed, watch, nextTick, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import PageHeader from '../common/PageHeader.vue'
import StatsRow from '../common/StatsRow.vue'
import ContentCard from '../common/ContentCard.vue'
import FileSelector from '../FileSelector.vue'
import TaskBar from './TaskBar.vue'
import { useGenerateState } from './composables/useGenerateState.js'
import { useTaskManager } from './composables/useTaskManager.js'
import { questionAPI } from '../../api/question.js'

const {
  selectedDoc,
  selectedDocData,
  selectedCollectionName,
  difficulty,
  generatedQuestions,
  isGenerating,
  questionTypeOptions,
  questionTypeCounts,
  totalQuestionCount,
  apiTotalCount,
  resetApiTotalCount,
  examTypeStats,
  onDocSelected,
  onCollectionChange,
  toggleQuestionType,
  handleGenerateQuestions,
  transformQuestionData
} = useGenerateState()

// 任务管理器
const {
  tasks,
  activeTasks,
  hasActiveTasks,
  taskCount,
  removeTask,
  clearCompleted,
  clearAll,
  startGeneration
} = useTaskManager()

const canStartTask = computed(() => {
  const hasFile = selectedDocData.value && (selectedDocData.value.id || selectedDocData.value.filePath || selectedDocData.value.pdfUrl)
  // 检查用户配置的题型数量总和（而非 apiTotalCount，后者是生成成功后才有的统计值）
  const userConfiguredCount = Object.values(questionTypeCounts).reduce((sum, c) => sum + (Number(c) || 0), 0)
  const hasCount = userConfiguredCount > 0
  return hasFile && hasCount && !isGenerating.value
})

const startTaskGeneration = async () => {
  if (!selectedDocData.value) {
    message.warning('请先选择文件')
    return
  }
  if (totalQuestionCount.value <= 0 && totalQuestionCount.value !== '-') {
    message.warning('请至少设置一种题型数量')
    return
  }

  // 重置统计为"暂未生成"
  resetApiTotalCount()

  const fileData = { ...selectedDocData.value, collectionName: selectedCollectionName.value }
  const typeCounts = {}
  questionTypeOptions.forEach(opt => {
    typeCounts[opt.value] = questionTypeCounts[opt.value] || 0
  })

  message.success('已加入出题任务队列')
  await startGeneration(
    fileData,
    difficulty.value,
    typeCounts,
    totalQuestionCount.value
  )

  // 从已完成任务的 resultCount 同步题目总数（与 TaskItem 数据源一致）
  const completedTask = tasks.value
    .filter(t => t.status === 'completed')
    .sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))[0]
  if (completedTask?.resultCount != null && completedTask.resultCount > 0) {
    apiTotalCount.value = completedTask.resultCount
  }

  // 刷新待审批列表
  loadPendingQuestions(true)
}

const pageSize = 10
const currentPage = ref(1)

const pagedQuestions = computed(() => {
  const start = (currentPage.value - 1) * pageSize
  const end = start + pageSize
  return generatedQuestions.value.slice(start, end)
})

const onPageChange = (page) => {
  currentPage.value = page
}

watch(generatedQuestions, () => {
  currentPage.value = 1
})

const loadPendingQuestions = async (forceRefresh = false) => {
  try {
    const res = await questionAPI.pageQuestions({
      status: 'pending',
      pageNum: 1,
      pageSize: 999
    })
    const raw = res?.data || res
    let list = []
    if (Array.isArray(raw)) {
      list = raw
    } else {
      const rawData = raw?.data || raw
      list = rawData?.list || rawData?.records || rawData?.questions || (Array.isArray(rawData) ? rawData : [])
    }

    if (Array.isArray(list) && list.length > 0) {
      console.log(`[GeneratePanel] pageQuestions(status=pending) 返回 ${list.length} 条`)
      const newQuestions = transformQuestionData(list)
      if (forceRefresh || generatedQuestions.value.length === 0) {
        generatedQuestions.value = newQuestions
        console.log(`[GeneratePanel] ${forceRefresh ? '强制刷新' : '首次加载'} ${generatedQuestions.value.length} 条待审核题目`)
      } else {
        // 增量合并：按 question_id 去重，避免重复
        const existingIds = new Set(generatedQuestions.value.map(q => q.questionId || q.question_id))
        const added = newQuestions.filter(q => !existingIds.has(q.questionId || q.question_id))
        if (added.length > 0) {
          generatedQuestions.value = [...generatedQuestions.value, ...added]
          console.log(`[GeneratePanel] 增量合并 ${added.length} 条新题目（总计 ${generatedQuestions.value.length} 条）`)
        } else {
          console.log(`[GeneratePanel] 无新题目需要合并`)
        }
      }
    } else {
      if (forceRefresh) {
        generatedQuestions.value = []
      }
    }
  } catch (error) {
    console.warn('[GeneratePanel] 自动加载待审核题目失败:', error.message)
  }
}

onMounted(() => {
  loadPendingQuestions()
})

// 接收从ExamModuleContainer传来的文件信息
const props = defineProps({
  preselectedFile: {
    type: Object,
    default: null
  }
})

// 存储待处理的文件信息（延迟处理）
const pendingPreselectedFile = ref(null)

// 标记当前文件是否来自文件管理模块的跳转
const isFileFromReadModule = ref(false)

/**
 * 从文件管理模块选中文件
 * 由ExamModuleContainer调用此方法
 */
const selectFileFromReadModule = (payload) => {
  console.log('📥 [GeneratePanel] selectFileFromReadModule 被调用:', payload)

  if (!payload || !payload.fileData) {
    console.warn('⚠️ [GeneratePanel] 收到无效的文件信息')
    return
  }

  const fileData = payload.fileData

  // 构建符合GeneratePanel预期的文档数据结构
  const docData = {
    id: fileData.id,
    title: fileData.title || fileData.fileName || fileData.rawFileName,
    rawFileName: fileData.fileName || fileData.rawFileName,
    version: fileData.currentVersion || fileData.version,
    extension: fileData.extension,
    pdfUrl: fileData.pdfUrl || fileData.filePath || fileData.path || fileData.fileName || fileData.title || fileData.rawFileName,
    filePath: fileData.pdfUrl || fileData.filePath || fileData.path || fileData.fileName || fileData.title || fileData.rawFileName
  }

  console.log('✅ [GeneratePanel] 设置选中的文件:', docData)
  console.log('✅ [GeneratePanel] 设置知识库:', payload.collectionName)

  // 标记为从文件管理跳转过来
  isFileFromReadModule.value = true

  // 关键修复：同时设置 selectedDoc（用于验证）和 selectedDocData（用于显示）
  selectedDoc.value = docData.id  // ✅ 设置文件ID，通过验证
  onDocSelected(docData)          // ✅ 设置完整文档数据

  if (payload.collectionName) {
    onCollectionChange(payload.collectionName)
  }
}

/**
 * 清除从文件管理选择的文件，切换回手动选择模式
 */
const clearFileFromReadModule = () => {
  console.log('🔄 [GeneratePanel] 清除跳转文件，切换到手动选择模式')
  isFileFromReadModule.value = false
  // 清空选择，让用户重新通过 FileSelector 选择
  selectedDoc.value = null
  selectedDocData.value = null
  selectedCollectionName.value = ''
}

// 监听props变化（不使用immediate，避免初始化顺序问题）
watch(() => props.preselectedFile, (newVal) => {
  if (newVal) {
    // 延迟到下一个tick处理，确保所有函数都已初始化
    pendingPreselectedFile.value = newVal
    nextTick(() => {
      if (pendingPreselectedFile.value) {
        selectFileFromReadModule(pendingPreselectedFile.value)
        pendingPreselectedFile.value = null
      }
    })
  }
})

// 暴露方法给父组件(ExamModuleContainer)调用
defineExpose({
  selectFileFromReadModule
})

const reviewingId = ref(null)

const approveQuestion = async (q) => {
  const questionId = q.questionId || q.id
  console.log('[审批] 通过题目 - 使用ID:', questionId, '题目:', q.stem?.substring(0, 50))
  reviewingId.value = q.id
  try {
    await questionAPI.reviewQuestion(questionId, 'approved', '')
    message.success('已通过该题目')
    const idx = generatedQuestions.value.findIndex(item => (item.questionId || item.id) === questionId)
    if (idx !== -1) {
      generatedQuestions.value.splice(idx, 1)
      console.log('[审批] 已从列表移除，剩余:', generatedQuestions.value.length)
    } else {
      console.warn('[审批] 未在列表中找到问题:', questionId)
    }
  } catch (error) {
    console.error('[审批] 通过失败:', error)
    message.error('审批失败: ' + (error.message || '未知错误'))
  } finally {
    reviewingId.value = null
  }
}

const rejectQuestion = async (q) => {
  const questionId = q.questionId || q.id
  console.log('[审批] 驳回题目 - 使用ID:', questionId, '题目:', q.stem?.substring(0, 50))
  reviewingId.value = q.id
  try {
    await questionAPI.reviewQuestion(questionId, 'rejected', '')
    message.success('已驳回该题目')
    const idx = generatedQuestions.value.findIndex(item => (item.questionId || item.id) === questionId)
    if (idx !== -1) {
      generatedQuestions.value.splice(idx, 1)
      console.log('[审批] 已从列表移除，剩余:', generatedQuestions.value.length)
    } else {
      console.warn('[审批] 未在列表中找到问题:', questionId)
    }
  } catch (error) {
    console.error('[审批] 驳回失败:', error)
    message.error('驳回失败: ' + (error.message || '未知错误'))
  } finally {
    reviewingId.value = null
  }
}

const editModalVisible = ref(false)
const savingEdit = ref(false)
const editingQuestion = ref(null)
const editForm = reactive({ stem: '', difficulty: 2, answer: '', options: [] })

const normalizeTfAnswer = (val) => {
  if (val === null || val === undefined || val === '') return ''
  if (typeof val === 'boolean') return val ? 'T' : 'F'
  const s = String(val).trim().toUpperCase()
  if (s === 'T' || s === 'TRUE' || s === '1' || s === 'YES' || s === '对' || s === '正确') return 'T'
  if (s === 'F' || s === 'FALSE' || s === '0' || s === 'NO' || s === '错' || s === '错误') return 'F'
  return ''
}

const splitBlankAnswers = (raw) => {
  if (raw === null || raw === undefined || raw === '') return []
  const s = String(raw).trim()
  return s.split(/[,，;；\n\r]+/).map(b => b.trim()).filter(b => b.length > 0)
}

const blankPreviewList = computed(() => splitBlankAnswers(editForm.answer))

const setCorrectOption = (idx) => {
  if (!editForm.options[idx]) return
  const isSingleChoice = editingQuestion.value?.type === 'single_choice'
  if (isSingleChoice) {
    editForm.options.forEach((o, i) => { o.isCorrect = (i === idx) ? !o.isCorrect : false })
    if (!editForm.options[idx].isCorrect) {
      editForm.answer = ''
    } else {
      editForm.answer = editForm.options[idx].key
    }
  } else {
    editForm.options[idx].isCorrect = !editForm.options[idx].isCorrect
    const correctKeys = editForm.options.filter(o => o.isCorrect).map(o => o.key)
    editForm.answer = correctKeys.join(',')
  }
}

const editQuestion = (q) => {
  editingQuestion.value = q
  editForm.stem = q.stem || ''
  editForm.difficulty = q.difficulty || 2
  editForm.answer = q.type === 'true_false'
    ? normalizeTfAnswer(q.answer)
    : (q.answer || '')

  if (q.options && q.options.length > 0) {
    const correctKeys = (q.answer || '').split(',').map(k => k.trim().toUpperCase())
    editForm.options = q.options.map(opt => ({
      key: opt.key || opt.label || '',
      text: opt.text || opt.content || '',
      isCorrect: correctKeys.includes((opt.key || opt.label || '').toUpperCase())
    }))
  } else {
    editForm.options = []
  }

  editModalVisible.value = true
}

const closeEditModal = () => {
  editModalVisible.value = false
  editingQuestion.value = null
}

const saveEdit = async () => {
  if (!editingQuestion.value) return
  savingEdit.value = true
  try {
    const q = editingQuestion.value
    const isChoice = q.type === 'single_choice' || q.type === 'multiple_choice'
    const correctOpts = editForm.options.filter(o => o.isCorrect).map(o => o.key)

    // 答案：统一转为字符串（与 POST /api/question 创建接口格式一致）
    let answerStr
    if (isChoice) {
      answerStr = correctOpts.join(',')
    } else if (q.type === 'fill_blank') {
      answerStr = splitBlankAnswers(editForm.answer).join(',')
    } else {
      answerStr = editForm.answer || ''
    }

    // 严格匹配创建接口的数据结构
    const contentObj = {
      stem: editForm.stem,
      data: {},
      answer: answerStr
    }

    if (isChoice && editForm.options.length > 0) {
      contentObj.data.options = editForm.options.map(o => ({ key: o.key, content: o.text }))
    } else if (q.type === 'true_false') {
      contentObj.data.options = [
        { key: 'T', content: '正确' },
        { key: 'F', content: '错误' }
      ]
    } else if (q.type === 'fill_blank') {
      const blanks = splitBlankAnswers(editForm.answer)
      if (blanks.length > 0) contentObj.data.blank_count = blanks.length
    }

    const updateData = {
      question_type: q.type,
      difficulty: editForm.difficulty,
      content: contentObj
    }

    if (q.score != null) updateData.score = q.score
    if (q.document_name || q.documentName) updateData.document_name = q.document_name || q.documentName

    console.log('[保存] 发送 payload:', JSON.stringify(updateData, null, 2))
    await questionAPI.updateQuestion(q.id, updateData)

    q.stem = editForm.stem
    q.difficulty = editForm.difficulty
    q.answer = answerStr
    if (isChoice) {
      q.options = editForm.options.map(o => ({ key: o.key, text: o.text }))
    }

    message.success('修改已保存')
    closeEditModal()
  } catch (error) {
    const serverError = error.response?.data
    console.error('[保存] 更新题目失败:', {
      status: error.response?.status,
      statusText: error.response?.statusText,
      serverData: serverError,
      message: error.message
    })
    const errMsg = serverError?.message || serverError?.error || error.message || '请联系管理员'
    message.error('保存失败: ' + errMsg)
  } finally {
    savingEdit.value = false
  }
}

const getTypeLabel = (type) => {
  const typeMap = {
    single_choice: '单选',
    multiple_choice: '多选',
    true_false: '判断',
    fill_blank: '填空',
    subjective: '简答'
  }
  return typeMap[type] || type
}
</script>

<style scoped>
.generate-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 16px;
}

.config-panel {
  flex-shrink: 0;
  margin-bottom: 12px;
}

.result-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  margin-top: 16px;
}

.result-panel :deep(.content-card) {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.result-panel :deep(.card-body) {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.form-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 16px;
  align-items: start;
}

.form-item--full {
  grid-column: 1 / -1;
}

.form-item--total .total-display {
  padding: 6px 12px;
  background: #F8F9FA;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  color: #212529;
  text-align: center;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.form-item {
  margin-bottom: 0;
}

.form-label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: #212529;
  margin-bottom: 6px;
}

.required-mark {
  color: #C92A2A;
  margin-left: 4px;
}

.form-select {
  width: 100%;
  height: 36px;
  padding: 6px 12px;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  font-size: 13px;
  color: #212529;
  background: #FFFFFF;
  transition: border-color 0.15s ease;
  cursor: pointer;
}

.form-select:focus {
  border-color: #212529;
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
}

.form-select:hover {
  border-color: #CED4DA;
}

.type-count-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 6px;
}

.type-count-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  background: #F8F9FA;
  border: 1px solid #E9ECEF;
  border-radius: 6px;
  transition: border-color 0.15s ease;
}

.type-count-item:hover {
  border-color: #CED4DA;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-size: 13px;
  color: #495057;
  transition: color 0.15s ease;
  user-select: none;
}

.checkbox-label:hover {
  color: #212529;
}

.checkbox-label.active {
  color: #212529;
  font-weight: 600;
}

.checkbox-label input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
  accent-color: #212529;
}

.form-input-sm {
  width: 56px;
  height: 30px;
  padding: 4px 6px;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  font-size: 13px;
  text-align: center;
  font-weight: 500;
  transition: border-color 0.15s ease;
}

.form-input-sm:focus {
  border-color: #212529;
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
}

.form-input-sm:disabled {
  background: #F8F9FA;
  cursor: not-allowed;
  opacity: 0.6;
}

.action-bar {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 12px;
  border-top: 1px solid #E9ECEF;
  margin-top: 4px;
  grid-column: 1 / -1;
}

.btn {
  border-radius: 6px;
  padding: 0 14px;
  height: 36px;
  font-size: 13px;
  font-weight: 500;
  transition: all 0.15s ease;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  box-sizing: border-box;
  min-width: 100px;
}

.btn-primary {
  background: #212529;
  color: #FFFFFF;
}

.btn-primary:hover:not(:disabled) {
  background: #000000;
}

.btn-secondary {
  background: #FFFFFF;
  color: #212529;
  border: 1px solid #DEE2E6;
}

.btn-secondary:hover:not(:disabled) {
  background: #F8F9FA;
  border-color: #ADB5BD;
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* 从文件管理跳转的文件信息横幅 - 白色简洁风格 */
.file-from-read-module-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: #F8F9FA;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  margin-top: 4px;
}

.banner-icon {
  font-size: 20px;
  line-height: 1;
  flex-shrink: 0;
  opacity: 0.7;
}

.banner-content {
  flex: 1;
  min-width: 0;
}

.banner-title {
  font-size: 11px;
  color: #6C757D;
  font-weight: 500;
  margin-bottom: 3px;
}

.banner-file-info {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 13px;
  color: #212529;
}

.banner-file-info strong {
  font-weight: 600;
  color: #212529;
}

.version-badge,
.collection-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
  background: #E9ECEF;
  color: #495057;
  border: 1px solid #DEE2E6;
}

.banner-change-btn {
  padding: 6px 12px;
  background: #FFFFFF;
  border: 1px solid #CED4DA;
  border-radius: 6px;
  font-size: 12px;
  color: #495057;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
  flex-shrink: 0;
}

.banner-change-btn:hover {
  background: #212529;
  color: #FFFFFF;
  border-color: #212529;
}

.collection-info,
.selected-file-info {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  padding: 8px 12px;
  background: #F8F9FA;
  border-radius: 6px;
  border: 1px solid #E9ECEF;
  font-size: 12px;
  color: #495057;
}

.collection-info strong,
.selected-file-info strong {
  color: #212529;
  font-weight: 600;
}

/* === 按钮特殊样式 === */
.btn-start {
  gap: 8px;
  font-weight: 600;
  letter-spacing: 0.03em;
  transition: all 0.15s ease;
}

.btn-start:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.btn-spin {
  animation: btnSpin 1.2s linear infinite;
}

@keyframes btnSpin {
  to { transform: rotate(360deg); }
}

@keyframes dash {
  0% {
    stroke-dasharray: 1, 150;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -35;
  }
  100% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -124;
  }
}

/* === 分页样式 === */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 24px;
  background: #F8F9FA;
  border: 1px solid #E9ECEF;
  border-radius: 8px;
  min-height: 200px;
  flex: 1;
  gap: 16px;
}

.empty-icon {
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  background: #FFFFFF;
  border: 2px solid #E9ECEF;
  border-radius: 50%;
}

.empty-state p {
  font-size: 14px;
  font-weight: 500;
  color: #495057;
  margin-bottom: 4px;
}

.empty-hint {
  font-size: 13px;
  color: #6C757D;
  margin-top: 6px;
  max-width: 400px;
  text-align: center;
  line-height: 1.5;
}

.question-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px;
}

.question-item {
  padding: 14px;
  background: #FFFFFF;
  border: 1px solid #E9ECEF;
  border-radius: 8px;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.question-item:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

.question-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid #E9ECEF;
}

.question-number {
  font-size: 13px;
  color: #212529;
  font-weight: 600;
  background: #F8F9FA;
  padding: 2px 8px;
  border-radius: 4px;
}

.type-badge {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
  background: #FFFFFF;
  color: #212529;
  border: 1px solid #DEE2E6;
}

.status-badge {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
  margin-left: auto;
  background: #FFF9DB;
  color: #E67700;
  border: 1px solid #FFE066;
}

.question-content {
  font-size: 14px;
  line-height: 1.6;
  color: #212529;
  margin-bottom: 12px;
  padding: 10px 12px;
  background: #F8F9FA;
  border-radius: 6px;
  border-left: 3px solid #212529;
  font-weight: 400;
}

.question-options {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
}

/* 填空/简答题答案显示 */
.question-answer-section {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 10px;
  padding: 10px 12px;
  background: #F8F9FA;
  border-radius: 6px;
  border-left: 3px solid #1C7ED6;
}

.answer-label {
  font-size: 13px;
  font-weight: 600;
  color: #1C7ED6;
  white-space: nowrap;
  flex-shrink: 0;
}

.answer-content {
  font-size: 13px;
  color: #212529;
  line-height: 1.6;
  word-break: break-word;
}

.option-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 6px;
  transition: background 0.15s ease;
  background: #F8F9FA;
  border: 1px solid transparent;
}

.option-item:hover {
  background: #F1F3F5;
  border-color: #E9ECEF;
}

.option-item.correct {
  background: #EBFBEE;
  color: #2B8A3E;
  font-weight: 500;
  border-color: #D3F9D8;
}

.option-key {
  font-weight: 600;
  font-size: 13px;
  color: #212529;
  min-width: 20px;
}

.option-text {
  flex: 1;
  color: #212529;
  font-size: 13px;
  line-height: 1.5;
}

.correct-badge {
  margin-left: auto;
  padding: 2px 8px;
  background: #2B8A3E;
  color: white;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
}

/* 题目操作按钮 */
.question-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid #F1F3F5;
}

.q-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 14px;
  border-radius: 5px;
  font-size: 12px;
  font-weight: 500;
  border: 1.5px solid transparent;
  cursor: pointer;
  transition: all 0.15s ease;
  background: transparent;
  color: #495057;
}

.q-action-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none !important;
}

.q-action-btn.approve {
  color: #2B8A3E;
  border-color: #D3F9D8;
  background: #EBFBEE;
}

.q-action-btn.approve:hover:not(:disabled) {
  background: #2B8A3E;
  color: #FFFFFF;
  border-color: #2B8A3E;
}

.q-action-btn.reject {
  color: #C92A2A;
  border-color: #FFD6D6;
  background: #FFF5F5;
}

.q-action-btn.reject:hover:not(:disabled) {
  background: #C92A2A;
  color: #FFFFFF;
  border-color: #C92A2A;
}

.q-action-btn.edit {
  color: #1C7ED6;
  border-color: #D0EBFF;
  background: #E7F5FF;
}

.q-action-btn.edit:hover:not(:disabled) {
  background: #1C7ED6;
  color: #FFFFFF;
  border-color: #1C7ED6;
}

/* 编辑弹窗 */
.edit-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
}

.edit-dialog {
  background: #FFFFFF;
  border-radius: 10px;
  width: 480px;
  max-width: 90vw;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}

.edit-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #E9ECEF;
}

.edit-header h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: #212529;
}

.close-btn {
  width: 28px;
  height: 28px;
  border: none;
  background: #F8F9FA;
  border-radius: 6px;
  font-size: 18px;
  cursor: pointer;
  color: #868E96;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease;
}

.close-btn:hover {
  background: #E9ECEF;
  color: #212529;
}

.edit-body {
  padding: 20px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.edit-field label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: #495057;
  margin-bottom: 6px;
}

.edit-textarea,
.edit-input,
.edit-select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #DEE2E6;
  border-radius: 6px;
  font-size: 13px;
  color: #212529;
  background: #FFFFFF;
  transition: border-color 0.15s ease;
  box-sizing: border-box;
}

.edit-textarea {
  resize: vertical;
  min-height: 60px;
  font-family: inherit;
  line-height: 1.5;
}

.edit-textarea:focus,
.edit-input:focus,
.edit-select:focus {
  border-color: #212529;
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
}

.edit-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid #E9ECEF;
}

/* ===== 题型差异化答案组件样式 ===== */

.gp-subjective-textarea {
  min-height: 140px;
  line-height: 1.7;
  font-size: 13px;
}

.gp-tf-answer {
  display: flex;
  gap: 12px;
}

.gp-tf-box {
  flex: 1;
  padding: 12px 16px;
  border: 2px solid #DEE2E6;
  border-radius: 8px;
  background: #FFFFFF;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  text-align: center;
  user-select: none;
}

.gp-tf-box:hover:not(.active) {
  border-color: #ADB5BD;
  background: #F8F9FA;
}

.gp-tf-box.active {
  background: #2B8A3E;
  border-color: #2B8A3E;
  color: #FFFFFF;
  box-shadow: 0 2px 8px rgba(43, 138, 62, 0.3);
}

.gp-options-edit-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.gp-option-edit-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.gp-option-key {
  width: 28px;
  height: 28px;
  background: #212529;
  color: #FFFFFF;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
}

.gp-option-input {
  flex: 1;
  height: 36px;
  padding: 0 12px;
  border: 1.5px solid #DEE2E6;
  border-radius: 6px;
  font-size: 13px;
  color: #212529;
  transition: border-color 0.15s ease;
}

.gp-option-input:focus {
  outline: none;
  border-color: #212529;
  box-shadow: 0 0 0 3px rgba(33, 37, 41, 0.06);
}

.gp-correct-toggle {
  height: 36px;
  padding: 0 14px;
  border: 1.5px solid #DEE2E6;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  background: #FFFFFF;
  transition: all 0.2s ease;
  color: #868E96;
  flex-shrink: 0;
  white-space: nowrap;
}

.gp-correct-toggle:hover:not(.active) {
  border-color: #86EFAC;
  color: #16A34A;
  background: #F0FFF4;
}

.gp-correct-toggle.active {
  background: #16A34A;
  border-color: #16A34A;
  color: #FFFFFF;
  box-shadow: 0 2px 6px rgba(22, 163, 74, 0.3);
}

.gp-edit-hint {
  margin: 6px 0 0;
  font-size: 11px;
  color: #868E96;
  line-height: 1.4;
}

.gp-edit-hint code {
  background: #F1F3F5;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 11px;
  color: #495057;
}

.gp-blank-preview {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
  padding: 8px 12px;
  background: #F8F9FA;
  border-radius: 6px;
  border: 1px solid #E9ECEF;
}

.gp-preview-label {
  color: #868E96;
  font-weight: 500;
  font-size: 12px;
}

.gp-preview-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  background: #E7F5FF;
  color: #1C7ED6;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
}

.gp-chip-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  background: #1C7ED6;
  color: #FFFFFF;
  border-radius: 50%;
  font-size: 10px;
  font-weight: 700;
  flex-shrink: 0;
}

.card-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: #212529;
  margin: 0;
}

@media (max-width: 1024px) {
  .type-count-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .form-content {
    gap: 10px 12px;
  }
}

@media (max-width: 768px) {
  .generate-panel {
    padding: 12px;
  }

  .form-content {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .form-item--full,
  .action-bar {
    grid-column: 1;
  }

  .type-count-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .action-bar {
    flex-direction: column;
  }

  .action-bar .btn {
    width: 100%;
  }

  .config-panel {
    margin-bottom: 8px;
  }

  .form-label {
    font-size: 12px;
  }

  .type-count-item {
    padding: 6px 8px;
  }
}

@media (max-width: 480px) {
  .type-count-grid {
    grid-template-columns: 1fr;
  }
}

.pagination-wrapper {
  display: flex;
  justify-content: center;
  padding: 16px 0 8px;
  border-top: 1px solid #E9ECEF;
  margin-top: 16px;
}

.pagination-wrapper :deep(.ant-pagination) {
  display: flex;
  align-items: center;
  gap: 4px;
}

.pagination-wrapper :deep(.ant-pagination-item) {
  border-radius: 5px;
  font-size: 13px;
  min-width: 30px;
  height: 30px;
  line-height: 30px;
  border: 1px solid #DEE2E6;
  transition: all 0.15s ease;
}

.pagination-wrapper :deep(.ant-pagination-item:hover) {
  border-color: #ADB5BD;
}

.pagination-wrapper :deep(.ant-pagination-item-active) {
  background: #212529;
  border-color: #212529;
}

.pagination-wrapper :deep(.ant-pagination-item-active a) {
  color: #FFFFFF;
}

.pagination-wrapper :deep(.ant-pagination-prev),
.pagination-wrapper :deep(.ant-pagination-next) {
  min-width: 30px;
  height: 30px;
  line-height: 30px;
  border-radius: 5px;
  border: 1px solid #DEE2E6;
  transition: all 0.15s ease;
}

.pagination-wrapper :deep(.ant-pagination-prev:hover),
.pagination-wrapper :deep(.ant-pagination-next:hover) {
  border-color: #212529;
  color: #212529;
}

.pagination-wrapper :deep(.ant-pagination-disabled) {
  opacity: 0.35;
}

.pagination-wrapper :deep(.ant-pagination-total-text) {
  font-size: 13px;
  color: #6C757D;
  margin-right: 8px;
}
</style>
