﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿﻿<template>
  <div class="manage-page">
    <TabsBar
      :tabs="manageModuleTabs"
      v-model="activeTab"
    />

      <div v-show="activeTab === 'oa' && canShowOA" class="manage-content">
          <div class="exam-header">
            <div class="header-left">
              <h1 class="page-title">OA系统深度对接</h1>
              <p class="page-desc">与OA系统进行数据同步和集成</p>
            </div>
            <div class="header-right">
              <a-badge 
                :status="isSSOConnected ? 'success' : 'default'" 
                :text="isSSOConnected ? '已连接' : '未连接'"
              />
              <a-button 
                :type="isSSOConnected ? 'default' : 'primary'"
                class="btn"
                :class="isSSOConnected ? '' : 'btn-primary'"
                @click="handleSSOLogin"
                :disabled="isSyncing"
              >
                <template #icon><SyncOutlined :spin="isSyncing" /></template>
                {{ isSSOConnected ? '断开连接' : 'SSO登录' }}
              </a-button>
            </div>
          </div>

          <div v-if="isSyncing" class="progress-container">
            <div class="progress-header">
              <span class="progress-status">{{ syncStatus }}</span>
              <span>{{ syncProgress.toFixed(0) }}%</span>
            </div>
            <div class="progress-bar">
              <div class="progress-fill" :style="{ width: `${syncProgress}%` }"></div>
            </div>
          </div>

          <div class="card-row">
            <div class="exam-card" style="flex: 1;">
              <div class="card-title">
                <span>对接配置</span>
              </div>
              <a-form layout="vertical">
                <a-form-item label="接口地址">
                  <a-input 
                    placeholder="请输入OA系统接口地址" 
                    :value="'https://oa.company.com/api/v1'"
                    :disabled="!isSSOConnected"
                    class="form-input"
                  />
                </a-form-item>
                <a-form-item label="认证方式">
                  <select 
                    :value="'token'" 
                    :disabled="!isSSOConnected"
                    class="form-select"
                  >
                    <option value="token">Token认证</option>
                    <option value="basic">Basic认证</option>
                    <option value="oauth">OAuth2.0</option>
                  </select>
                </a-form-item>
                <a-form-item label="同步策略">
                  <select 
                    :value="'realtime'" 
                    :disabled="!isSSOConnected"
                    class="form-select"
                  >
                    <option value="realtime">实时同步</option>
                    <option value="定时">定时同步</option>
                  </select>
                </a-form-item>
                <a-form-item>
                  <a-button 
                    type="primary" 
                    class="btn btn-primary"
                    :disabled="!isSSOConnected || isSyncing"
                    @click="handleSimulateSync"
                  >
                    {{ isSyncing ? '同步中...' : '立即同步' }}
                  </a-button>
                  <a-button 
                    class="btn"
                    style="margin-left: 8px;"
                    :disabled="!isSSOConnected"
                    @click="message.success('配置保存成功！')"
                  >
                    保存配置
                  </a-button>
                </a-form-item>
              </a-form>
            </div>

            <div class="card-col" style="flex: 2;">
              <div class="exam-card">
                <div class="card-title">
                  <span>同步日志</span>
                </div>
                <a-table
                  :dataSource="syncLogs"
                  size="small"
                  :pagination="{ pageSize: 4 }"
                  :columns="syncLogColumns"
                >
                  <template #bodyCell="{ column, record }">
                    <template v-if="column.key === 'type'">
                      <a-tag>{{ typeMap[record.type] || record.type }}</a-tag>
                    </template>
                    <template v-else-if="column.key === 'status'">
                      <a-badge 
                        :status="record.status === 'success' ? 'success' : 'error'" 
                        :text="record.status === 'success' ? '成功' : '失败'"
                      />
                    </template>
                    <template v-else-if="column.key === 'action'">
                      <div class="action-buttons">
                        <a-button type="link" size="small" @click="handleViewSyncDetail(record)">详情</a-button>
                        <a-button v-if="record.status === 'failed'" type="link" danger size="small" @click="handleRetrySync(record)">重试</a-button>
                      </div>
                    </template>
                  </template>
                </a-table>
              </div>

              <div class="exam-card">
                <div class="card-title">
                  <span>反馈工单</span>
                </div>
                <a-table
                  :dataSource="feedbackTickets"
                  size="small"
                  :pagination="{ pageSize: 4 }"
                  :columns="feedbackTicketColumns"
                >
                  <template #bodyCell="{ column, record }">
                    <template v-if="column.key === 'status'">
                      <a-tag :color="statusMap[record.status]?.color">{{ statusMap[record.status]?.text }}</a-tag>
                    </template>
                    <template v-else-if="column.key === 'action'">
                      <div class="action-buttons">
                        <a-button type="link" size="small" @click="handleViewTicketDetail(record)">查看</a-button>
                        <a-button v-if="record.status !== 'resolved'" type="link" size="small" @click="handleProcessTicket(record)">
                          <template #icon><EditOutlined /></template>
                          处理
                        </a-button>
                      </div>
                    </template>
                  </template>
                </a-table>
              </div>
            </div>
          </div>
        </div>

      <div v-show="activeTab === 'kb' && canShowKB" class="manage-content kb-manage-content">
          <div class="exam-header kb-header">
            <div class="header-left">
              <h1 class="page-title">知识库管理</h1>
              <p class="page-desc">创建向量库、管理文档、一键向量化</p>
            </div>
            <div class="header-right kb-header-right">
              <a-button type="primary" class="btn btn-primary btn-create" @click="openCreateModal" :disabled="kbLoading">
                <template #icon><PlusOutlined /></template>
                新建知识库
              </a-button>
            </div>
          </div>

          <div class="kb-statistics">
            <div class="stat-card">
              <div class="stat-icon total">
                <DatabaseOutlined />
              </div>
              <div class="stat-content">
                <div class="stat-value">{{ collections.length }}</div>
                <div class="stat-label">知识库数量</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon docs">
                <FileTextOutlined />
              </div>
              <div class="stat-content">
                <div class="stat-value">{{ totalDocumentCount }}</div>
                <div class="stat-label">总文档数</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon public">
                <BookOutlined />
              </div>
              <div class="stat-content">
                <div class="stat-value">{{ publicCollectionCount }}</div>
                <div class="stat-label">公开知识库</div>
              </div>
            </div>
          </div>

          <div v-if="kbLoading && !collections.length" class="kb-loading-skeleton">
            <div v-for="i in 6" :key="i" class="kb-card-skeleton"></div>
          </div>

          <div v-else-if="!kbLoading && !collections.length" class="empty-state kb-empty-state">
            <template v-if="!ragServiceAvailable">
              <div class="empty-icon warning">
                <WarningOutlined />
              </div>
              <h3>RAG知识库服务未启动</h3>
              <p>请先启动RAG服务（端口5001）后再使用知识库管理功能</p>
              <a-button type="primary" @click="loadCollections">
                <template #icon><ReloadOutlined /></template>
                重新连接
              </a-button>
            </template>
            <template v-else>
              <div class="empty-icon">
                <DatabaseOutlined />
              </div>
              <h3>暂无知识库</h3>
              <p>创建您的第一个知识库，开始构建企业知识大脑</p>
              <a-button type="primary" @click="openCreateModal">
                <template #icon><PlusOutlined /></template>
                创建知识库
              </a-button>
            </template>
          </div>

          <div v-else class="kb-main-layout">
            <div class="kb-list-section">
              <div class="kb-toolbar">
                <span class="kb-count-label">共 {{ collections.length }} 个知识库</span>
                <div class="toolbar-right">
                  <a-input-search placeholder="搜索知识库名称..." v-model:value="kbSearchQuery" style="width:220px;" allow-clear @search="handleKBSearch" />
                </div>
              </div>
              <div class="kb-card-grid">
                <div 
                  v-for="collection in paginatedCollections" 
                  :key="collection.name"
                  class="kb-collection-card"
                  :class="{ active: selectedCollection?.name === collection.name }"
                  @click="selectCollection(collection)"
                >
                  <div class="card-header">
                    <div class="card-icon" :class="collection.visibility === 'public' ? 'public' : 'private'">
                      <DatabaseOutlined />
                    </div>
                    <div class="card-status-tags">
                      <a-tag :color="collection.visibility === 'public' ? 'green' : 'blue'" size="small">
                        {{ collection.visibility === 'public' ? '公开' : '私密' }}
                      </a-tag>
                    </div>
                  </div>
                  <div class="card-body">
                    <h4 class="card-title">{{ collection.displayName || collection.name }}</h4>
                    <p class="card-subtitle">{{ collection.name }}</p>
                    <p class="card-desc" v-if="collection.description">{{ collection.description }}</p>
                  </div>
                  <div class="card-footer">
                    <div class="card-meta">
                      <div class="meta-item">
                        <FileTextOutlined />
                        <span>{{ collection.documentCount || 0 }} 文档</span>
                      </div>
                      <div class="meta-item" v-if="collection.fileSize">
                        <HddOutlined />
                        <span>{{ formatFileSize(collection.fileSize) }}</span>
                      </div>
                    </div>
                    <div class="card-actions">
                      <a-tooltip title="管理文档">
                        <span class="action-btn" @click.stop="openDocuments(collection)">
                          <FileTextOutlined />
                        </span>
                      </a-tooltip>
                      <a-tooltip title="编辑信息">
                        <span class="action-btn" @click.stop="editCollectionInfo(collection)">
                          <EditOutlined />
                        </span>
                      </a-tooltip>
                      <a-popconfirm title="确定删除此知识库？删除后数据无法恢复" @confirm.stop="deleteCollection(collection)">
                        <a-tooltip title="删除">
                          <span class="action-btn danger">
                            <DeleteOutlined />
                          </span>
                        </a-tooltip>
                      </a-popconfirm>
                    </div>
                  </div>
                </div>
              </div>
              <!-- 分页组件 -->
              <div v-if="kbTotalPages > 1" class="kb-pagination">
                <a-pagination
                  v-model:current="kbCurrentPage"
                  :total="filteredCollections.length"
                  :page-size="kbPageSize"
                  :show-size-changer="false"
                  :show-quick-jumper="false"
                  show-total
                  @change="handlePageChange"
                />
              </div>
            </div>

            <div v-if="selectedCollection" class="kb-detail-panel">
              <div class="detail-panel-header">
                <div class="panel-title">
                  <div class="panel-icon">
                    <DatabaseOutlined />
                  </div>
                  <div>
                    <h3>{{ selectedCollection.displayName || selectedCollection.name }}</h3>
                    <p>{{ selectedCollection.name }}</p>
                  </div>
                </div>
                <a-button type="text" size="small" @click="selectedCollection = null">
                  <CloseOutlined />
                </a-button>
              </div>

              <a-tabs v-model:activeKey="kbDetailTab" size="small" class="kb-detail-tabs">
                <a-tab-pane key="info" tab="基本信息">
                  <div class="detail-form-section">
                    <a-form layout="vertical" size="small">
                      <a-row :gutter="16">
                        <a-col :span="12">
                          <a-form-item label="显示名称">
                            <a-input v-model:value="editForm.displayName" placeholder="输入显示名称" />
                          </a-form-item>
                        </a-col>
                        <a-col :span="12">
                          <a-form-item label="所属部门">
                            <a-select v-model:value="editForm.department" allow-clear placeholder="请选择部门">
                              <a-select-option v-for="dept in departmentList" :key="dept.id || dept.deptId" :value="dept.name || dept.deptName">
                                {{ dept.name || dept.deptName }}
                              </a-select-option>
                            </a-select>
                          </a-form-item>
                        </a-col>
                      </a-row>
                      <a-form-item label="描述信息">
                        <a-textarea v-model:value="editForm.description" :rows="3" placeholder="输入知识库描述" />
                      </a-form-item>
                      <a-form-item>
                        <a-space>
                          <a-button type="primary" size="small" @click="updateCollection" :loading="kbActionLoading">
                            <template #icon><SaveOutlined /></template>
                            保存修改
                          </a-button>
                        </a-space>
                      </a-form-item>
                    </a-form>
                    <div class="detail-meta-info">
                      <div class="meta-row">
                        <span class="meta-label">类型：</span>
                        <a-tag :color="editForm.ownerType === 'department' ? 'blue' : 'purple'">
                          {{ editForm.ownerType === 'department' ? '部门知识库' : '个人知识库' }}
                        </a-tag>
                      </div>
                      <div class="meta-row">
                        <span class="meta-label">可见性：</span>
                        <a-tag :color="editForm.visibility === 'public' ? 'green' : 'orange'">
                          {{ editForm.visibility === 'public' ? '公开可访问' : '仅自己可见' }}
                        </a-tag>
                      </div>
                      <div class="meta-row" v-if="editForm.createTime">
                        <span class="meta-label">创建时间：</span>
                        <span>{{ editForm.createTime }}</span>
                      </div>
                      <div class="meta-row">
                        <span class="meta-label">文档数量：</span>
                        <span class="highlight">{{ selectedCollection.documentCount || 0 }}</span>
                      </div>
                    </div>
                  </div>
                </a-tab-pane>

                <a-tab-pane key="documents" tab="文档管理" force-render>
                  <div class="doc-toolbar">
                    <a-space>
                      <a-button type="primary" size="small" @click="loadDocuments" :loading="docLoading">
                        <template #icon><ReloadOutlined /></template>
                        刷新文档
                      </a-button>
                      <a-upload action="#" :max-count="1" accept=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt,.md,.csv,.json,.xml,.html,.jpg,.jpeg,.png,.gif,.webp,.bmp,.svg,.epub,.rtf" :before-upload="() => false" @change="handleDocUpload">
                        <a-button size="small">
                          <template #icon><UploadOutlined /></template>
                          上传文档
                        </a-button>
                      </a-upload>
                    </a-space>
                    <a-space>
                      <a-button size="small" @click="openBatchVectorize" type="default">
                        <template #icon><ThunderboltOutlined /></template>
                        批量向量化
                      </a-button>
                    </a-space>
                  </div>
                  <a-table 
                    :dataSource="documents" 
                    :columns="documentColumns" 
                    :pagination="{ pageSize: 8, size: 'small' }" 
                    :row-key="(r) => r.path || r.document_id" 
                    :loading="docLoading" 
                    size="small" 
                    :locale="{ emptyText: '该知识库暂无文档，请上传文档后进行向量化' }"
                  >
                    <template #bodyCell="{ column, record }">
                      <template v-if="column.key === 'name'">
                        <div class="doc-name-cell">
                          <span class="doc-icon" :class="getFileIconClass(record)">
                            <FileTextOutlined v-if="!record.metadata?.filename?.match(/\.(pdf|doc|docx|txt|md)$/)" />
                            <FilePdfOutlined v-else-if="record.metadata?.filename?.includes('.pdf')" />
                            <FileWordOutlined v-else-if="record.metadata?.filename?.match(/\.docx?$/) " />
                            <FileTextOutlined v-else />
                          </span>
                          <div class="doc-text">
                            <span class="doc-title">{{ record.metadata?.filename || record.path || '未命名文档' }}</span>
                            <span class="doc-path" v-if="record.path">{{ record.path }}</span>
                          </div>
                        </div>
                      </template>
                      <template v-else-if="column.key === 'status'">
                        <a-tag v-if="record.status === 'active'" color="success">生效中</a-tag>
                        <a-tag v-else-if="record.status === 'deprecated'" color="error">已废止</a-tag>
                        <a-tag v-else-if="record.status === 'draft'" color="default">草稿</a-tag>
                        <a-tag v-else color="processing">{{ record.status }}</a-tag>
                      </template>
                      <template v-else-if="column.key === 'action'">
                        <a-space size="small">
                          <a-tooltip title="查看切片"><a-button type="link" size="small" @click="viewDocumentChunks(record)"><EyeOutlined /></a-button></a-tooltip>
                          <a-tooltip title="向量化"><a-button type="link" size="small" @click="vectorizeSingleDocument(record)"><ThunderboltOutlined /></a-button></a-tooltip>
                          <a-dropdown>
                            <a-button type="link" size="small">更多</a-button>
                            <template #overlay>
                              <a-menu>
                                <a-menu-item @click="viewDocumentVersions(record)"><HistoryOutlined /> 版本历史</a-menu-item>
                                <a-menu-item @click="deprecateDocument(record)"><StopOutlined /> 废止文档</a-menu-item>
                                <a-menu-item @click="restoreDocument(record)"><UndoOutlined /> 恢复文档</a-menu-item>
                                <a-menu-divider />
                                <a-menu-item danger @click="deleteDocument(record)"><DeleteOutlined /> 删除文档</a-menu-item>
                              </a-menu>
                            </template>
                          </a-dropdown>
                        </a-space>
                      </template>
                    </template>
                  </a-table>
                </a-tab-pane>

                <a-tab-pane key="vectorize" tab="文件向量化">
                  <div class="vectorize-section">
                    <a-alert message="将已上传到服务器的文件解析并存储到当前选中的向量库中。文件需先通过文件管理模块上传。" type="info" show-icon :closable="false" style="margin-bottom:16px;" />
                    
                    <div class="vectorize-toolbar">
                      <a-select 
                        v-model:value="vectorizeFileId" 
                        style="width:280px;" 
                        placeholder="选择要向量化的文件ID" 
                        allow-clear 
                        show-search 
                        :filter-option="false" 
                        :options="vectorizeFileOptions" 
                      />
                      <a-button type="primary" size="small" @click="vectorizeSingle" :disabled="!vectorizeFileId" :loading="vectorizing">
                        <template #icon><ThunderboltOutlined /></template>
                        单文件向量化
                      </a-button>
                      <a-button size="small" @click="openBatchVectorize">
                        <template #icon><ClusterOutlined /></template>
                        批量向量化
                      </a-button>
                    </div>

                    <div v-if="vectorizeResult" class="vectorize-result" :class="vectorizeResult.success ? 'success' : 'error'">
                      <CheckCircleOutlined v-if="vectorizeResult.success" class="result-icon success" />
                      <CloseCircleOutlined v-else class="result-icon error" />
                      <div class="result-content">
                        <strong>{{ vectorizeResult.success ? '向量化成功' : '向量化失败' }}</strong>
                        <p>{{ vectorizeResult.message }}</p>
                        <span v-if="vectorizeResult.chunkCount">共生成 {{ vectorizeResult.chunkCount }} 个切片</span>
                      </div>
                    </div>
                  </div>
                </a-tab-pane>

                <a-tab-pane key="chunks" tab="切片查看" force-render>
                  <div class="chunks-section">
                    <div class="chunks-toolbar">
                      <a-button size="small" @click="loadChunks" :loading="chunkLoading">
                        <template #icon><ReloadOutlined /></template>
                        加载切片
                      </a-button>
                      <span class="chunks-total">共 {{ chunkTotal }} 个切片</span>
                    </div>
                    <a-table 
                      :dataSource="chunks" 
                      :columns="chunkColumns" 
                      :pagination="{ pageSize: 6, size: 'small' }" 
                      :row-key="(r) => r.id" 
                      :loading="chunkLoading" 
                      size="small" 
                      :locale="{ emptyText: '暂无切片数据' }"
                    >
                      <template #bodyCell="{ column, record }">
                        <template v-if="column.key === 'content'">
                          <div class="chunk-content-preview">{{ record.content?.substring(0, 200) }}{{ record.content?.length > 200 ? '...' : '' }}</div>
                        </template>
                      </template>
                    </a-table>
                  </div>
                </a-tab-pane>
              </a-tabs>
            </div>
          </div>
        </div>

      <a-modal
        v-model:open="showCreateModal"
        title="创建新知识库"
        :width="520"
        :confirm-loading="kbActionLoading"
        @ok="createCollection"
        ok-text="确认创建"
        cancel-text="取消"
      >
        <div class="create-kb-form">
          <a-alert message="知识库名称用于系统内部标识，显示名称用于前端展示。创建后可在基本信息中修改。" type="info" show-icon :closable="false" style="margin-bottom:16px;" />
          <a-form layout="vertical">
            <a-form-item label="知识库名称" required>
              <a-input v-model:value="createForm.name" placeholder="例如：public_kb、hr_policy_kb（仅英文、数字、下划线）" />
            </a-form-item>
            <a-form-item label="显示名称" required>
              <a-input v-model:value="createForm.displayName" placeholder="例如：公开知识库、人事政策库" />
            </a-form-item>
            <a-form-item label="所属部门">
              <a-select v-model:value="createForm.department" placeholder="请选择所属部门" allow-clear>
                <a-select-option value="" disabled>请选择部门</a-select-option>
                <a-select-option v-for="dept in departmentList" :key="dept.id || dept.deptId" :value="dept.name || dept.deptName">
                  {{ dept.name || dept.deptName }}
                </a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item label="描述信息">
              <a-textarea v-model:value="createForm.description" placeholder="输入知识库的用途和说明..." :rows="3" />
            </a-form-item>
          </a-form>
        </div>
      </a-modal>

      <div v-show="activeTab === 'exam' && canShowExam" class="manage-content">
          <div class="exam-header">
            <div class="header-left">
              <h1 class="page-title">题库智能维护</h1>
              <p class="page-desc">扫描受影响题目，AI智能生成新题</p>
            </div>
          </div>

          <div v-if="isScanningQuestions" class="progress-container scan-progress">
            <div class="progress-header">
              <span class="progress-status">{{ scanStatus }}</span>
              <span>{{ scanProgress }}%</span>
            </div>
            <a-progress 
              :percent="scanProgress" 
              status="active" 
              stroke-color="#52c41a"
            />
            <div class="progress-icon">
              <ScanOutlined spin />
            </div>
          </div>

          <div v-if="isGeneratingQuestions" class="progress-container generate-progress">
            <div class="progress-header">
              <span class="progress-status">{{ generateStatus }}</span>
              <span>{{ generateProgress }}%</span>
            </div>
            <a-progress 
              :percent="generateProgress" 
              status="active" 
              stroke-color="#fa8c16"
            />
            <div class="progress-icon">
              <RobotOutlined spin />
            </div>
          </div>

          <div class="action-bar">
            <a-button
              type="primary"
              class="btn btn-primary"
              @click="handleScanQuestions"
              :disabled="isScanningQuestions || isGeneratingQuestions"
            >
              <template #icon><ScanOutlined /></template>
              {{ isScanningQuestions ? '扫描中...' : '扫描受影响题目' }}
            </a-button>
            <a-button
              class="btn btn-success"
              style="margin-left: 16px;"
              @click="handleGenerateQuestions"
              :disabled="isGeneratingQuestions || isScanningQuestions"
            >
              <template #icon><RobotOutlined /></template>
              {{ isGeneratingQuestions ? '生成中...' : '生成新题' }}
            </a-button>
            <a-button
              type="default"
              class="btn btn-info"
              style="margin-left: 16px;"
              @click="showGradeModal = true"
              :disabled="isGradingExam"
            >
              <template #icon><CheckCircleOutlined /></template>
              {{ isGradingExam ? '评分中...' : '智能评分' }}
            </a-button>
          </div>

          <div class="card-row">
            <div class="exam-card" style="flex: 1;">
              <div class="card-title">
                <span>受影响题目</span>
              </div>
              <a-table
                :dataSource="affectedQuestions"
                :columns="affectedQuestionColumns"
                :pagination="false"
              >
                <template #bodyCell="{ column, record }">
                  <template v-if="column.key === 'status'">
                    <a-badge status="warning" text="待审核" />
                  </template>
                  <template v-else-if="column.key === 'action'">
                    <a-button class="btn btn-small" @click="handleViewQuestionDetail(record)">查看</a-button>
                  </template>
                </template>
              </a-table>
            </div>

            <div class="exam-card" style="flex: 1;">
              <div class="card-title">
                <span>AI生成题目</span>
              </div>
              <div v-if="aiGeneratedQuestions.length > 0">
                <div v-for="question in aiGeneratedQuestions" :key="question.id" class="question-card">
                  <h5>{{ question.type === 'single' ? '单选题' : '判断题' }}</h5>
                  <p>{{ question.content }}</p>
                  <div class="question-options">
                    <div v-for="(option, index) in question.options" :key="index">
                      <input type="radio" :name="`q${question.id}`" />
                      {{ ' ' }}{{ option }}
                    </div>
                  </div>
                  <div class="question-answer">
                    <strong>答案：{{ question.answer }}</strong>
                  </div>
                  <div class="question-analysis">
                    <strong>解析：</strong>{{ question.analysis }}
                  </div>
                  <div class="question-actions">
                    <a-button class="btn btn-primary btn-small" @click="handleAcceptQuestion(question)">采纳</a-button>
                    <a-button class="btn btn-small" @click="handleEditQuestion(question)">修改</a-button>
                    <a-button class="btn btn-danger btn-small" @click="handleRejectQuestion(question)">拒绝</a-button>
                  </div>
                </div>
              </div>
              <div v-else class="empty-state">
                <p>暂无AI生成题目</p>
              </div>
            </div>
          </div>
        </div>

    <a-modal
      title="AI智能评分"
      v-model:open="showGradeModal"
      @ok="handleGradeExam"
      @cancel="resetGradeForm"
      :confirmLoading="isGradingExam"
      width="700px"
    >
      <a-alert
        message="智能评分说明"
        description="输入学生答案，AI将根据标准答案和评分标准进行自动评分，并提供详细的反馈和建议。"
        type="info"
        show-icon
        style="margin-bottom: 16px;"
      />
      <a-form layout="vertical">
        <a-form-item label="考试ID（可选）">
          <a-input v-model:value="gradeForm.examId" placeholder="留空则自动生成" class="form-input" />
        </a-form-item>
        <a-form-item label="学生答案" required>
          <a-textarea
            v-model:value="gradeForm.studentAnswers"
            placeholder="请输入学生的答案内容..."
            :rows="6"
            class="form-input"
          />
          <div style="font-size: 12px; color: #999; margin-top: 4px;">
            支持多道题目的答案，每题答案用换行分隔
          </div>
        </a-form-item>
        <a-form-item label="评分标准">
          <a-select v-model:value="gradeForm.gradingCriteria" style="width: 100%;">
            <a-select-option value="accuracy_completeness">准确性和完整性</a-select-option>
            <a-select-option value="keyword_matching">关键词匹配</a-select-option>
            <a-select-option value="semantic_similarity">语义相似度</a-select-option>
            <a-select-option value="comprehensive">综合评估</a-select-option>
          </a-select>
        </a-form-item>
      </a-form>

      <div v-if="gradeResult" style="margin-top: 16px; padding: 16px; background: #f6ffed; border-radius: 8px; border: 1px solid #b7eb8f;">
        <h4 style="margin: 0 0 12px 0; color: #52c41a;">
          <CheckCircleOutlined /> 评分结果：{{ gradeResult.totalScore }} / {{ gradeResult.maxScore }} 分
        </h4>
        <div v-if="gradeResult.feedback" style="margin-bottom: 8px;">
          <strong>总体反馈：</strong>{{ gradeResult.feedback }}
        </div>
        <div v-if="gradeResult.questionResults.length > 0" style="margin-top: 8px;">
          <strong>各题得分：</strong>
          <a-table
            :dataSource="gradeResult.questionResults"
            :columns="[
              { title: '题目', dataIndex: 'question_id', key: 'question_id' },
              { title: '得分', dataIndex: 'score', key: 'score' },
              { title: '满分', dataIndex: 'max_score', key: 'max_score' },
              { title: '评语', dataIndex: 'comment', key: 'comment', ellipsis: true }
            ]"
            :pagination="false"
            size="small"
            :row-key="(r) => r.question_id"
          />
        </div>
        <div v-if="gradeResult.suggestions.length > 0" style="margin-top: 8px;">
          <strong>改进建议：</strong>
          <ul style="margin: 4px 0 0 20px; padding: 0;">
            <li v-for="(suggestion, index) in gradeResult.suggestions" :key="index">{{ suggestion }}</li>
          </ul>
        </div>
      </div>
    </a-modal>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import {
  FolderOutlined,
  FileTextOutlined,
  SyncOutlined,
  DatabaseOutlined,
  BookOutlined,
  UploadOutlined,
  DiffOutlined,
  RollbackOutlined,
  SettingOutlined,
  EyeOutlined,
  CheckOutlined,
  ArrowLeftOutlined,
  FileUnknownOutlined,
  SwapOutlined,
  CloseOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
  RotateLeftOutlined,
  RotateRightOutlined,
  EditOutlined,
  ScanOutlined,
  RobotOutlined,
  ClockCircleOutlined,
  PlusOutlined,
  CheckCircleOutlined,
  WarningOutlined,
  ReloadOutlined,
  SaveOutlined,
  DeleteOutlined,
  HddOutlined,
  HistoryOutlined,
  StopOutlined,
  UndoOutlined,
  CloseCircleOutlined,
  ThunderboltOutlined,
  ClusterOutlined,
  FilePdfOutlined,
  FileWordOutlined
} from '@ant-design/icons-vue'
import { getDirectPermission } from '../utils/permission.js'
import { ragAPI } from '../api/rag.js'
import { departmentAPI } from '../api/auth.js'
import { fileAPI } from '../api/file.js'
import TabsBar from './common/TabsBar.vue'
import PageHeader from './common/PageHeader.vue'

const activeTab = ref('kb')

const canShowOA = computed(() =>
  getDirectPermission('manage:sync')
)
const canShowKB = computed(() =>
  getDirectPermission('manage:sync')
)
const canShowExam = computed(() =>
  getDirectPermission('manage:question')
)

const manageModuleTabs = computed(() => {
  const tabs = []
  if (canShowKB.value) {
    tabs.push({ key: 'kb', label: '知识库', icon: '<BookOutlined />' })
  }
  return tabs
})

const getFirstAccessibleTab = () => {
  if (canShowKB.value) return 'kb'
  return null
}

watch(
  [canShowOA, canShowKB, canShowExam],
  () => {
    const hasAccess =
      (activeTab.value === 'oa' && canShowOA.value) ||
      (activeTab.value === 'kb' && canShowKB.value) ||
      (activeTab.value === 'exam' && canShowExam.value)

    if (!hasAccess) {
      const firstTab = getFirstAccessibleTab()
      if (firstTab) {
        activeTab.value = firstTab
      }
    }
  },
  { immediate: true }
)

onMounted(() => {
  const firstTab = getFirstAccessibleTab()
  if (firstTab) {
    activeTab.value = firstTab
  }
  if (canShowKB.value) {
    loadCollections()
    fetchDepartments()
  }
})

const isSyncing = ref(false)
const syncProgress = ref(0)
const syncStatus = ref('')
const isSSOConnected = ref(false)
const isKBSyncing = ref(false)
const kbSyncProgress = ref(0)
const kbSyncStatus = ref('')
const kbLoading = ref(false)
const ragServiceAvailable = ref(true)
const collections = ref([])
const selectedCollection = ref(null)
const kbDetailTab = ref('info')
const kbSearchQuery = ref('')
const showCreateModal = ref(false)
const kbActionLoading = ref(false)

// 分页相关状态
const kbCurrentPage = ref(1)
const kbPageSize = ref(6) // 每页显示6个知识库（2列x3行）

const createForm = reactive({ name: '', displayName: '', department: '', description: '', ownerType: 'department', visibility: 'public' })
const editForm = reactive({ name: '', displayName: '', department: '', description: '', ownerType: '', visibility: '', createTime: '' })

// 部门列表
const departmentList = ref([])

const fetchDepartments = async () => {
  try {
    const response = await departmentAPI.getDepartments()
    if (response.data.code === 200 && Array.isArray(response.data.data)) {
      departmentList.value = response.data.data
    }
  } catch (error) {
    console.warn('获取部门列表失败:', error.message)
  }
}

const documents = ref([])
const docLoading = ref(false)
const chunks = ref([])
const chunkTotal = ref(0)
const chunkLoading = ref(false)
const vectorizeFileId = ref(null)
const vectorizing = ref(false)
const vectorizeResult = ref(null)
const showBatchVectorize = ref(false)
const batchSelectedFiles = ref([])
const selectedDocumentForVersions = ref(null)
const showVersionModal = ref(false)
const documentVersions = ref([])
const kbPaths = ref([])
const kbPathLoading = ref(false)
const kbPathSearchQuery = ref('')
const selectedKBPathDetail = ref(null)
const showKBPathDetailModal = ref(false)
const isScanningQuestions = ref(false)
const scanProgress = ref(0)
const scanStatus = ref('')
const isGeneratingQuestions = ref(false)
const generateProgress = ref(0)
const generateStatus = ref('')

const isGradingExam = ref(false)
const showGradeModal = ref(false)
const gradeResult = ref(null)
const gradeForm = ref({
  examId: '',
  studentAnswers: '',
  gradingCriteria: 'accuracy_completeness'
})

const aiGeneratedQuestions = ref([])

const syncLogs = ref([])
const feedbackTickets = ref([])
const kbSyncs = ref([])
const affectedQuestions = ref([])

const typeMap = {
  document: '制度文件',
  user: '用户数据',
  org: '组织架构'
}

const statusMap = {
  pending: { color: 'orange', text: '待处理' },
  processing: { color: 'blue', text: '处理中' },
  resolved: { color: 'green', text: '已解决' }
}

const syncLogColumns = [
  { title: '同步时间', dataIndex: 'time', key: 'time', width: 160 },
  { title: '同步类型', dataIndex: 'type', key: 'type', width: 100 },
  { title: '同步内容', dataIndex: 'content', key: 'content' },
  { title: '数量', dataIndex: 'count', key: 'count', width: 80 },
  { title: '状态', dataIndex: 'status', key: 'status', width: 80 },
  { title: '操作', key: 'action', width: 120 },
]

const feedbackTicketColumns = [
  { title: '工单编号', dataIndex: 'id', key: 'id', width: 100 },
  { title: '关联制度', dataIndex: 'doc', key: 'doc', width: 140 },
  { title: '反馈内容', dataIndex: 'content', key: 'content' },
  { title: '状态', dataIndex: 'status', key: 'status', width: 100 },
  { title: '反馈时间', dataIndex: 'time', key: 'time', width: 160 },
  { title: '操作', key: 'action', width: 140 },
]

const collectionColumns = [
  { title: '向量库名称', key: 'name', width: 220 },
  { title: '所属部门', key: 'department', width: 100 },
  { title: '所有者类型', key: 'ownerType', width: 100 },
  { title: '可见性', key: 'visibility', width: 80 },
  { title: '文档数', key: 'documentCount', width: 80 },
  { title: '操作', key: 'action', width: 150 }
]

const documentColumns = [
  { title: '文件名', dataIndex: ['metadata', 'filename'], key: 'name', ellipsis: true },
  { title: '路径', dataIndex: 'path', key: 'path', ellipsis: true },
  { title: '大小', dataIndex: ['metadata', 'size'], key: 'size' },
  { title: '状态', dataIndex: 'status', key: 'status' },
  { title: '操作', key: 'action', width: 200 }
]

const chunkColumns = [
  { title: 'ID', dataIndex: 'id', key: 'id', width: 80 },
  { title: '内容', key: 'content' },
  { title: '元数据', key: 'metadata', width: 150 },
  { title: '来源', dataIndex: ['metadata', 'source'], key: 'source', width: 120 }
]

const kbPathColumns = [
  { title: '知识库名称', key: 'name', width: 200 },
  { title: '所属部门', key: 'department', width: 100 },
  { title: '所有者类型', key: 'ownerType', width: 100 },
  { title: '可见性', key: 'visibility', width: 80 },
  { title: '同步状态', key: 'syncStatus', width: 100 },
  { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 160 },
  { title: '操作', key: 'action', width: 80 }
]

const affectedQuestionColumns = [
  { title: '题目ID', dataIndex: 'id', key: 'id' },
  { title: '题目内容', dataIndex: 'content', key: 'content' },
  { title: '关联制度', dataIndex: 'doc', key: 'doc' },
  { title: '原版本', dataIndex: 'version', key: 'version' },
  { title: '状态', dataIndex: 'status', key: 'status' },
  { title: '操作', key: 'action', width: 80 },
]

const handleSimulateSync = async () => {
  isSyncing.value = true
  syncProgress.value = 10
  syncStatus.value = '正在触发RAG服务同步...'

  try {
    syncProgress.value = 30
    const result = await ragAPI.triggerSync()
    syncProgress.value = 80

    if (result) {
      syncLogs.value.unshift({
        id: Date.now(),
        time: new Date().toLocaleString('zh-CN'),
        content: `RAG知识库同步 - 新增${result.result?.added || 0}，更新${result.result?.updated || 0}，删除${result.result?.deleted || 0}`,
        status: 'success',
        type: 'document',
        count: (result.result?.added || 0) + (result.result?.updated || 0)
      })
      syncProgress.value = 100
      message.success('同步完成！')
    }
  } catch (error) {
    console.error('同步失败:', error)
    syncLogs.value.unshift({
      id: Date.now(),
      time: new Date().toLocaleString('zh-CN'),
      content: 'RAG知识库同步失败',
      status: 'failed',
      type: 'document',
      count: 0,
      error: error.message
    })
    message.error('同步失败: ' + (error.message || '请检查网络或确认RAG服务已启动'))
  } finally {
    setTimeout(() => {
      isSyncing.value = false
      syncStatus.value = ''
    }, 500)
  }
}

const handleSSOLogin = () => {
  if (isSSOConnected.value) {
    isSSOConnected.value = false
  } else {
    syncStatus.value = '正在连接OA系统...'
    setTimeout(() => {
      isSSOConnected.value = true
      syncStatus.value = ''
    }, 1500)
  }
}

const handleViewSyncDetail = (record) => {
  console.log('查看同步日志详情:', record)
}

const handleRetrySync = (record) => {
  console.log('重试同步:', record)
  handleSimulateSync()
  message.success(`正在重试同步: ${record.content}`)
}

const handleViewTicketDetail = (record) => {
  console.log('查看反馈工单详情:', record)
}

const handleProcessTicket = (record) => {
  console.log('处理反馈工单:', record)
  message.success('工单已标记为处理中')
}

const filteredCollections = computed(() => {
  if (!kbSearchQuery.value) return collections.value
  const q = kbSearchQuery.value.toLowerCase()
  return collections.value.filter(c => (c.displayName || c.name || '').toLowerCase().includes(q))
})

// 当前页显示的知识库
const paginatedCollections = computed(() => {
  const start = (kbCurrentPage.value - 1) * kbPageSize.value
  const end = start + kbPageSize.value
  return filteredCollections.value.slice(start, end)
})

// 总页数
const kbTotalPages = computed(() => Math.ceil(filteredCollections.value.length / kbPageSize.value))

// 页码变化处理
const handlePageChange = (page) => {
  kbCurrentPage.value = page
  // 切换页面时，取消选中状态
  selectedCollection.value = null
}

// 搜索时重置到第一页
const handleKBSearch = () => {
  kbCurrentPage.value = 1
  selectedCollection.value = null
}

// 监听 filteredCollections 变化，确保页码有效
watch(filteredCollections, () => {
  if (kbCurrentPage.value > kbTotalPages.value && kbTotalPages.value > 0) {
    kbCurrentPage.value = kbTotalPages.value
  }
})

// 监听 tab 切换，自动加载数据
watch(kbDetailTab, (newTab) => {
  if (!selectedCollection.value) return
  if (newTab === 'documents') {
    loadDocuments()
  } else if (newTab === 'chunks') {
    loadChunks()
  }
})

const totalDocumentCount = computed(() => {
  return collections.value.reduce((acc, c) => acc + (c.documentCount || 0), 0)
})

const publicCollectionCount = computed(() => {
  return collections.value.filter(c => c.visibility === 'public').length
})

const vectorizeFileOptions = computed(() => {
  if (!documents.value.length) return []
  return documents.value.map(d => ({ label: d.metadata?.filename || d.path, value: d.id || d.document_id || d.path }))
})

const batchFileOptions = computed(() => {
  if (!documents.value.length) return []
  return documents.value.map(d => ({
    key: d.id || d.document_id || d.path,
    title: d.metadata?.filename || d.path,
    description: `${d.path || ''} | ${d.metadata?.size ? formatFileSize(d.metadata.size) : '未知大小'}`
  }))
})

const versionHistoryColumns = [
  { title: '版本号', dataIndex: 'version', key: 'version', width: 80 },
  { title: '状态', dataIndex: 'status', key: 'status', width: 100 },
  { title: '切片数', dataIndex: 'chunk_count', key: 'chunk_count', width: 100 },
  { title: '生效日期', dataIndex: 'effective_date', key: 'effective_date', width: 160 },
  { title: '废止日期', dataIndex: 'deprecated_date', key: 'deprecated_date', width: 160 },
  { title: '变更摘要', dataIndex: 'change_summary', key: 'change_summary', ellipsis: true },
  { title: '创建时间', dataIndex: 'created_at', key: 'created_at', width: 160 }
]

const loadCollections = async () => {
  kbLoading.value = true
  ragServiceAvailable.value = true
  try {
    const res = await ragAPI.getCollections()
    if (res && (res.collections || Array.isArray(res))) {
      collections.value = res.collections || res
      message.success(`加载 ${collections.value.length} 个知识库`)
    } else {
      collections.value = []
    }
  } catch (e) {
    console.error('加载知识库失败:', e)

    const errorMsg = e.message || ''

    if (errorMsg.includes('RAG') || errorMsg.includes('5001') || errorMsg.includes('服务') || errorMsg.includes('Connection refused')) {
      ragServiceAvailable.value = false
      message.warning(errorMsg, 5)
      collections.value = []
    } else {
      message.error('加载知识库列表失败: ' + errorMsg)
      collections.value = []
    }
  } finally {
    kbLoading.value = false
  }
}

const openCreateModal = () => {
  Object.assign(createForm, { name: '', displayName: '', department: '', description: '' })
  showCreateModal.value = true
}

const getFileIconClass = (record) => {
  const filename = record?.metadata?.filename || record?.path || ''
  if (filename.includes('.pdf')) return 'pdf'
  if (filename.match(/\.docx?$/)) return 'word'
  if (filename.match(/\.(txt|md)$/)) return 'text'
  return 'default'
}

const openDocuments = (collection) => {
  selectCollection(collection)
  kbDetailTab.value = 'documents'
  loadDocuments()
}

const editCollectionInfo = (collection) => {
  selectCollection(collection)
  kbDetailTab.value = 'info'
}

const openBatchVectorize = () => {
  showBatchVectorize.value = true
}

const vectorizeSingleDocument = (record) => {
  const docId = record.id || record.document_id || record.path
  if (!docId) {
    message.warning('无法获取文档标识，请检查文档数据')
    return
  }
  vectorizeFileId.value = docId
  vectorizeSingle()
}

const selectCollection = async (collection) => {
  selectedCollection.value = collection
  kbDetailTab.value = 'info'
  editForm.name = collection.name
  editForm.displayName = collection.displayName || ''
  editForm.department = collection.department || ''
  editForm.description = collection.description || ''
  editForm.ownerType = collection.ownerType || ''
  editForm.visibility = collection.visibility || ''
  editForm.createTime = collection.createTime || ''
  documents.value = []
  chunks.value = []
}

const createCollection = async () => {
  if (!createForm.name) { message.warning('请输入向量库名称'); return }
  try {
    await ragAPI.createCollection(createForm)
    message.success('创建成功')
    showCreateModal.value = false
    Object.assign(createForm, { name: '', displayName: '', department: '', description: '', ownerType: 'department', visibility: 'public' })
    loadCollections()
  } catch (e) { message.error('创建失败: ' + (e.message || '')) }
}

const updateCollection = async () => {
  kbActionLoading.value = true
  try {
    await ragAPI.updateCollection(editForm.name, { 
      displayName: editForm.displayName, 
      description: editForm.description,
      department: editForm.department || ''
    })
    message.success('更新成功')
    
    if (selectedCollection.value) {
      selectedCollection.value.department = editForm.department
    }
    
    loadCollections()
  } catch (e) { message.error('更新失败: ' + (e.message || '')) }
  finally { kbActionLoading.value = false }
}

const deleteCollection = async (collection) => {
  try {
    await ragAPI.deleteCollection(collection.name)
    message.success(`已删除: ${collection.displayName || collection.name}`)
    if (selectedCollection.value?.name === collection.name) selectedCollection.value = null
    loadCollections()
  } catch (e) { message.error('删除失败: ' + (e.message || '')) }
}

const loadDocuments = async () => {
  if (!selectedCollection.value) return
  docLoading.value = true
  try {
    const res = await ragAPI.getDocumentList(selectedCollection.value.name)
    console.log('[loadDocuments] 完整响应:', res)
    documents.value = res?.documents || res || []
    console.log('[loadDocuments] 文档列表:', documents.value)
  } catch (e) {
    console.error('[loadDocuments] 加载文档失败:', e)
    documents.value = []
  } finally { docLoading.value = false }
}

const handleDocUpload = async ({ file }) => {
  if (!selectedCollection.value) return
  try {
    const res = await ragAPI.uploadDocument(file, selectedCollection.value.name)
    message.success(`上传成功: ${res?.message || file.name}`)
    loadDocuments()
  } catch (e) { message.error('上传失败: ' + (e.message || '')) }
}

const getDocumentFilename = (doc) => {
  // 使用完整的文档路径（包括知识库前缀）
  const path = doc.path || doc.metadata?.filename || doc.filename || doc.name || doc.document_id || ''
  console.log('[getDocumentFilename] 使用完整路径:', path)
  return path
}

const getDocumentPath = (doc) => {
  // 使用完整的文档路径（包括知识库前缀）
  const path = doc.path || doc.metadata?.filename || doc.filename || doc.name || doc.document_id || ''
  console.log('[getDocumentPath] 使用完整路径:', path)
  return path
}

const deleteDocument = async (doc) => {
  if (!selectedCollection.value) return
  const docPath = getDocumentPath(doc)
  if (!docPath) {
    message.error('无法获取文档路径，请检查文档数据')
    return
  }
  console.log('[deleteDocument] 文档数据:', doc)
  console.log('[deleteDocument] 知识库:', selectedCollection.value.name)
  console.log('[deleteDocument] 文档路径:', docPath)
  try {
    await ragAPI.deleteDocument(selectedCollection.value.name, docPath)
    message.success('删除成功')
    loadDocuments()
  } catch (e) {
    console.error('[deleteDocument] 删除失败:', e)
    message.error('删除失败: ' + (e.message || ''))
  }
}

const deprecateDocument = async (doc) => {
  if (!selectedCollection.value) return
  const filename = getDocumentFilename(doc)
  if (!filename) {
    message.error('无法获取文档名称，请检查文档数据')
    return
  }
  console.log('[deprecateDocument] 文档数据:', doc)
  console.log('[deprecateDocument] 知识库:', selectedCollection.value.name)
  console.log('[deprecateDocument] 文档名称:', filename)
  try {
    await ragAPI.deprecateDocument(selectedCollection.value.name, filename)
    message.success('已废止')
    loadDocuments()
  } catch (e) {
    console.error('[deprecateDocument] 废止失败:', e)
    message.error('废止失败: ' + (e.message || ''))
  }
}

const restoreDocument = async (doc) => {
  if (!selectedCollection.value) return
  const filename = getDocumentFilename(doc)
  if (!filename) {
    message.error('无法获取文档名称，请检查文档数据')
    return
  }
  console.log('[restoreDocument] 文档数据:', doc)
  console.log('[restoreDocument] 知识库:', selectedCollection.value.name)
  console.log('[restoreDocument] 文档名称:', filename)
  try {
    await ragAPI.restoreDocument(selectedCollection.value.name, filename)
    message.success('已恢复')
    loadDocuments()
  } catch (e) {
    console.error('[restoreDocument] 恢复失败:', e)
    message.error('恢复失败: ' + (e.message || ''))
  }
}

const viewDocumentVersions = async (doc) => {
  if (!selectedCollection.value) return
  const filename = getDocumentFilename(doc)
  if (!filename) {
    message.error('无法获取文档名称，请检查文档数据')
    return
  }
  console.log('[viewDocumentVersions] 文档数据:', doc)
  console.log('[viewDocumentVersions] 知识库:', selectedCollection.value.name)
  console.log('[viewDocumentVersions] 文档名称:', filename)
  selectedDocumentForVersions.value = doc
  showVersionModal.value = true
  try {
    const res = await ragAPI.getDocumentVersions(selectedCollection.value.name, filename)
    documentVersions.value = res?.versions || []
  } catch (e) {
    console.error('[viewDocumentVersions] 加载失败:', e)
    documentVersions.value = []
    message.error('加载版本历史失败: ' + (e.message || ''))
  }
}

const getVersionStatusLabel = (status) => {
  const statusMap = {
    draft: '草稿',
    active: '生效中',
    deprecated: '已废止',
    superseded: '被替代'
  }
  return statusMap[status] || status
}

const getVersionStatusColor = (status) => {
  const colorMap = {
    draft: 'default',
    active: 'success',
    deprecated: 'error',
    superseded: 'warning'
  }
  return colorMap[status] || 'default'
}

const formatFileSize = (bytes) => {
  if (!bytes) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const handleBatchFileChange = (nextTargetKeys) => {
  batchSelectedFiles.value = nextTargetKeys
}

const vectorizeBatch = async () => {
  if (!batchSelectedFiles.value.length) return
  vectorizing.value = true
  vectorizeResult.value = null
  try {
    // 使用智能批量向量化接口，每个文件自动匹配对应部门向量库
    const res = await ragAPI.smartVectorizeBatch(batchSelectedFiles.value)
    const submittedCount = res?.submittedCount || res?.successCount || res?.submittedFiles?.length || batchSelectedFiles.value.length
    const failedCount = res?.failedCount || res?.failedFiles?.length || 0
    const batchId = res?.batchId || ''
    vectorizeResult.value = {
      success: true,
      message: batchId
        ? `批量向量化任务已提交（批次: ${batchId}）：已提交 ${submittedCount} 个，失败 ${failedCount} 个`
        : `批量向量化完成：成功 ${submittedCount} 个，失败 ${failedCount} 个`,
      submitted: !!batchId,
      details: res?.submittedFiles || []
    }
    message.success(`批量向量化任务已提交：${submittedCount} 个文件正在后台处理`)
    showBatchVectorize.value = false
    batchSelectedFiles.value = []
    loadDocuments()
  } catch (e) {
    vectorizeResult.value = { success: false, message: e.message || '批量向量化失败' }
  } finally { vectorizing.value = false }
}

const viewDocumentChunks = async (doc) => {
  if (!selectedCollection.value) return
  const docPath = getDocumentPath(doc)
  if (!docPath) {
    message.error('无法获取文档路径，请检查文档数据')
    return
  }
  console.log('[viewDocumentChunks] 文档数据:', doc)
  console.log('[viewDocumentChunks] 知识库:', selectedCollection.value.name)
  console.log('[viewDocumentChunks] 文档路径:', docPath)
  chunkLoading.value = true
  try {
    const res = await ragAPI.viewDocumentChunks(selectedCollection.value.name, docPath)
    chunks.value = res?.chunks || res || []
    chunkTotal.value = chunks.value.length
    kbDetailTab.value = 'chunks'
  } catch (e) {
    console.error('[viewDocumentChunks] 加载失败:', e)
    message.error('加载切片失败: ' + (e.message || ''))
  } finally { chunkLoading.value = false }
}

const vectorizeSingle = async () => {
  if (!vectorizeFileId.value) return
  vectorizing.value = true
  vectorizeResult.value = null
  try {
    // 使用智能向量化接口，自动根据文件部门ID匹配知识库
    const res = await ragAPI.smartVectorizeFile(vectorizeFileId.value)
    if (res.submitted) {
      const collection = res.collection || res.data?.collection || '系统默认'
      vectorizeResult.value = { success: true, message: `智能向量化任务已提交到「${collection}」，正在后台处理...`, submitted: true }
      message.success(`向量化任务已提交（自动识别知识库：${collection}）`)
    } else {
      const collection = res.collection || res.data?.collection || selectedCollection.value?.name || '系统默认'
      vectorizeResult.value = { success: true, message: res?.message || '向量化成功', chunkCount: res?.chunk_count || res?.chunks?.length || 0 }
      message.success(`向量化完成（知识库：${collection}）`)
    }
    loadDocuments()
  } catch (e) {
    vectorizeResult.value = { success: false, message: e.message || '向量化失败' }
  } finally { vectorizing.value = false }
}

const loadChunks = async () => {
  if (!selectedCollection.value) return
  chunkLoading.value = true
  try {
    const res = await ragAPI.getCollectionChunks(selectedCollection.value.name, {})
    chunks.value = res?.chunks || res || []
    chunkTotal.value = chunks.value.length
  } catch (e) {
    chunks.value = []
    chunkTotal.value = 0
  } finally { chunkLoading.value = false }
}

const getSyncStatusLabel = (status) => {
  const statusMap = {
    LATEST: '最新',
    OUTDATED: '未更新',
    SYNCING: '同步中',
    FAILED: '失败'
  }
  return statusMap[status] || status || '未知'
}

const getSyncStatusColor = (status) => {
  const colorMap = {
    LATEST: 'success',
    OUTDATED: 'warning',
    SYNCING: 'processing',
    FAILED: 'error'
  }
  return colorMap[status] || 'default'
}

const loadKBPaths = async () => {
  kbPathLoading.value = true
  try {
    const res = await ragAPI.getKnowledgeBasePaths({ pageNum: 1, pageSize: 50 })
    kbPaths.value = res?.records || res || []
  } catch (e) {
    console.error('加载知识库路径失败:', e)
    kbPaths.value = []
    message.error('加载知识库路径失败')
  } finally { kbPathLoading.value = false }
}

const loadAccessibleKBs = async () => {
  kbPathLoading.value = true
  try {
    const res = await ragAPI.getAccessibleKnowledgeBases()
    kbPaths.value = res?.collections || res || []
    message.success(`找到 ${kbPaths.value.length} 个可访问的知识库`)
  } catch (e) {
    console.error('加载可访问知识库失败:', e)
    kbPaths.value = []
    message.error('加载可访问知识库失败')
  } finally { kbPathLoading.value = false }
}

const handleKBPathSearch = () => {
  if (!kbPathSearchQuery.value) {
    loadKBPaths()
    return
  }
  const q = kbPathSearchQuery.value.toLowerCase()
  kbPaths.value = kbPaths.value.filter(kb => (kb.displayName || kb.name || '').toLowerCase().includes(q))
}

const viewKBPathDetail = async (record) => {
  selectedKBPathDetail.value = record
  showKBPathDetailModal.value = true
  if (record.id) {
    try {
      const detail = await ragAPI.getKnowledgeBasePathById(record.id)
      selectedKBPathDetail.value = detail
    } catch (e) {
      console.error('加载详情失败:', e)
    }
  }
}

const handleScanQuestions = async () => {
  isScanningQuestions.value = true
  scanProgress.value = 10
  scanStatus.value = '正在扫描受影响题目...'

  try {
    scanProgress.value = 50
    const result = await ragAPI.getSyncChanges(50)
    scanProgress.value = 80

    if (result && result.changes) {
      affectedQuestions.value = result.changes.map((change, index) => ({
        id: index + 1,
        content: `文档变更: ${change.document}`,
        doc: change.document,
        version: change.change_type,
        status: 'pending'
      }))
      scanProgress.value = 100
      message.success(`题目扫描完成，共发现${affectedQuestions.value.length}个变更！`)
    } else {
      scanProgress.value = 100
      message.info('未发现受影响的题目')
    }
  } catch (error) {
    console.error('题目扫描失败:', error)
    message.error('题目扫描失败: ' + (error.message || '请检查网络或确认RAG服务已启动'))
  } finally {
    setTimeout(() => {
      isScanningQuestions.value = false
      scanStatus.value = ''
    }, 500)
  }
}

const handleGenerateQuestions = async () => {
  isGeneratingQuestions.value = true
  generateProgress.value = 10
  generateStatus.value = '正在调用AI生成题目...'

  try {
    generateProgress.value = 30
    const result = await ragAPI.generateExam({
      question_count: 3,
      question_types: ['single_choice', 'true_false'],
      difficulty: 2,
      collection_name: 'public_kb',
      request_id: `manage_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
    })

    generateProgress.value = 80

    if (result && result.questions) {
      const typeLabelMap = {
        single_choice: '单选题',
        multiple_choice: '多选题',
        true_false: '判断题',
        fill_blank: '填空题',
        subjective: '简答题'
      }
      aiGeneratedQuestions.value = result.questions.map((q, index) => ({
        id: index + 1,
        type: q.question_type,
        typeLabel: typeLabelMap[q.question_type] || q.question_type,
        content: q.content?.stem || '',
        options: q.content?.data?.options?.map(o => `${o.key}. ${o.content}`) || [],
        answer: q.content?.answer || '',
        analysis: q.content?.explanation || ''
      }))
      generateProgress.value = 100
      message.success(`题目生成完成，共生成${result.questions.length}道新题目！`)
    } else {
      generateProgress.value = 100
      message.info('未生成题目，请稍后重试')
    }
  } catch (error) {
    console.error('题目生成失败:', error)
    message.error('题目生成失败: ' + (error.message || '请检查网络或确认RAG服务已启动'))
  } finally {
    setTimeout(() => {
      isGeneratingQuestions.value = false
      generateStatus.value = ''
    }, 500)
  }
}

const handleViewQuestionDetail = (record) => {
  console.log('查看题目详情:', record)
}

const handleAcceptQuestion = (question) => {
  message.success('题目已采纳！')
  aiGeneratedQuestions.value = aiGeneratedQuestions.value.filter(q => q.id !== question.id)
}

const handleEditQuestion = (question) => {
  console.log('编辑题目:', question)
  message.info('进入题目编辑模式')
}

const handleRejectQuestion = (question) => {
  message.warning('题目已拒绝')
  aiGeneratedQuestions.value = aiGeneratedQuestions.value.filter(q => q.id !== question.id)
}

const handleGradeExam = async () => {
  if (!gradeForm.value.studentAnswers) {
    message.warning('请输入学生答案')
    return
  }

  isGradingExam.value = true
  gradeResult.value = null

  try {
    const result = await ragAPI.gradeExam({
      exam_id: gradeForm.value.examId || `exam_${Date.now()}`,
      student_answers: gradeForm.value.studentAnswers,
      grading_criteria: gradeForm.value.gradingCriteria,
      request_id: `grade_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
    })

    if (result && result.grading_result) {
      gradeResult.value = {
        totalScore: result.grading_result.total_score || 0,
        maxScore: result.grading_result.max_score || 100,
        questionResults: result.grading_result.question_results || [],
        feedback: result.grading_result.feedback || '',
        suggestions: result.grading_result.suggestions || []
      }
      message.success(`评分完成！总分：${gradeResult.value.totalScore}/${gradeResult.value.maxScore}`)
    } else {
      message.info('评分结果为空，请稍后重试')
    }
  } catch (error) {
    console.error('智能评分失败:', error)
    message.error('智能评分失败: ' + (error.message || '请检查网络或确认RAG服务已启动'))
  } finally {
    isGradingExam.value = false
  }
}

const resetGradeForm = () => {
  gradeResult.value = null
  gradeForm.value = {
    examId: '',
    studentAnswers: '',
    gradingCriteria: 'accuracy_completeness'
  }
}
</script>

<style scoped>
.manage-page {
  height: 100%;
  min-height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  background: var(--bg-page);
}

.manage-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: var(--space-lg);
  overflow-y: auto;
  overflow-x: hidden;
  min-width: 0;
}

.exam-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-sm);
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
}

.header-left {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.header-right {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
}

.page-title {
  font-size: var(--font-xl);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  margin: 0;
  line-height: 1.4;
}

.page-desc {
  font-size: var(--font-xs);
  color: var(--text-tertiary);
  margin: 0;
  line-height: 1.3;
}

.tab-icon {
  font-size: var(--font-lg);
}

.exam-card {
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  margin-bottom: var(--space-md);
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--border-light);
}

.card-title {
  font-size: var(--font-xl);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  margin-bottom: var(--space-md);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.action-bar {
  display: flex;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
  flex-wrap: wrap;
}

.card-row {
  display: flex;
  gap: var(--space-md);
}

.card-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.btn {
  border-radius: var(--radius-md);
  padding: 0 var(--space-xl);
  height: var(--input-height);
  font-size: var(--font-lg);
  font-weight: var(--weight-medium);
  transition: all var(--transition-normal);
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  box-sizing: border-box;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--text-inverse);
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn-success {
  background: var(--color-success);
  color: var(--text-inverse);
  box-shadow: var(--shadow-sm);
}

.btn-success:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn-warning {
  background: var(--color-warning);
  color: var(--text-inverse);
  box-shadow: var(--shadow-sm);
}

.btn-warning:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn-danger {
  background: var(--color-error);
  color: var(--text-inverse);
  box-shadow: var(--shadow-sm);
}

.btn-danger:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn-small {
  padding: 2px var(--space-sm);
  font-size: var(--font-sm);
}

.form-input {
  width: 300px;
  height: var(--input-height);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-default);
  padding: 0 var(--space-md);
  font-size: var(--font-md);
  transition: all 0.3s ease;
  box-sizing: border-box;
}

.form-input:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px var(--color-primary-alpha-20);
}

.form-select {
  width: 140px;
  height: var(--input-height);
  box-sizing: border-box;
}

.form-select :deep(.ant-select-selector) {
  height: var(--input-height) !important;
  min-height: var(--input-height) !important;
  max-height: var(--input-height) !important;
  padding: 0 28px 0 var(--space-md) !important;
  border-radius: var(--radius-md) !important;
  border: 1px solid var(--border-light) !important;
  background: var(--bg-container) !important;
  display: flex !important;
  align-items: center !important;
  justify-content: flex-start !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
  line-height: 1 !important;
}

.form-select :deep(.ant-select-selection-search) {
  flex: 1;
  height: 100% !important;
  display: flex !important;
  align-items: center !important;
  box-sizing: border-box !important;
}

.form-select :deep(.ant-select-selection-item) {
  height: 100% !important;
  line-height: 1 !important;
  display: flex !important;
  align-items: center !important;
  font-size: var(--font-md);
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  box-sizing: border-box !important;
  margin: 0 !important;
  padding: 0 !important;
}

.form-select :deep(.ant-select-selection-placeholder) {
  height: 100% !important;
  line-height: 1 !important;
  display: flex !important;
  align-items: center !important;
  font-size: var(--font-md);
  color: var(--text-disabled);
  box-sizing: border-box !important;
  margin: 0 !important;
  padding: 0 !important;
}

.form-select :deep(.ant-select-arrow) {
  right: var(--space-sm) !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  margin-top: 0 !important;
  color: var(--text-tertiary);
  font-size: var(--font-xs);
  position: absolute !important;
  height: 16px !important;
  width: 16px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
}

.form-select :deep(.ant-select-arrow svg) {
  width: 12px !important;
  height: 12px !important;
  box-sizing: border-box !important;
  overflow: visible !important;
  position: relative !important;
  z-index: 1 !important;
}

.progress-container {
  padding: 20px;
  background: linear-gradient(135deg, #f0f5ff 0%, #e6f7ff 100%);
  border-radius: 12px;
  margin-bottom: 20px;
  border: 1px solid #91caff;
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.08);
}

.progress-container.scan-progress {
  background: linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%);
  border: 1px solid #b7eb8f;
  box-shadow: 0 4px 12px rgba(82, 196, 26, 0.08);
}

.progress-container.generate-progress {
  background: linear-gradient(135deg, #fffbe6 0%, #ffe7ba 100%);
  border: 1px solid #ffe58f;
  box-shadow: 0 4px 12px rgba(250, 140, 22, 0.08);
}

.progress-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
}

.progress-status {
  font-weight: var(--weight-semibold);
  color: var(--color-primary);
}

.scan-progress .progress-status {
  color: var(--color-success);
}

.generate-progress .progress-status {
  color: #fa8c16;
}

.progress-bar {
  height: 8px;
  background-color: #e6f7ff;
  border-radius: 4px;
  overflow: hidden;
}

.scan-progress .progress-bar {
  background-color: #f6ffed;
}

.generate-progress .progress-bar {
  background-color: #fffbe6;
}

.progress-fill {
  height: 100%;
  background-color: var(--color-primary);
}

.scan-progress .progress-fill {
  background-color: var(--color-success);
}

.generate-progress .progress-fill {
  background-color: #fa8c16;
}

.progress-icon {
  display: flex;
  justify-content: center;
  margin-top: 8px;
  font-size: 24px;
}

.scan-progress .progress-icon {
  color: #52c41a;
}

.generate-progress .progress-icon {
  color: #fa8c16;
}

.action-buttons {
  display: flex;
  gap: 8px;
}

.question-card {
  background: #fff;
  border-radius: 12px;
  padding: 20px;
  margin-bottom: 16px;
  border: 1px solid #f0f0f0;
  transition: all 0.3s ease;
}

.question-card:hover {
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
  transform: translateY(-3px);
}

.question-card h5 {
  margin: 0 0 12px 0;
  font-size: 16px;
  font-weight: 600;
  color: #1a1a2e;
}

.question-card p {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: #333;
}

.question-options {
  margin-bottom: 12px;
}

.question-options div {
  margin-bottom: 4px;
}

.question-answer {
  margin-bottom: 8px;
  font-size: 14px;
}

.question-analysis {
  font-size: 14px;
  color: #666;
  margin-bottom: 16px;
}

.question-actions {
  display: flex;
  gap: 8px;
}

.empty-state {
  text-align: center;
  padding: 40px 24px;
  background: linear-gradient(180deg, #fafafa 0%, #ffffff 100%);
  border-radius: 12px;
}

.empty-state p {
  color: #999;
  margin: 0;
}

.kb-manage-content {
  padding: var(--space-lg);
}

.kb-header {
  margin-bottom: var(--space-sm);
}

.kb-header-right {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
}

.btn-create {
  padding-left: var(--space-md);
  padding-right: var(--space-md);
  height: var(--input-height);
  font-weight: var(--weight-medium);
}

.kb-statistics {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}

.stat-card {
  display: flex;
  gap: var(--space-md);
  align-items: center;
  padding: var(--space-md) var(--space-lg);
  background: var(--bg-card);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-light);
}

.stat-card:hover {
  border-color: var(--color-primary);
}

.stat-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-xl);
}

.stat-icon.total {
  background: var(--color-primary);
  color: var(--bg-card);
}

.stat-icon.docs {
  background: var(--color-primary);
  color: var(--bg-card);
}

.stat-icon.public {
  background: var(--color-success);
  color: var(--bg-card);
}

.stat-content {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stat-value {
  font-size: var(--font-2xl);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  line-height: 1;
}

.stat-label {
  font-size: var(--font-sm);
  color: var(--text-tertiary);
  font-weight: var(--weight-medium);
}

.kb-main-layout {
  display: flex;
  gap: var(--space-xl);
  min-height: 400px;
}

.kb-list-section {
  flex: 1;
  min-width: 360px;
  overflow: visible;
  padding-right: 16px;
}

.kb-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 2px solid #fafafa;
}

.kb-count-label {
  font-size: var(--font-md);
  color: var(--text-tertiary);
  font-weight: var(--weight-medium);
}

.toolbar-right {
  display: flex;
  gap: 12px;
  align-items: center;
}

.kb-card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}

/* 分页组件样式 */
.kb-pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px 0 8px;
  border-top: 1px solid #f0f0f0;
}

.kb-pagination :deep(.ant-pagination) {
  display: flex;
  justify-content: center;
  align-items: center;
}

.kb-pagination :deep(.ant-pagination-item) {
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-light);
}

.kb-pagination :deep(.ant-pagination-item:hover) {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.kb-pagination :deep(.ant-pagination-item-active) {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--bg-card);
}

.kb-pagination :deep(.ant-pagination-item-active:hover) {
  border-color: var(--color-primary);
  color: var(--bg-card);
}

.kb-pagination :deep(.ant-pagination-prev),
.kb-pagination :deep(.ant-pagination-next) {
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-light);
}

.kb-pagination :deep(.ant-pagination-prev:hover),
.kb-pagination :deep(.ant-pagination-next:hover) {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.kb-pagination :deep(.ant-pagination-prev .ant-pagination-item-link),
.kb-pagination :deep(.ant-pagination-next .ant-pagination-item-link) {
  border: none;
  border-radius: var(--radius-sm);
}

.kb-pagination :deep(.ant-pagination-total-text) {
  color: var(--text-tertiary);
  font-size: var(--font-sm);
  margin-right: var(--space-md);
}

.kb-collection-card {
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  padding: var(--space-sm) var(--space-md);
  cursor: pointer;
}

.kb-collection-card:hover {
  border-color: var(--color-primary);
}

.kb-collection-card.active {
  border-color: var(--color-primary);
  background: var(--bg-active);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-xs);
}

.card-icon {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-md);
}

.card-icon.public {
  background: var(--bg-active);
  color: var(--color-primary);
}

.card-icon.private {
  background: var(--bg-active);
  color: var(--color-primary);
}

.card-status-tags {
  display: flex;
  gap: 4px;
}

.card-body {
  margin-bottom: var(--space-sm);
}

.card-title {
  margin: 0 0 2px 0;
  font-size: var(--font-lg);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  line-height: 1.3;
}

.card-subtitle {
  margin: 0 0 4px 0;
  font-size: var(--font-xs);
  color: var(--text-tertiary);
  font-family: monospace;
}

.card-desc {
  margin: 0;
  font-size: var(--font-sm);
  color: var(--text-secondary);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border-light);
}

.card-meta {
  display: flex;
  gap: var(--space-md);
}

.meta-item {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--font-xs);
  color: var(--text-tertiary);
}

.meta-item .anticon {
  font-size: var(--font-xs);
}

.card-actions {
  display: flex;
  gap: 4px;
}

.action-icon {
  font-size: var(--font-md);
  color: var(--text-tertiary);
  padding: 4px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.action-icon:hover {
  color: var(--color-primary);
  background: var(--bg-active);
}

.action-btn {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-md);
  color: var(--text-tertiary);
  cursor: pointer;
}

.action-btn:hover {
  background: var(--bg-active);
  color: var(--text-primary);
}

.action-btn.danger:hover {
  background: var(--bg-error);
  color: var(--color-error);
}

.kb-detail-panel {
  flex: 2;
  min-width: 400px;
  background: var(--bg-card);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-light);
  overflow: visible;
  display: flex;
  flex-direction: column;
  height: fit-content;
}

.detail-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-md) var(--space-lg);
  border-bottom: 1px solid var(--border-light);
  background: var(--bg-container);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.panel-title {
  display: flex;
  gap: var(--space-md);
  align-items: center;
}

.panel-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-md);
  background: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-md);
  color: var(--bg-card);
}

.panel-title h3 {
  margin: 0;
  font-size: var(--font-xl);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.panel-title p {
  margin: 2px 0 0 0;
  font-size: var(--font-sm);
  color: var(--text-tertiary);
  font-family: monospace;
}

.kb-detail-tabs {
  padding: 0 var(--space-lg) var(--space-lg) var(--space-lg);
  flex: 1;
}

.kb-detail-tabs :deep(.ant-tabs-nav) {
  margin-bottom: var(--space-md) !important;
  padding-bottom: var(--space-sm);
  border-bottom: none !important;
}

.kb-detail-tabs :deep(.ant-tabs-tab) {
  padding: var(--space-sm) var(--space-md) !important;
  font-weight: var(--weight-medium);
  font-size: var(--font-md);
  color: var(--text-secondary);
}

.kb-detail-tabs :deep(.ant-tabs-tab:hover) {
  color: var(--color-primary);
}

.kb-detail-tabs :deep(.ant-tabs-tab-active) {
  color: var(--color-primary) !important;
  font-weight: var(--weight-semibold);
}

.kb-detail-tabs :deep(.ant-tabs-ink-bar) {
  background: var(--color-primary);
  height: 2px;
  border-radius: 2px;
}

.detail-form-section {
  padding: var(--space-lg) 0;
}

.detail-meta-info {
  margin-top: var(--space-lg);
  padding: var(--space-md) var(--space-lg);
  background: var(--bg-container);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-light);
}

.detail-meta-info .meta-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
  font-size: var(--font-sm);
}

.detail-meta-info .meta-row:last-child {
  margin-bottom: 0;
}

.detail-meta-info .meta-label {
  color: var(--text-tertiary);
  min-width: 70px;
  font-weight: var(--weight-medium);
}

.highlight {
  font-weight: var(--weight-semibold);
  color: var(--color-primary);
  font-size: var(--font-md);
}

.doc-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
  padding-bottom: var(--space-sm);
  border-bottom: 1px dashed var(--border-light);
  flex-wrap: wrap;
  justify-content: space-between;
}

.doc-toolbar > :first-child {
  display: flex;
  gap: var(--space-md);
  align-items: center;
}

.doc-name-cell {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.doc-icon {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-sm);
  flex-shrink: 0;
}

.doc-icon.pdf {
  background: var(--bg-error);
  color: var(--color-error);
}

.doc-icon.word {
  background: var(--bg-active);
  color: var(--color-primary);
}

.doc-icon.text {
  background: var(--bg-success);
  color: var(--color-success);
}

.doc-icon.default {
  background: var(--bg-container);
  color: var(--text-tertiary);
}

.doc-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.doc-title {
  font-size: var(--font-sm);
  font-weight: var(--weight-medium);
  color: var(--text-primary);
}

.doc-path {
  font-size: var(--font-xs);
  color: var(--text-tertiary);
}

.vectorize-section {
  padding: var(--space-lg) 0;
}

.vectorize-toolbar {
  display: flex;
  gap: var(--space-md);
  align-items: center;
  flex-wrap: wrap;
}

.vectorize-result {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  border-radius: var(--radius-md);
  margin-top: var(--space-lg);
}

.vectorize-result.success {
  background: var(--bg-success);
  border: 1px solid var(--color-success);
}

.vectorize-result.error {
  background: var(--bg-error);
  border: 1px solid var(--color-error);
}

.result-icon {
  font-size: var(--font-xl);
  margin-top: 2px;
  flex-shrink: 0;
}

.result-icon.success {
  color: var(--color-success);
}

.result-icon.error {
  color: var(--color-error);
}

.result-content strong {
  display: block;
  font-size: var(--font-md);
  margin-bottom: 4px;
  color: var(--text-primary);
}

.result-content p {
  margin: 4px 0;
  font-size: var(--font-sm);
  color: var(--text-secondary);
}

.chunks-section {
  padding: 20px 0;
}

.chunks-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
}

.chunks-total {
  font-size: var(--font-sm);
  color: var(--text-tertiary);
  margin-left: auto;
}

.chunk-content-preview {
  font-size: var(--font-sm);
  line-height: 1.6;
  color: var(--text-secondary);
  max-height: 72px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  text-overflow: ellipsis;
}

.kb-loading-skeleton {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-md);
  padding: 0;
}

.kb-card-skeleton {
  height: 120px;
  background: var(--bg-container);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-light);
}

.kb-empty-state {
  text-align: center;
  padding: var(--space-3xl) var(--space-xl);
}

.kb-empty-state .empty-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-xl);
  background: var(--bg-container);
  color: var(--text-disabled);
  margin-bottom: var(--space-lg);
}

.kb-empty-state .empty-icon.warning {
  background: var(--bg-warning);
  color: var(--color-warning);
}

.kb-empty-state h3 {
  margin: 0 0 var(--space-sm) 0;
  font-size: var(--font-xl);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.kb-empty-state p {
  margin: 0 0 var(--space-xl) 0;
  font-size: var(--font-md);
  color: var(--text-tertiary);
  line-height: 1.6;
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* 统一输入框样式 */
.kb-detail-tabs :deep(.ant-input),
.kb-detail-tabs :deep(.ant-input-affix-wrapper),
.create-kb-form :deep(.ant-input),
.create-kb-form :deep(.ant-input-affix-wrapper) {
  border-radius: 8px;
  border: 1px solid #e8e8e8;
  transition: all 0.25s ease;
  padding: 8px 12px;
  font-size: 14px;
}

.kb-detail-tabs :deep(.ant-input:hover),
.kb-detail-tabs :deep(.ant-input-affix-wrapper:hover),
.create-kb-form :deep(.ant-input:hover),
.create-kb-form :deep(.ant-input-affix-wrapper:hover) {
  border-color: var(--color-primary);
}

.kb-detail-tabs :deep(.ant-input:focus),
.kb-detail-tabs :deep(.ant-input-affix-wrapper:focus-within),
.create-kb-form :deep(.ant-input:focus),
.create-kb-form :deep(.ant-input-affix-wrapper:focus-within) {
  border-color: var(--color-primary);
}

.kb-detail-tabs :deep(.ant-input-disabled),
.create-kb-form :deep(.ant-input-disabled) {
  background: var(--bg-container);
  cursor: not-allowed;
  color: var(--text-tertiary);
}

/* 统一按钮样式 */
.kb-detail-tabs :deep(.ant-btn),
.doc-toolbar :deep(.ant-btn),
.chunks-toolbar :deep(.ant-btn),
.vectorize-toolbar :deep(.ant-btn) {
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  padding: var(--space-sm) var(--space-md);
  height: auto;
  font-size: var(--font-md);
}

.kb-detail-tabs :deep(.ant-btn-primary),
.doc-toolbar :deep(.ant-btn-primary),
.chunks-toolbar :deep(.ant-btn-primary),
.vectorize-toolbar :deep(.ant-btn-primary) {
  background: var(--color-primary);
  border-color: var(--color-primary);
  padding: var(--space-sm) var(--space-lg);
}

.kb-detail-tabs :deep(.ant-btn-primary:hover),
.doc-toolbar :deep(.ant-btn-primary:hover),
.chunks-toolbar :deep(.ant-btn-primary:hover),
.vectorize-toolbar :deep(.ant-btn-primary:hover) {
  opacity: 0.9;
}

/* 统一表单项间距 */
.kb-detail-tabs :deep(.ant-form-item) {
  margin-bottom: var(--space-lg);
}

.kb-detail-tabs :deep(.ant-form-item-label) {
  padding-bottom: var(--space-sm);
}

.kb-detail-tabs :deep(.ant-form-item-label > label) {
  font-weight: var(--weight-medium);
  font-size: var(--font-md);
  color: var(--text-primary);
}

/* 统一标签样式 */
.kb-detail-tabs :deep(.ant-tag) {
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  padding: 2px var(--space-sm);
  border: none;
}

/* 统一下拉菜单样式 */
.kb-detail-tabs :deep(.ant-dropdown-menu) {
  border-radius: var(--radius-md);
}

.kb-detail-tabs :deep(.ant-dropdown-menu-item) {
  border-radius: var(--radius-sm);
  margin: 2px var(--space-sm);
}

.kb-detail-tabs :deep(.ant-dropdown-menu-item:hover) {
  background: var(--bg-active);
  color: var(--color-primary);
}

/* 统一表格样式 */
.kb-detail-tabs :deep(.ant-table) {
  border-radius: 8px;
}

.kb-detail-tabs :deep(.ant-table-thead > tr > th) {
  background: var(--bg-container);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  border-bottom: 1px solid var(--border-light);
}

.kb-detail-tabs :deep(.ant-table-tbody > tr:hover > td) {
  background: var(--bg-active);
}

/* 创建表单样式 */
.create-kb-form {
  padding: 8px 0;
}
</style>
