<template>
  <div class="editor-page">
    <!-- 主体 -->
    <div class="editor-body">
      <!-- 左侧面板 -->
      <div class="left-panel" :style="{ width: leftPanelWidth + 'px' }">
        <!-- Tab 切换 -->
        <div class="panel-tabs">
          <div 
            class="panel-tab" 
            :class="{ active: leftPanelTab === 'reports' }"
            @click="leftPanelTab = 'reports'"
          >
            📄 报告
            <span class="tab-count">{{ myReports?.length || 0 }}</span>
          </div>
          <transition name="tab-slide">
            <div 
              v-if="hasActiveDocument"
              class="panel-tab" 
              :class="{ active: leftPanelTab === 'files' }"
              @click="leftPanelTab = 'files'"
            >
              📁 资源
              <span class="tab-count">{{ sourceFiles?.length || 0 }}</span>
            </div>
          </transition>
          <transition name="tab-slide">
            <div 
              v-if="hasActiveDocument"
              class="panel-tab" 
              :class="{ active: leftPanelTab === 'toc' }"
              @click="leftPanelTab = 'toc'"
            >
              📑 目录
              <span class="tab-count">{{ tocItems?.length || 0 }}</span>
            </div>
          </transition>
        </div>

        <!-- 我的报告面板 -->
        <div class="panel-body reports-panel" v-show="leftPanelTab === 'reports'">
          <!-- 新建报告按钮（带下拉菜单） -->
          <el-popover
            placement="bottom-start"
            :width="240"
            trigger="click"
            popper-class="new-report-popover"
          >
            <template #reference>
              <el-button 
                class="new-report-btn" 
                type="primary" 
                :icon="Plus"
              >
                新建报告
              </el-button>
            </template>
            <div class="new-report-menu">
              <div class="menu-item" @click="handleCreateReport">
                <div class="menu-icon">📄</div>
                <div class="menu-content">
                  <div class="menu-title">创建空白报告</div>
                  <div class="menu-desc">从零开始创建新报告</div>
                </div>
              </div>
              <div class="menu-item" @click="handleUploadFile">
                <div class="menu-icon">📁</div>
                <div class="menu-content">
                  <div class="menu-title">上传文件创建</div>
                  <div class="menu-desc">上传 PDF/Word 自动解析</div>
                </div>
              </div>
            </div>
          </el-popover>

          <!-- 报告搜索 -->
          <el-input
            v-model="reportSearchKeyword"
            placeholder="搜索报告..."
            :prefix-icon="Search"
            clearable
            class="report-search"
          />

          <!-- 报告列表 -->
          <div class="report-list" v-if="filteredReports.length > 0">
            <div
              v-for="report in filteredReports"
              :key="report.id"
              class="report-item"
              :class="{ active: currentReportId === report.id }"
              @click="switchReport(report)"
            >
              <div class="report-icon">📄</div>
              <div class="report-info">
                <div class="report-name">{{ report.name }}</div>
                <div class="report-meta">
                  <span class="report-time">{{ formatReportTime(report.updatedAt || report.createdAt) }}</span>
                  <span class="report-status" :class="report.status">
                    {{ getReportStatusText(report.status) }}
                  </span>
                </div>
              </div>
            </div>
          </div>
          
          <!-- 空状态 -->
          <div class="report-empty" v-else-if="!loadingReports">
            <div class="empty-icon">📄</div>
            <div class="empty-text">{{ reportSearchKeyword ? '未找到匹配的报告' : '暂无报告' }}</div>
            <div class="empty-hint">点击上方按钮创建新报告</div>
          </div>

          <!-- 加载状态 -->
          <div class="report-loading" v-if="loadingReports">
            <el-icon class="is-loading"><Loading /></el-icon>
            <span>加载中...</span>
          </div>
        </div>

        <!-- 来源文件面板 -->
        <div class="panel-body" v-show="leftPanelTab === 'files'">
          <!-- 上传区 -->
          <el-upload
            class="upload-zone"
            drag
            action="/api/v1/parse/upload"
            :on-success="handleFileUpload"
            :show-file-list="false"
          >
            <div class="upload-content">
              <div class="upload-icon">📄</div>
              <div class="upload-text">拖拽或点击上传</div>
              <div class="upload-hint">支持 PDF / Word / Excel</div>
            </div>
          </el-upload>

          <!-- 来源文件列表 -->
          <div class="file-list">
            <div
              v-for="file in sourceFiles"
              :key="file.id"
              class="file-item"
              :class="{ active: selectedFile?.id === file.id }"
              @click="selectFile(file)"
            >
              <span class="file-icon">{{ getFileIcon(file) }}</span>
              <div class="file-info">
                <div class="file-name">{{ file.alias }}</div>
                <div class="file-meta">
                  <span v-if="file.required" class="required">必需</span>
                  <span v-else>可选</span>
                </div>
              </div>
              <el-button
                size="small"
                :icon="Delete"
                circle
                @click.stop="removeSourceFile(file)"
              />
            </div>
          </div>

          <!-- 添加来源文件定义 -->
          <el-button
            class="add-source-btn"
            :icon="Plus"
            @click="showAddSourceDialog = true"
          >
            添加来源文件定义
          </el-button>
        </div>

        <!-- 目录面板 -->
        <div class="panel-body toc-panel" v-show="leftPanelTab === 'toc'">
          <div class="toc-list" v-if="tocItems && tocItems.length > 0">
            <div 
              v-for="(item, index) in tocItems" 
              :key="item.index || index"
              class="toc-item"
              :class="['toc-level-' + item.level]"
              @click="scrollToHeading(item)"
            >
              <span class="toc-bullet">{{ getTocBullet(item.level) }}</span>
              <span class="toc-text">{{ item.title || item.text }}</span>
            </div>
          </div>
          <div class="toc-empty" v-else>
            <div class="empty-icon">📑</div>
            <div class="empty-text">暂无目录</div>
            <div class="empty-hint">文档解析后将自动生成目录</div>
          </div>
        </div>
      </div>

      <!-- 左侧拖拽分隔条 -->
      <div 
        class="resize-handle left-resize"
        @mousedown="startResizeLeft"
      ></div>

      <!-- 中间编辑区 -->
      <div class="center-panel">
        <!-- 欢迎页：没有选中文档时显示 -->
        <div class="welcome-page" v-if="!hasActiveDocument">
          <div class="welcome-content">
            <div class="welcome-logo">灵</div>
            <div class="welcome">
              <h1>{{ greetingText }}，{{ userName }}！<span>智能报告，洞察未来。</span></h1>
              <p>今天是个创作的好日子，开始您的智能报告之旅吧</p>
            </div>
          </div>
        </div>

        <!-- 编辑器：有选中文档时显示 -->
        <template v-else>
          <div class="editor-title-bar">
            <!-- 左侧：标题和保存状态 -->
            <div class="title-section">
              <div class="title-input-wrapper" :style="{ width: titleInputWidth + 'px' }">
                <el-input
                  v-model="reportTitle"
                  class="title-input"
                  placeholder="请输入报告标题"
                />
                <span class="title-measure" ref="titleMeasure">{{ reportTitle || '请输入报告标题' }}</span>
              </div>
              <span class="save-status" v-if="saved">✓ 已保存</span>
            </div>
            
            <!-- 中间：视图切换 -->
            <div class="view-toggle">
              <el-radio-group v-model="viewMode" size="small">
                <el-radio-button value="edit">📝 编辑</el-radio-button>
                <el-radio-button value="preview">👁 预览</el-radio-button>
              </el-radio-group>
            </div>
            
            <!-- 右侧：操作按钮 -->
            <div class="toolbar-actions">
              <el-button 
                size="small"
                :icon="Refresh" 
                :loading="regenerating"
                @click="handleRegenerateBlocks"
                title="重新生成文档结构"
              >
                重新生成
              </el-button>
              <el-button size="small" :icon="Clock" title="版本历史">版本</el-button>
              <el-button size="small" :icon="Share" circle @click="showGraphModal = true" title="知识图谱" />
              <el-divider direction="vertical" />
              <el-button size="small" type="primary" :icon="Check" @click="handleSave">保存</el-button>
            </div>
          </div>

          <div class="editor-scroll" ref="editorRef">
            <div
              class="editor-content"
              contenteditable="true"
              @contextmenu.prevent="handleContextMenu"
              ref="editorContentRef"
            />
          </div>
        </template>
      </div>

      <!-- 右侧拖拽分隔条：仅在选中文档时显示 -->
      <div 
        v-if="hasActiveDocument"
        class="resize-handle right-resize"
        @mousedown="startResizeRight"
      ></div>

      <!-- 右侧要素面板：仅在选中文档时显示 -->
      <div v-if="hasActiveDocument" class="right-panel" :style="{ width: rightPanelWidth + 'px' }">
        <!-- 要素管理（展示文档中识别的实体） -->
        <div class="element-section">
          <div class="element-header">
            <span class="element-title">
              🏷️ 要素管理
              <span class="element-count">({{ allFilteredEntities?.length || 0 }}/{{ entities?.length || 0 }})</span>
            </span>
            <el-button size="small" :icon="Plus" @click="showAddVariableDialog = true">
              添加
            </el-button>
          </div>
          <!-- 搜索和筛选 -->
          <div class="element-filter" v-if="entities && entities.length > 0">
            <el-input
              v-model="entitySearchKeyword"
              placeholder="搜索要素..."
              size="small"
              :prefix-icon="Search"
              clearable
              class="entity-search"
            />
            <div class="entity-type-filter">
              <el-tag
                v-for="(count, type) in entityTypeCounts"
                :key="type"
                :class="['filter-tag', { active: entityTypeFilter === type }]"
                size="small"
                @click="toggleEntityTypeFilter(type)"
              >
                {{ getEntityTypeIcon(type) }} {{ getEntityTypeName(type) }} ({{ count }})
              </el-tag>
              <el-tag
                v-if="entityTypeFilter"
                class="filter-tag clear"
                size="small"
                @click="entityTypeFilter = ''"
              >
                清除筛选
              </el-tag>
            </div>
          </div>
          <div class="element-body">
            <div class="element-tags-wrap" v-if="filteredEntities && filteredEntities.length > 0">
              <div
                v-for="entity in filteredEntities"
                :key="entity.id"
                class="var-tag"
                :class="[getEntityTypeClass(entity.type), { confirmed: entity.confirmed }]"
                :title="`${getEntityTypeName(entity.type)}: ${entity.text}`"
                @click="scrollToEntity(entity.id)"
                @dblclick="openEntityEditModal(entity)"
              >
                <span class="tag-icon">{{ getEntityTypeIcon(entity.type) }}</span>
                <span class="tag-name">{{ entity.text }}</span>
                <span class="tag-status" v-if="entity.confirmed">✓</span>
              </div>
            </div>
            <!-- 加载更多按钮 -->
            <div class="load-more-wrap" v-if="hasMoreEntities">
              <el-button 
                size="small" 
                text 
                @click="loadMoreEntities"
              >
                加载更多 (还有 {{ remainingEntitiesCount }} 个)
              </el-button>
            </div>
            <div class="element-hint" v-if="!entities || entities.length === 0">
              选中文本后右键标记为实体
            </div>
            <div class="element-hint" v-else-if="(!filteredEntities || filteredEntities.length === 0) && !hasMoreEntities">
              没有匹配的要素
            </div>
          </div>
        </div>

        <!-- 按类别分组显示 -->
        <div class="category-section" v-for="(vars, category) in groupedVariables" :key="category">
          <div class="category-header">
            <span
              class="category-dot"
              :style="{ background: getCategoryColor(category) }"
            />
            <span>{{ getCategoryLabel(category) }}</span>
            <span class="category-count">{{ vars.length }}</span>
          </div>
          <div class="category-items">
            <div
              v-for="v in vars"
              :key="v.id"
              class="category-item"
              @click="editVariable(v)"
            >
              <span>{{ v.displayName }}</span>
              <span class="item-value">{{ v.exampleValue || '-' }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 右键菜单 -->
    <div
      v-show="contextMenuVisible"
      class="context-menu"
      :style="{ left: contextMenuPos.x + 'px', top: contextMenuPos.y + 'px' }"
    >
      <div class="context-menu-header" v-if="selectedText">
        <span class="selected-preview">"{{ selectedText.slice(0, 20) }}{{ selectedText.length > 20 ? '...' : '' }}"</span>
      </div>
      <div class="context-menu-section">标记为实体</div>
      <div class="context-menu-item" @click="markAsVariable('person')" :disabled="markingEntity">
        <span class="icon">👤</span>
        <span>人物</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('org')" :disabled="markingEntity">
        <span class="icon">🏢</span>
        <span>组织机构</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('location')" :disabled="markingEntity">
        <span class="icon">📍</span>
        <span>地点</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('date')" :disabled="markingEntity">
        <span class="icon">📅</span>
        <span>日期/时间</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('data')" :disabled="markingEntity">
        <span class="icon">📊</span>
        <span>数据/指标</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('concept')" :disabled="markingEntity">
        <span class="icon">💡</span>
        <span>概念/技术</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('entity')" :disabled="markingEntity">
        <span class="icon">🏷️</span>
        <span>其他实体</span>
      </div>
      <div class="context-menu-loading" v-if="markingEntity">
        <el-icon class="is-loading"><Loading /></el-icon>
        <span>标记中...</span>
      </div>
    </div>

    <!-- 添加来源文件对话框 -->
    <el-dialog v-model="showAddSourceDialog" title="添加来源文件定义" width="400">
      <el-form :model="newSourceFile" label-width="80px">
        <el-form-item label="文件别名" required>
          <el-input v-model="newSourceFile.alias" placeholder="如：可研批复" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="newSourceFile.description" placeholder="文件描述" />
        </el-form-item>
        <el-form-item label="是否必需">
          <el-switch v-model="newSourceFile.required" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showAddSourceDialog = false">取消</el-button>
        <el-button type="primary" @click="addSourceFile">添加</el-button>
      </template>
    </el-dialog>

    <!-- 添加/编辑变量对话框 -->
    <el-dialog v-model="showVariableDialog" :title="editingVariable ? '编辑变量' : '添加变量'" width="500">
      <el-form :model="variableForm" label-width="100px">
        <el-form-item label="变量名" required>
          <el-input v-model="variableForm.name" placeholder="程序用名，如 project_name" />
        </el-form-item>
        <el-form-item label="显示名称" required>
          <el-input v-model="variableForm.displayName" placeholder="用户可见名称" />
        </el-form-item>
        <el-form-item label="类别">
          <el-select v-model="variableForm.category" style="width: 100%">
            <el-option label="核心实体" value="entity" />
            <el-option label="概念/技术" value="concept" />
            <el-option label="数据/指标" value="data" />
            <el-option label="地点/组织" value="location" />
            <el-option label="资源模板" value="asset" />
          </el-select>
        </el-form-item>
        <el-form-item label="示例值">
          <el-input v-model="variableForm.exampleValue" placeholder="文档中的原始值" />
        </el-form-item>
        <el-form-item label="来源类型">
          <el-select v-model="variableForm.sourceType" style="width: 100%">
            <el-option label="从来源文件提取" value="document" />
            <el-option label="手动输入" value="manual" />
            <el-option label="引用其他变量" value="reference" />
            <el-option label="固定值" value="fixed" />
          </el-select>
        </el-form-item>
        <el-form-item label="来源文件" v-if="variableForm.sourceType === 'document'">
          <el-select v-model="variableForm.sourceFileAlias" style="width: 100%">
            <el-option
              v-for="sf in sourceFiles"
              :key="sf.id"
              :label="sf.alias"
              :value="sf.alias"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="提取方式" v-if="variableForm.sourceType === 'document'">
          <el-select v-model="variableForm.extractType" style="width: 100%">
            <el-option label="直接提取" value="direct" />
            <el-option label="AI 字段提取" value="ai_extract" />
            <el-option label="AI 总结" value="ai_summarize" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showVariableDialog = false">取消</el-button>
        <el-button
          v-if="editingVariable"
          type="danger"
          @click="deleteVariable"
        >
          删除
        </el-button>
        <el-button type="primary" @click="saveVariable">保存</el-button>
      </template>
    </el-dialog>

    <!-- 知识图谱弹窗 -->
    <el-dialog v-model="showGraphModal" title="🔗 知识图谱" width="900">
      <div class="graph-container">
        <div class="graph-legend">
          <div class="legend-title">图例</div>
          <div class="legend-item">
            <span class="legend-dot entity"></span>
            <span>核心实体</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot concept"></span>
            <span>概念/技术</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot data"></span>
            <span>数据/指标</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot location"></span>
            <span>地点/组织</span>
          </div>
        </div>
        <div class="graph-body">
          <div class="graph-placeholder">
            <el-icon size="64" color="#ccc"><Connection /></el-icon>
            <p>知识图谱可视化（开发中）</p>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 实体编辑弹窗 -->
    <el-dialog v-model="showEntityEditModal" title="编辑实体" width="400">
      <div class="entity-edit-form" v-if="editingEntity">
        <div class="entity-edit-preview">
          <span class="preview-icon">{{ getEntityTypeIcon(editingEntity.type) }}</span>
          <span class="preview-text">"{{ editingEntity.text }}"</span>
        </div>
        
        <el-form label-width="80px">
          <el-form-item label="实体类型">
            <el-select v-model="editingEntity.type" style="width: 100%">
              <el-option label="👤 人物" value="PERSON" />
              <el-option label="🏢 组织机构" value="ORGANIZATION" />
              <el-option label="📍 地点" value="LOCATION" />
              <el-option label="📅 日期/时间" value="DATE" />
              <el-option label="📊 数据/指标" value="DATA" />
              <el-option label="💡 概念/技术" value="CONCEPT" />
              <el-option label="🏷️ 其他实体" value="ENTITY" />
            </el-select>
          </el-form-item>
          <el-form-item label="状态">
            <el-tag :type="editingEntity.confirmed ? 'success' : 'info'">
              {{ editingEntity.confirmed ? '已确认' : '待确认' }}
            </el-tag>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <el-button @click="showEntityEditModal = false">取消</el-button>
        <el-button 
          type="primary" 
          v-if="editingEntity && !editingEntity.confirmed"
          @click="confirmEditingEntity"
        >
          确认实体
        </el-button>
        <el-button type="danger" @click="deleteEditingEntity">删除</el-button>
        <el-button type="primary" @click="saveEditingEntity">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import {
  ArrowLeft, Clock, Share, Check, Plus, Delete, Connection, Refresh, Search, Loading
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useTemplateStore } from '@/stores/template'
import { documentApi, templateApi } from '@/api'

const router = useRouter()
const route = useRoute()
const templateStore = useTemplateStore()

// 从 URL 查询参数获取文档ID
const currentDocumentId = ref(route.query.doc || null)

// 当前选中的报告ID（用于标记左侧列表的选中状态）
const currentReportId = ref(null)

// 是否有当前激活的文档
const hasActiveDocument = computed(() => !!currentDocumentId.value)

// 欢迎页问候语
const userName = computed(() => localStorage.getItem('username') || '用户')
const greetingText = computed(() => {
  const hour = new Date().getHours()
  if (hour < 6) return '凌晨好'
  if (hour < 9) return '早上好'
  if (hour < 12) return '上午好'
  if (hour < 14) return '中午好'
  if (hour < 18) return '下午好'
  if (hour < 22) return '晚上好'
  return '夜深了'
})

const reportTitle = ref('')
const titleMeasure = ref(null)
const titleInputWidth = ref(120)
const viewMode = ref('edit')
const saved = ref(true)
const editorRef = ref(null)
const editorContentRef = ref(null)
const loading = ref(false)
const regenerating = ref(false)

// 面板宽度（可拖拽调整）
const leftPanelWidth = ref(300)
const rightPanelWidth = ref(380)
const isResizing = ref(false)
const resizeType = ref('') // 'left' or 'right'

// 开始拖拽左侧分隔条
function startResizeLeft(e) {
  isResizing.value = true
  resizeType.value = 'left'
  document.addEventListener('mousemove', handleResize)
  document.addEventListener('mouseup', stopResize)
  document.body.style.cursor = 'col-resize'
  document.body.style.userSelect = 'none'
}

// 开始拖拽右侧分隔条
function startResizeRight(e) {
  isResizing.value = true
  resizeType.value = 'right'
  document.addEventListener('mousemove', handleResize)
  document.addEventListener('mouseup', stopResize)
  document.body.style.cursor = 'col-resize'
  document.body.style.userSelect = 'none'
}

// 处理拖拽
function handleResize(e) {
  if (!isResizing.value) return
  
  if (resizeType.value === 'left') {
    const newWidth = e.clientX
    leftPanelWidth.value = Math.max(240, Math.min(500, newWidth))
  } else if (resizeType.value === 'right') {
    const newWidth = window.innerWidth - e.clientX
    rightPanelWidth.value = Math.max(280, Math.min(500, newWidth))
  }
}

// 停止拖拽
function stopResize() {
  isResizing.value = false
  resizeType.value = ''
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
  document.body.style.cursor = ''
  document.body.style.userSelect = ''
}

// 动态计算标题输入框宽度
watch(reportTitle, () => {
  nextTick(() => {
    if (titleMeasure.value) {
      const measuredWidth = titleMeasure.value.offsetWidth + 30 // 额外边距
      titleInputWidth.value = Math.max(120, Math.min(400, measuredWidth))
    }
  })
})

// 左侧面板 Tab（默认显示报告列表）
const leftPanelTab = ref('reports')

// 我的报告列表
const myReports = ref([])
const loadingReports = ref(false)
const reportSearchKeyword = ref('')

// 筛选后的报告列表
const filteredReports = computed(() => {
  if (!reportSearchKeyword.value) {
    return myReports.value
  }
  const keyword = reportSearchKeyword.value.toLowerCase()
  return myReports.value.filter(r => 
    r.name?.toLowerCase().includes(keyword)
  )
})

// 加载我的报告列表
async function loadMyReports() {
  loadingReports.value = true
  try {
    const data = await templateApi.list(1, 50)
    myReports.value = data.records || data || []
  } catch (error) {
    console.warn('获取报告列表失败:', error)
    myReports.value = []
  } finally {
    loadingReports.value = false
  }
}

// 切换报告
async function switchReport(report) {
  // 如果点击的是当前已选中的报告，则取消选中
  if (currentDocumentId.value && currentDocumentId.value === report.baseDocumentId) {
    unselectReport()
    return
  }
  
  // 如果是当前选中的空白报告（无 baseDocumentId），也取消选中
  if (!report.baseDocumentId && currentReportId.value === report.id) {
    unselectReport()
    return
  }
  
  // 更新当前报告ID（用于标记选中状态）
  currentReportId.value = report.id
  
  if (!report.baseDocumentId) {
    // 没有关联文档，进入空白编辑页面
    currentDocumentId.value = 'empty-' + report.id  // 使用特殊标识表示空白文档
    reportTitle.value = report.name || '未命名报告'
    
    // 清空文档内容，显示空白提示
    blocks.value = []
    tocItems.value = []
    documentContent.value = emptyPlaceholder
    entities.value = []
    sourceFiles.value = []
    return
  }
  
  // 更新 URL（不刷新页面）
  const newUrl = new URL(window.location.href)
  newUrl.searchParams.set('doc', report.baseDocumentId)
  window.history.replaceState({}, '', newUrl.toString())
  
  // 更新当前文档ID
  currentDocumentId.value = report.baseDocumentId
  
  // 加载新文档
  await loadDocumentById(report.baseDocumentId)
  
  // 更新报告标题
  reportTitle.value = report.name || '未命名报告'
}

// 取消选中报告，回到初始状态
function unselectReport() {
  // 清除 URL 参数
  const newUrl = new URL(window.location.href)
  newUrl.searchParams.delete('doc')
  window.history.replaceState({}, '', newUrl.toString())
  
  // 清除当前文档和报告
  currentDocumentId.value = null
  currentReportId.value = null
  reportTitle.value = '新建报告'
  
  // 清空文档内容
  blocks.value = []
  tocItems.value = []
  documentContent.value = emptyPlaceholder
  entities.value = []
  sourceFiles.value = []
  
  // 切换回报告 Tab
  leftPanelTab.value = 'reports'
}

// 根据文档ID加载文档
async function loadDocumentById(documentId) {
  if (!documentId) return
  
  loading.value = true
  try {
    const [structuredDoc] = await Promise.all([
      documentApi.getStructured(documentId),
      loadToc(documentId)
    ])
    
    if (structuredDoc && structuredDoc.blocks && structuredDoc.blocks.length > 0) {
      blocks.value = structuredDoc.blocks
      documentContent.value = renderStructuredDocument(structuredDoc)
      entities.value = extractEntitiesFromBlocks(structuredDoc.blocks)
    } else {
      blocks.value = []
      documentContent.value = emptyPlaceholder
      entities.value = []
    }
  } catch (error) {
    console.warn('加载文档失败:', error)
    blocks.value = []
    documentContent.value = emptyPlaceholder
    entities.value = []
  } finally {
    loading.value = false
  }
}

// 新建报告
async function handleCreateReport() {
  try {
    const { value: reportName } = await ElMessageBox.prompt('请输入报告名称', '新建报告', {
      confirmButtonText: '创建',
      cancelButtonText: '取消',
      inputPattern: /\S+/,
      inputErrorMessage: '报告名称不能为空'
    })
    
    if (reportName) {
      const newReport = await templateApi.create({ name: reportName })
      ElMessage.success('报告创建成功')
      // 刷新报告列表
      await loadMyReports()
      // 如果新报告有文档，切换到该报告
      if (newReport && newReport.baseDocumentId) {
        await switchReport(newReport)
      }
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('创建报告失败:', error)
      ElMessage.error('创建报告失败')
    }
  }
}

// 上传文件入口
function handleUploadFile() {
  // 先选择一个报告，然后切换到资源 Tab
  if (myReports.value.length > 0) {
    leftPanelTab.value = 'reports'
    ElMessage.info('请先选择一个报告，然后在资源面板上传文件')
  } else {
    ElMessage.info('请先创建一个报告')
  }
}

// AI 辅助入口
function handleAiAssist() {
  ElMessage.info('AI 辅助功能开发中...')
}

// 格式化报告时间
function formatReportTime(dateStr) {
  if (!dateStr) return ''
  const date = new Date(dateStr)
  const now = new Date()
  const diffMs = now - date
  const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))
  
  if (diffDays === 0) {
    return '今天'
  } else if (diffDays === 1) {
    return '昨天'
  } else if (diffDays < 7) {
    return `${diffDays}天前`
  } else {
    return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' })
  }
}

// 获取报告状态文本
function getReportStatusText(status) {
  const statusMap = {
    'draft': '草稿',
    'published': '已发布',
    'archived': '已归档',
    'editing': '编辑中'
  }
  return statusMap[status] || '草稿'
}

// 来源文件（从 API 获取）
const sourceFiles = ref([])
const selectedFile = ref(null)
const showAddSourceDialog = ref(false)
const newSourceFile = reactive({
  alias: '',
  description: '',
  required: true
})

// 文档结构块（用于生成目录等）
const blocks = ref([])

// 目录数据（从 API 获取）
const tocItems = ref([])

// 加载文档目录
async function loadToc(documentId) {
  try {
    const items = await documentApi.getToc(documentId)
    tocItems.value = items || []
  } catch (error) {
    console.warn('获取文档目录失败:', error)
    tocItems.value = []
  }
}

// 获取目录项的项目符号
function getTocBullet(level) {
  const bullets = ['●', '○', '◦']
  return bullets[Math.min(level - 1, bullets.length - 1)]
}

// 规范化文本用于比较
function normalizeForCompare(text) {
  if (!text) return ''
  return text
    .replace(/\s+/g, ' ')  // 多个空格合并
    .replace(/[\u00A0\u202F\u2009]/g, ' ')  // 特殊空格转普通空格
    .trim()
}

// 滚动到指定章节（只匹配 h1-h6 标题元素）
function scrollToHeading(item) {
  const titleText = normalizeForCompare(item.title || item.text)
  if (!titleText) return
  
  // 在文档内容区域中查找标题元素
  const editorContent = document.querySelector('.editor-content')
  if (!editorContent) return
  
  // 查找 h1-h6 标题元素
  const headings = editorContent.querySelectorAll('h1, h2, h3, h4, h5, h6')
  
  for (const heading of headings) {
    const headingText = normalizeForCompare(heading.textContent)
    if (headingText === titleText) {
      heading.scrollIntoView({ behavior: 'smooth', block: 'start' })
      highlightElement(heading)
      return
    }
  }
  
  ElMessage.info(`章节「${titleText}」在当前文档中不存在`)
}

// 高亮元素
function highlightElement(el) {
  el.classList.add('highlight-block')
  setTimeout(() => {
    el.classList.remove('highlight-block')
  }, 2000)
}

// 旧的滚动方法（用于 blockId）
function scrollToBlock(blockId) {
  if (!blockId) return
  
  const blockEl = document.querySelector(`[data-block-id="${blockId}"]`)
  if (blockEl) {
    blockEl.scrollIntoView({ behavior: 'smooth', block: 'start' })
    // 高亮一下
    blockEl.classList.add('highlight-block')
    setTimeout(() => {
      blockEl.classList.remove('highlight-block')
    }, 2000)
  }
}

// 变量（从 API 获取）
const variables = ref([])

// 文档中的实体（从 blocks 的 elements 中提取）
const entities = ref([])

// 要素搜索和筛选
const entitySearchKeyword = ref('')
const entityTypeFilter = ref('')

// 计算属性：按类型统计要素数量
const entityTypeCounts = computed(() => {
  const counts = {}
  if (!entities.value || !Array.isArray(entities.value)) return counts
  entities.value.forEach(entity => {
    if (!entity) return
    const type = entity.type || 'default'
    counts[type] = (counts[type] || 0) + 1
  })
  return counts
})

// 实体显示数量限制（性能优化）
const entityDisplayLimit = ref(50)
const ENTITY_PAGE_SIZE = 50

// 计算属性：筛选后的要素列表（全部）
const allFilteredEntities = computed(() => {
  if (!entities.value || !Array.isArray(entities.value)) return []
  
  let result = entities.value.filter(e => e != null)
  
  // 按类型筛选
  if (entityTypeFilter.value) {
    result = result.filter(e => e.type === entityTypeFilter.value)
  }
  
  // 按关键词搜索
  if (entitySearchKeyword.value) {
    const keyword = entitySearchKeyword.value.toLowerCase()
    result = result.filter(e => 
      e.text?.toLowerCase()?.includes(keyword) ||
      e.type?.toLowerCase()?.includes(keyword)
    )
  }
  
  return result
})

// 计算属性：限制显示数量的要素列表
const filteredEntities = computed(() => {
  const all = allFilteredEntities.value || []
  return all.slice(0, entityDisplayLimit.value)
})

// 是否还有更多实体可显示
const hasMoreEntities = computed(() => {
  const all = allFilteredEntities.value || []
  return all.length > entityDisplayLimit.value
})

// 剩余未显示的实体数量
const remainingEntitiesCount = computed(() => {
  const all = allFilteredEntities.value || []
  return Math.max(0, all.length - entityDisplayLimit.value)
})

// 加载更多实体
function loadMoreEntities() {
  entityDisplayLimit.value += ENTITY_PAGE_SIZE
}

// 重置实体显示数量（筛选条件变化时）
watch([entityTypeFilter, entitySearchKeyword], () => {
  entityDisplayLimit.value = ENTITY_PAGE_SIZE
})

// 切换类型筛选
function toggleEntityTypeFilter(type) {
  if (entityTypeFilter.value === type) {
    entityTypeFilter.value = ''
  } else {
    entityTypeFilter.value = type
  }
}

// 获取实体类型名称（支持后端返回的英文类型）
function getEntityTypeName(type) {
  const typeNames = {
    // 中文类型
    'entity': '实体',
    'concept': '概念',
    'data': '数据',
    'location': '地点',
    'asset': '资产',
    'person': '人物',
    'org': '组织',
    'date': '日期',
    'product': '产品',
    'event': '事件',
    'law': '法规',
    'default': '其他',
    // 后端返回的英文类型
    'DOC_ID': '文档编号',
    'ORG': '组织机构',
    'ORGANIZATION': '组织机构',
    'PERSON': '人物',
    'LOCATION': '地点',
    'LOC': '地点',
    'DATE': '日期',
    'TIME': '时间',
    'MONEY': '金额',
    'PERCENT': '百分比',
    'PRODUCT': '产品',
    'EVENT': '事件',
    'LAW': '法规',
    'WORK_OF_ART': '作品',
    'LANGUAGE': '语言',
    'NORP': '民族/宗教/政治团体',
    'FAC': '设施',
    'FACILITY': '设施',
    'GPE': '地理政治实体',
    'CARDINAL': '数量',
    'ORDINAL': '序数',
    'QUANTITY': '数量单位',
    'TITLE': '职务/头衔',
    'STANDARD': '标准规范',
    'RATING': '评级',
    'PERIOD': '时间段',
    'SCORE': '评分',
    'LEVEL': '等级',
    // 业务相关类型
    'CERT': '证书/资质',
    'NUMBER': '编号/数值',
    'METHOD': '方法/流程',
    'PROJECT': '项目',
    'POLICY': '政策/制度',
    'DEVICE': '设备',
    'MATERIAL': '材料',
    'TECHNOLOGY': '技术',
    'REQUIREMENT': '要求',
    'INDICATOR': '指标',
    'RESULT': '结果',
    'PROBLEM': '问题',
    'SOLUTION': '解决方案',
    'RISK': '风险',
    'MEASURE': '措施',
    'DEPARTMENT': '部门',
    'ROLE': '角色',
    'DOCUMENT': '文档',
    'REGULATION': '法规',
    'PROCEDURE': '程序',
    'ACTIVITY': '活动',
    'TASK': '任务',
    'GOAL': '目标',
    'RESOURCE': '资源',
    'SYSTEM': '系统',
    'AREA': '区域',
    'EQUIPMENT': '设备',
    'TOOL': '工具',
    'SOFTWARE': '软件',
    'DATA': '数据',
    'RECORD': '记录',
    'REPORT': '报告',
    'PLAN': '计划',
    'SCHEDULE': '日程',
    'BUDGET': '预算',
    'COST': '成本',
    'UNIT': '单位',
    'COMPANY': '公司',
    'INSTITUTION': '机构'
  }
  const upperType = type?.toUpperCase()
  return typeNames[type] || typeNames[upperType] || type || '其他'
}

/**
 * 从结构化文档的 blocks 中提取所有实体
 */
function extractEntitiesFromBlocks(blocks) {
  const entityList = []
  const entityMap = new Map() // 用于去重
  
  if (!blocks || !Array.isArray(blocks)) {
    return entityList
  }
  
  for (const block of blocks) {
    if (!block.elements || !Array.isArray(block.elements)) {
      continue
    }
    
    for (const element of block.elements) {
      if (element.type === 'entity' && element.entityId) {
        // 使用 entityId 去重
        if (!entityMap.has(element.entityId)) {
          entityMap.set(element.entityId, true)
          entityList.push({
            id: element.entityId,
            text: element.entityText || '',
            type: element.entityType || 'ENTITY',
            confirmed: element.confirmed || false
          })
        }
      }
    }
  }
  
  return entityList
}

// 加载模板数据
onMounted(async () => {
  try {
    // 加载报告列表
    await loadMyReports()
    
    // 检查 URL 是否有指定文档ID
    const docId = route.query.doc
    if (docId) {
      // 只有 URL 明确指定了文档才加载
      currentDocumentId.value = docId
      await loadDocumentById(docId)
      // 找到对应的报告设置标题和ID
      const report = myReports.value.find(r => r.baseDocumentId === docId)
      if (report) {
        reportTitle.value = report.name || '未命名报告'
        currentReportId.value = report.id
      }
    } else {
      // 没有指定文档，显示欢迎页，不自动选中任何报告
      reportTitle.value = '新建报告'
      currentReportId.value = null
      documentContent.value = emptyPlaceholder
    }
  } catch (err) {
    console.error('初始化失败:', err)
    documentContent.value = emptyPlaceholder
  }
})
const showVariableDialog = ref(false)
const showAddVariableDialog = ref(false)
const editingVariable = ref(null)
const variableForm = reactive({
  name: '',
  displayName: '',
  category: 'entity',
  exampleValue: '',
  sourceType: 'document',
  sourceFileAlias: '',
  extractType: 'direct'
})

// 右键菜单
const contextMenuVisible = ref(false)
const contextMenuPos = reactive({ x: 0, y: 0 })
const selectedText = ref('')
const selectionRange = ref(null)

// 知识图谱
const showGraphModal = ref(false)

// 实体编辑弹窗
const showEntityEditModal = ref(false)
const editingEntity = ref(null)

/**
 * 打开实体编辑弹窗
 */
function openEntityEditModal(entity) {
  editingEntity.value = { ...entity }
  showEntityEditModal.value = true
}

/**
 * 确认编辑中的实体
 */
async function confirmEditingEntity() {
  if (!editingEntity.value) return
  await handleConfirmEntity(editingEntity.value)
  editingEntity.value.confirmed = true
}

/**
 * 删除编辑中的实体
 */
async function deleteEditingEntity() {
  if (!editingEntity.value) return
  await handleUnmarkEntity(editingEntity.value)
  showEntityEditModal.value = false
  editingEntity.value = null
}

/**
 * 保存编辑中的实体
 */
async function saveEditingEntity() {
  if (!editingEntity.value) return
  
  // 查找原实体
  const idx = entities.value.findIndex(e => e.id === editingEntity.value.id)
  if (idx === -1) {
    showEntityEditModal.value = false
    return
  }
  
  const originalEntity = entities.value[idx]
  
  // 如果类型发生变化，调用更新API
  if (originalEntity.type !== editingEntity.value.type) {
    await handleUpdateEntityType(originalEntity, editingEntity.value.type)
  }
  
  showEntityEditModal.value = false
  editingEntity.value = null
}

/**
 * 全局函数：从文档内点击实体时调用
 * 注意：函数名与 ref 变量不同，避免冲突
 */
window.handleEntityClick = function(event, entityId) {
  event.stopPropagation()
  const entity = entities.value.find(e => e.id === entityId)
  if (entity) {
    openEntityEditModal(entity)
  }
}

// 文档内容（从 API 获取或空白）
const documentContent = ref('')

// 监听文档内容变化，更新 DOM
watch(documentContent, (newContent) => {
  nextTick(() => {
    if (editorContentRef.value) {
      editorContentRef.value.innerHTML = newContent || ''
    }
  })
})

// 空白模板时的占位提示 - V2 风格
const emptyPlaceholder = `
  <div class="empty-editor-placeholder">
    <div class="empty-icon">📄</div>
    <h2>开始编辑您的报告</h2>
    <p class="empty-subtitle">当前报告还没有内容，您可以：</p>
    <div class="empty-actions">
      <div class="action-card">
        <span class="action-icon">📁</span>
        <span class="action-text">上传来源文件自动解析生成内容</span>
      </div>
      <div class="action-card">
        <span class="action-icon">✏️</span>
        <span class="action-text">直接在此处开始编辑</span>
      </div>
      <div class="action-card">
        <span class="action-icon">🤖</span>
        <span class="action-text">使用 AI 助手辅助撰写</span>
      </div>
    </div>
    <p class="empty-hint">💡 提示：选中文本后右键可将其标记为要素</p>
  </div>
`

/**
 * 渲染结构化文档（合并 blocks 和 images）
 * 根据 index 排序，将图片插入到正确的位置
 */
function renderStructuredDocument(structuredDoc) {
  const blocks = structuredDoc.blocks || []
  const images = structuredDoc.images || []
  const tables = structuredDoc.tables || []
  const paragraphs = structuredDoc.paragraphs || []
  
  // 将所有元素合并
  const allElements = []
  
  // 从 blocks 中提取实体映射（按文本内容匹配）
  const entityMap = buildEntityMap(blocks)
  
  // 检查 paragraphs 是否有 runs（带格式信息）
  const hasParagraphsWithRuns = paragraphs.some(p => p.runs && p.runs.length > 0)
  
  if (hasParagraphsWithRuns) {
    // 使用 paragraphs 渲染（保留格式 + 合并实体高亮）
    paragraphs.forEach(para => {
      // 查找对应的块ID（通过 index 匹配）
      const matchingBlock = blocks.find(b => b.index === para.index)
      const blockId = matchingBlock?.id || matchingBlock?.blockId || `para_${para.index}`
      const content = renderParagraphWithRunsAndEntities(para, entityMap)
      allElements.push({
        type: 'paragraph',
        index: para.index,
        html: `<div data-block-id="${blockId}" class="doc-block">${content}</div>`
      })
    })
  } else if (blocks.length > 0) {
    // 回退到 blocks 渲染（带实体标记，但无格式）
    blocks.forEach(block => {
      if (block.type === 'page') return // 跳过根节点
      // 添加 data-block-id 属性以支持实体标记定位
      const blockId = block.id || block.blockId
      const content = block.markedHtml || block.html || block.plainText || ''
      allElements.push({
        type: 'block',
        index: block.index,
        html: `<div data-block-id="${blockId}" class="doc-block">${content}</div>`
      })
    })
  }
  
  // 添加图片（保持原始尺寸，不显示说明文字）
  images.forEach(img => {
    // 图片样式：保持原始尺寸，不强制居中
    const imgStyle = img.width && img.height 
      ? `width:${img.width}px; height:${img.height}px;`
      : 'max-width: 100%; height: auto;'
    
    allElements.push({
      type: 'image',
      index: img.index,
      html: `<div class="doc-image" style="margin: 8px 0;">
        <img src="${img.url}" alt="${img.alt || '图片'}" style="${imgStyle}" />
      </div>`
    })
  })
  
  // 添加表格
  tables.forEach(table => {
    allElements.push({
      type: 'table',
      index: table.index,
      html: renderTable(table, entityMap)
    })
  })
  
  // 按 index 排序
  allElements.sort((a, b) => (a.index || 0) - (b.index || 0))
  
  // 合并 HTML
  return allElements.map(el => el.html).join('')
}

/**
 * 渲染表格
 */
function renderTable(table, entityMap) {
  if (!table.rows || table.rows.length === 0) {
    return '<div class="doc-table-empty">空表格</div>'
  }
  
  let html = '<div class="doc-table-container"><table class="doc-table">'
  
  table.rows.forEach((row, rowIndex) => {
    html += '<tr>'
    row.forEach((cell, colIndex) => {
      const tag = rowIndex === 0 ? 'th' : 'td'
      const attrs = []
      
      if (cell.rowSpan && cell.rowSpan > 1) {
        attrs.push(`rowspan="${cell.rowSpan}"`)
      }
      if (cell.colSpan && cell.colSpan > 1) {
        attrs.push(`colspan="${cell.colSpan}"`)
      }
      
      // 单元格样式
      const styleAttrs = []
      if (cell.style) {
        if (cell.style.alignment) {
          const alignMap = { 'left': 'left', 'center': 'center', 'right': 'right', 'both': 'justify' }
          styleAttrs.push(`text-align:${alignMap[cell.style.alignment] || cell.style.alignment}`)
        }
        if (cell.style.backgroundColor) {
          styleAttrs.push(`background-color:#${cell.style.backgroundColor}`)
        }
      }
      if (styleAttrs.length > 0) {
        attrs.push(`style="${styleAttrs.join(';')}"`)
      }
      
      // 单元格内容（支持 runs 格式）
      let content = ''
      if (cell.runs && cell.runs.length > 0) {
        content = cell.runs.map(run => renderTextRunWithEntities(run, entityMap)).join('')
      } else {
        content = highlightEntitiesInText(cell.text || '', entityMap)
      }
      
      html += `<${tag} ${attrs.join(' ')}>${content}</${tag}>`
    })
    html += '</tr>'
  })
  
  html += '</table></div>'
  return html
}

/**
 * 从 blocks 中构建实体映射
 * 返回 { entityText: { entityId, entityType, confirmed } }
 */
function buildEntityMap(blocks) {
  const entityMap = new Map()
  
  blocks.forEach(block => {
    if (!block.elements) return
    
    block.elements.forEach(el => {
      if (el.type === 'entity' && el.entityText) {
        // 使用实体文本作为 key（可能有多个相同文本的实体）
        if (!entityMap.has(el.entityText)) {
          entityMap.set(el.entityText, [])
        }
        entityMap.get(el.entityText).push({
          entityId: el.entityId,
          entityType: el.entityType,
          confirmed: el.confirmed
        })
      }
    })
  })
  
  return entityMap
}

/**
 * 渲染带格式和实体高亮的段落
 */
function renderParagraphWithRunsAndEntities(para, entityMap) {
  if (!para.runs || para.runs.length === 0) {
    // 没有 runs，使用纯文本
    const content = highlightEntitiesInText(para.content || '', entityMap)
    return wrapWithParagraphTag(content, para.type, para.style)
  }
  
  // 渲染每个 run，同时应用实体高亮
  const runsHtml = para.runs.map(run => renderTextRunWithEntities(run, entityMap)).join('')
  return wrapWithParagraphTag(runsHtml, para.type, para.style)
}

/**
 * 渲染带格式的段落（使用 runs）- 保留兼容
 */
function renderParagraphWithRuns(para) {
  if (!para.runs || para.runs.length === 0) {
    const content = escapeHtml(para.content || '').replace(/\n/g, '<br>')
    return wrapWithParagraphTag(content, para.type, para.style)
  }
  
  const runsHtml = para.runs.map(run => renderTextRun(run)).join('')
  return wrapWithParagraphTag(runsHtml, para.type, para.style)
}

/**
 * 渲染单个文本片段（Run）并高亮实体
 */
function renderTextRunWithEntities(run, entityMap) {
  if (!run || !run.text) return ''
  
  // 先在文本中查找并高亮实体
  const highlightedText = highlightEntitiesInText(run.text, entityMap)
  
  // 如果文本被实体高亮处理过（包含 span 标签），需要特殊处理样式
  const hasEntityHighlight = highlightedText.includes('entity-highlight')
  
  // 构建样式
  const styles = buildRunStyles(run)
  
  // 如果没有样式，直接返回高亮后的文本
  if (styles.length === 0) {
    return highlightedText.replace(/\n/g, '<br>')
  }
  
  // 如果有实体高亮，需要用 span 包裹整体样式
  if (hasEntityHighlight) {
    return `<span style="${styles.join(';')}">${highlightedText.replace(/\n/g, '<br>')}</span>`
  }
  
  // 普通文本，处理换行并应用样式
  const text = escapeHtml(run.text).replace(/\n/g, '<br>')
  
  // 上下标特殊处理
  if (run.verticalAlign === 'superscript') {
    return `<sup style="${styles.join(';')}">${text}</sup>`
  } else if (run.verticalAlign === 'subscript') {
    return `<sub style="${styles.join(';')}">${text}</sub>`
  }
  
  return `<span style="${styles.join(';')}">${text}</span>`
}

/**
 * 在文本中查找并高亮实体
 */
function highlightEntitiesInText(text, entityMap) {
  if (!text || !entityMap || entityMap.size === 0) {
    return escapeHtml(text || '')
  }
  
  // 按实体文本长度降序排序（优先匹配长的）
  const sortedEntities = Array.from(entityMap.keys()).sort((a, b) => b.length - a.length)
  
  let result = text
  const replacements = []
  
  // 找出所有需要替换的位置
  for (const entityText of sortedEntities) {
    const entities = entityMap.get(entityText)
    if (!entities || entities.length === 0) continue
    
    let searchStart = 0
    let entityIndex = 0
    
    while (true) {
      const pos = result.indexOf(entityText, searchStart)
      if (pos === -1) break
      
      // 获取对应的实体信息（循环使用）
      const entity = entities[entityIndex % entities.length]
      
      replacements.push({
        start: pos,
        end: pos + entityText.length,
        text: entityText,
        entity: entity
      })
      
      searchStart = pos + entityText.length
      entityIndex++
    }
  }
  
  // 按位置排序，从后往前替换（避免位置偏移）
  replacements.sort((a, b) => b.start - a.start)
  
  // 检查重叠，移除被包含的替换
  const finalReplacements = []
  for (const rep of replacements) {
    const hasOverlap = finalReplacements.some(
      existing => rep.start < existing.end && rep.end > existing.start
    )
    if (!hasOverlap) {
      finalReplacements.push(rep)
    }
  }
  
  // 执行替换
  for (const rep of finalReplacements) {
    const before = result.substring(0, rep.start)
    const after = result.substring(rep.end)
    const highlighted = renderEntityHighlight(rep.text, rep.entity)
    result = before + highlighted + after
  }
  
  // 对非实体部分进行 HTML 转义
  // 由于实体部分已经包含 HTML，需要分段处理
  return escapeNonEntityText(result)
}

/**
 * 转义非实体部分的文本
 */
function escapeNonEntityText(text) {
  // 分割出实体标签和普通文本
  const parts = text.split(/(<span class="entity-highlight[^>]*>.*?<\/span>)/g)
  
  return parts.map(part => {
    if (part.startsWith('<span class="entity-highlight')) {
      return part // 保留实体标签
    }
    return escapeHtml(part) // 转义普通文本
  }).join('')
}

/**
 * 渲染实体高亮标签
 */
function renderEntityHighlight(text, entity) {
  const cssClass = getEntityCssClass(entity.entityType)
  const confirmedMark = entity.confirmed ? ' ✓' : ''
  
  return `<span class="${cssClass}" ` +
    `data-entity-id="${entity.entityId || ''}" ` +
    `data-type="${entity.entityType || ''}" ` +
    `onclick="handleEntityClick(event,'${entity.entityId || ''}')" ` +
    `contenteditable="false">${escapeHtml(text)}${confirmedMark}</span>`
}

/**
 * 获取实体类型对应的 CSS 类
 */
function getEntityCssClass(entityType) {
  const typeMap = {
    'PERSON': 'entity-highlight person',
    'ORG': 'entity-highlight org',
    'ORGANIZATION': 'entity-highlight org',
    'LOC': 'entity-highlight location',
    'LOCATION': 'entity-highlight location',
    'GPE': 'entity-highlight location',
    'DATE': 'entity-highlight date',
    'TIME': 'entity-highlight date',
    'MONEY': 'entity-highlight data',
    'NUMBER': 'entity-highlight data',
    'PERCENT': 'entity-highlight data',
    'DATA': 'entity-highlight data',
    'CONCEPT': 'entity-highlight concept',
    'PRODUCT': 'entity-highlight product',
    'EVENT': 'entity-highlight event'
  }
  return typeMap[entityType?.toUpperCase()] || 'entity-highlight entity'
}

/**
 * 构建 Run 的 CSS 样式数组
 */
function buildRunStyles(run) {
  const styles = []
  
  if (run.fontFamily) {
    styles.push(`font-family:${run.fontFamily}`)
  }
  if (run.fontSize && run.fontSize > 0) {
    styles.push(`font-size:${run.fontSize}pt`)
  }
  if (run.color) {
    const color = run.color.startsWith('#') ? run.color : `#${run.color}`
    styles.push(`color:${color}`)
  }
  if (run.highlightColor) {
    const bgColor = getHighlightColor(run.highlightColor)
    styles.push(`background-color:${bgColor}`)
  }
  if (run.bold) {
    styles.push('font-weight:bold')
  }
  if (run.italic) {
    styles.push('font-style:italic')
  }
  
  const textDecorations = []
  if (run.underline && run.underline !== 'none') {
    const underlineStyle = run.underline === 'double' ? 'double' : 
                           run.underline === 'wave' || run.underline === 'wavy' ? 'wavy' :
                           run.underline === 'dotted' ? 'dotted' :
                           run.underline === 'dashed' ? 'dashed' : 'solid'
    textDecorations.push(`underline ${underlineStyle}`)
  }
  if (run.strikeThrough) {
    textDecorations.push('line-through')
  }
  if (textDecorations.length > 0) {
    styles.push(`text-decoration:${textDecorations.join(' ')}`)
  }
  
  return styles
}

/**
 * 渲染单个文本片段（Run）- 保留兼容
 */
function renderTextRun(run) {
  if (!run || !run.text) return ''
  
  // 转义 HTML 并将换行符转换为 <br>
  let text = escapeHtml(run.text).replace(/\n/g, '<br>')
  const styles = buildRunStyles(run)
  
  // 上下标
  if (run.verticalAlign === 'superscript') {
    return styles.length > 0 ? `<sup style="${styles.join(';')}">${text}</sup>` : `<sup>${text}</sup>`
  } else if (run.verticalAlign === 'subscript') {
    return styles.length > 0 ? `<sub style="${styles.join(';')}">${text}</sub>` : `<sub>${text}</sub>`
  }
  
  // 如果没有样式，直接返回文本
  if (styles.length === 0) {
    return text
  }
  
  return `<span style="${styles.join(';')}">${text}</span>`
}

/**
 * 获取高亮颜色对应的 CSS 颜色
 */
function getHighlightColor(colorName) {
  const colors = {
    'yellow': '#ffff00',
    'green': '#00ff00',
    'cyan': '#00ffff',
    'magenta': '#ff00ff',
    'blue': '#0000ff',
    'red': '#ff0000',
    'darkblue': '#000080',
    'darkcyan': '#008080',
    'darkgreen': '#008000',
    'darkmagenta': '#800080',
    'darkred': '#800000',
    'darkyellow': '#808000',
    'darkgray': '#808080',
    'lightgray': '#c0c0c0',
    'black': '#000000'
  }
  return colors[colorName.toLowerCase()] || colorName
}

/**
 * 用段落标签包裹内容
 */
function wrapWithParagraphTag(content, type, style) {
  // 段落样式
  const styleAttrs = []
  if (style) {
    // 对齐方式
    if (style.alignment) {
      const alignMap = {
        'left': 'left',
        'center': 'center',
        'right': 'right',
        'both': 'justify',  // 两端对齐
        'justify': 'justify'
      }
      styleAttrs.push(`text-align:${alignMap[style.alignment] || style.alignment}`)
    }
    
    // 左缩进（twips -> pt，1 twip = 1/20 pt）
    if (style.indentLeft) {
      styleAttrs.push(`padding-left:${style.indentLeft / 20}pt`)
    }
    
    // 右缩进
    if (style.indentRight) {
      styleAttrs.push(`padding-right:${style.indentRight / 20}pt`)
    }
    
    // 首行缩进
    if (style.indentFirstLine) {
      styleAttrs.push(`text-indent:${style.indentFirstLine / 20}pt`)
    }
    
    // 悬挂缩进（负的首行缩进 + 增加左边距）
    if (style.indentHanging) {
      const hangingPt = style.indentHanging / 20
      styleAttrs.push(`text-indent:-${hangingPt}pt`)
      // 如果没有左缩进，需要增加左边距来补偿
      if (!style.indentLeft) {
        styleAttrs.push(`margin-left:${hangingPt}pt`)
      }
    }
    
    // 段前间距
    if (style.spacingBefore) {
      styleAttrs.push(`margin-top:${style.spacingBefore / 20}pt`)
    }
    
    // 段后间距
    if (style.spacingAfter) {
      styleAttrs.push(`margin-bottom:${style.spacingAfter / 20}pt`)
    }
    
    // 行距处理
    if (style.lineSpacing) {
      // getSpacingBetween 返回的是倍数（如 1.0, 1.5, 2.0）
      if (style.lineSpacing >= 1 && style.lineSpacing <= 5) {
        styleAttrs.push(`line-height:${style.lineSpacing}`)
      }
    } else if (style.lineSpacingValue && style.lineSpacingRule) {
      // 精确行距值处理
      const rule = style.lineSpacingRule.toLowerCase()
      if (rule === 'exact') {
        // 固定行距（twips -> pt）
        styleAttrs.push(`line-height:${style.lineSpacingValue / 20}pt`)
      } else if (rule === 'atleast' || rule === 'at_least') {
        // 最小行距
        styleAttrs.push(`min-height:${style.lineSpacingValue / 20}pt`)
      } else if (rule === 'auto') {
        // 倍数行距（240 twips = 1 倍行距）
        styleAttrs.push(`line-height:${style.lineSpacingValue / 240}`)
      }
    }
    
    // 字体信息（段落级别的默认字体）
    if (style.fontFamily) {
      styleAttrs.push(`font-family:${style.fontFamily}`)
    }
    if (style.fontSize) {
      styleAttrs.push(`font-size:${style.fontSize}pt`)
    }
  }
  
  const styleAttr = styleAttrs.length > 0 ? ` style="${styleAttrs.join(';')}"` : ''
  
  // 目录项特殊处理
  if (type === 'toc_item') {
    const pageNum = style?.tocPageNum || ''
    // 计算缩进级别（根据章节号判断）
    let level = 0
    const levelMatch = content.match(/^(\d+(?:\.\d+)*)/)
    if (levelMatch) {
      level = (levelMatch[1].match(/\./g) || []).length
    }
    const indentStyle = level > 0 ? ` style="padding-left:${level * 20}px"` : ''
    return `<div class="doc-toc-item"${indentStyle}><span class="toc-title">${content}</span><span class="toc-dots"></span><span class="toc-page">${pageNum}</span></div>`
  }
  
  switch (type) {
    case 'heading1':
      return `<h1${styleAttr}>${content}</h1>`
    case 'heading2':
      return `<h2${styleAttr}>${content}</h2>`
    case 'heading3':
      return `<h3${styleAttr}>${content}</h3>`
    case 'heading':
      return `<h2${styleAttr}>${content}</h2>`
    case 'toc':
      return `<div class="doc-toc-title"${styleAttr}>${content}</div>`
    case 'bullet':
    case 'list_item':
      return `<div class="doc-list-item bullet"${styleAttr}>${content}</div>`
    case 'ordered':
      return `<div class="doc-list-item ordered"${styleAttr}>${content}</div>`
    case 'quote':
      return `<blockquote${styleAttr}>${content}</blockquote>`
    case 'code':
      return `<pre><code>${content}</code></pre>`
    case 'title':
      return `<h1 class="doc-title"${styleAttr}>${content}</h1>`
    default:
      return `<p${styleAttr}>${content}</p>`
  }
}

/**
 * HTML 转义
 */
function escapeHtml(text) {
  if (!text) return ''
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
}

// 计算属性
const groupedVariables = computed(() => {
  const groups = {}
  if (!variables.value || !Array.isArray(variables.value)) return groups
  variables.value.forEach(v => {
    if (!v) return
    const cat = v.category || 'other'
    if (!groups[cat]) groups[cat] = []
    groups[cat].push(v)
  })
  return groups
})

// 方法
function goBack() {
  router.back()
}

function handleSave() {
  saved.value = true
  ElMessage.success('保存成功')
}

// 重新生成文档块结构
async function handleRegenerateBlocks() {
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) {
    ElMessage.warning('没有关联的示例文档')
    return
  }

  regenerating.value = true
  try {
    const result = await documentApi.regenerateBlocks(baseDocumentId)
    ElMessage.success(`重新生成成功: ${result.blockCount} 个文档块, ${result.entityCount} 个实体`)
    
    // 重新加载文档内容
    const structuredDoc = await documentApi.getStructured(baseDocumentId)
    if (structuredDoc && structuredDoc.blocks && structuredDoc.blocks.length > 0) {
      blocks.value = structuredDoc.blocks // 更新 blocks
      documentContent.value = renderStructuredDocument(structuredDoc)
      // 重新提取实体
      entities.value = extractEntitiesFromBlocks(structuredDoc.blocks)
    }
  } catch (error) {
    console.error('重新生成失败:', error)
    ElMessage.error('重新生成失败: ' + (error.message || '未知错误'))
  } finally {
    regenerating.value = false
  }
}

function getFileIcon(file) {
  return '📄'
}

function selectFile(file) {
  selectedFile.value = file
}

async function removeSourceFile(file) {
  try {
    await templateStore.deleteSourceFile(file.id)
    sourceFiles.value = sourceFiles.value.filter(f => f.id !== file.id)
    ElMessage.success('删除成功')
  } catch (error) {
    ElMessage.error('删除失败: ' + error.message)
  }
}

async function addSourceFile() {
  if (!newSourceFile.alias) {
    ElMessage.warning('请输入文件别名')
    return
  }
  try {
    const sf = await templateStore.addSourceFile(templateId, newSourceFile)
    sourceFiles.value.push(sf)
    showAddSourceDialog.value = false
    Object.assign(newSourceFile, { alias: '', description: '', required: true })
    ElMessage.success('添加成功')
  } catch (error) {
    ElMessage.error('添加失败: ' + error.message)
  }
}

function getCategoryIcon(category) {
  const icons = {
    entity: '🏢',
    concept: '💡',
    data: '📊',
    location: '📍',
    asset: '📑'
  }
  return icons[category] || '📌'
}

function getCategoryColor(category) {
  const colors = {
    entity: '#1890ff',
    concept: '#722ed1',
    data: '#52c41a',
    location: '#faad14',
    asset: '#eb2f96'
  }
  return colors[category] || '#8c8c8c'
}

function getCategoryLabel(category) {
  const labels = {
    entity: '核心实体',
    concept: '概念/技术',
    data: '数据/指标',
    location: '地点/组织',
    asset: '资源模板'
  }
  return labels[category] || '其他'
}

/**
 * 根据实体类型获取图标
 */
function getEntityTypeIcon(type) {
  const icons = {
    'PERSON': '👤',
    'ORGANIZATION': '🏢',
    'ORG': '🏢',
    'LOCATION': '📍',
    'LOC': '📍',
    'DATE': '📅',
    'TIME': '⏰',
    'PERIOD': '📆',
    'MONEY': '💰',
    'PERCENT': '📊',
    'PRODUCT': '📦',
    'EVENT': '📋',
    'FACILITY': '🏭',
    'FAC': '🏭',
    'GPE': '🌍',
    'LAW': '⚖️',
    'WORK_OF_ART': '🎨',
    'LANGUAGE': '🗣️',
    'QUANTITY': '🔢',
    'ORDINAL': '🔢',
    'CARDINAL': '🔢',
    'ENTITY': '🏷️',
    'DOC_ID': '📄',
    'NORP': '👥',
    'TITLE': '🎖️',
    'STANDARD': '📋',
    'RATING': '⭐',
    'SCORE': '💯',
    'LEVEL': '📊',
    // 业务相关类型图标
    'CERT': '📜',
    'NUMBER': '🔢',
    'METHOD': '⚙️',
    'PROJECT': '📁',
    'POLICY': '📑',
    'DEVICE': '🔧',
    'MATERIAL': '🧱',
    'TECHNOLOGY': '💡',
    'REQUIREMENT': '📝',
    'INDICATOR': '📈',
    'RESULT': '✅',
    'PROBLEM': '⚠️',
    'SOLUTION': '💡',
    'RISK': '🚨',
    'MEASURE': '📏',
    'DEPARTMENT': '🏛️',
    'ROLE': '👔',
    'DOCUMENT': '📄',
    'REGULATION': '⚖️',
    'PROCEDURE': '📋',
    'ACTIVITY': '🎯',
    'TASK': '✔️',
    'GOAL': '🎯',
    'RESOURCE': '📦',
    'SYSTEM': '🖥️',
    'AREA': '📍',
    'EQUIPMENT': '🔧',
    'TOOL': '🛠️',
    'SOFTWARE': '💻',
    'DATA': '📊',
    'RECORD': '📝',
    'REPORT': '📊',
    'PLAN': '📅',
    'SCHEDULE': '📆',
    'BUDGET': '💵',
    'COST': '💰',
    'UNIT': '📐',
    'COMPANY': '🏢',
    'INSTITUTION': '🏛️'
  }
  return icons[type?.toUpperCase()] || '🏷️'
}

/**
 * 根据实体类型获取样式类名
 */
function getEntityTypeClass(type) {
  const typeMap = {
    'PERSON': 'entity-person',
    'ORGANIZATION': 'entity-org',
    'LOCATION': 'entity-location',
    'DATE': 'entity-date',
    'TIME': 'entity-date',
    'MONEY': 'entity-data',
    'PERCENT': 'entity-data',
    'PRODUCT': 'entity-product',
    'EVENT': 'entity-event',
    'FACILITY': 'entity-org',
    'GPE': 'entity-location',
    'LAW': 'entity-law'
  }
  return typeMap[type?.toUpperCase()] || 'entity-default'
}

/**
 * 滚动到文档中的指定实体
 */
function scrollToEntity(entityId) {
  const editorEl = document.querySelector('.editor-content')
  if (!editorEl) return
  
  const entitySpan = editorEl.querySelector(`[data-entity-id="${entityId}"]`)
  if (entitySpan) {
    entitySpan.scrollIntoView({ behavior: 'smooth', block: 'center' })
    // 添加高亮闪烁效果
    entitySpan.classList.add('entity-highlight-flash')
    setTimeout(() => {
      entitySpan.classList.remove('entity-highlight-flash')
    }, 2000)
  }
}

function editVariable(variable) {
  editingVariable.value = variable
  Object.assign(variableForm, variable)
  showVariableDialog.value = true
}

async function saveVariable() {
  if (!variableForm.name || !variableForm.displayName) {
    ElMessage.warning('请填写必要字段')
    return
  }

  try {
    if (editingVariable.value) {
      // 更新
      const updated = await templateStore.updateVariable(editingVariable.value.id, variableForm)
      Object.assign(editingVariable.value, updated)
      ElMessage.success('更新成功')
    } else {
      // 新增
      const newVar = await templateStore.addVariable(templateId, variableForm)
      variables.value.push(newVar)
      ElMessage.success('添加成功')
    }

    showVariableDialog.value = false
    resetVariableForm()
  } catch (error) {
    ElMessage.error('保存失败: ' + error.message)
  }
}

async function deleteVariable() {
  if (editingVariable.value) {
    try {
      await templateStore.deleteVariable(editingVariable.value.id)
      variables.value = variables.value.filter(v => v.id !== editingVariable.value.id)
      showVariableDialog.value = false
      resetVariableForm()
      ElMessage.success('删除成功')
    } catch (error) {
      ElMessage.error('删除失败: ' + error.message)
    }
  }
}

function resetVariableForm() {
  editingVariable.value = null
  Object.assign(variableForm, {
    name: '',
    displayName: '',
    category: 'entity',
    exampleValue: '',
    sourceType: 'document',
    sourceFileAlias: '',
    extractType: 'direct'
  })
}

// 实体标记相关状态
const markingEntity = ref(false)
const selectionInfo = reactive({
  blockId: null,
  elementIndex: null,
  startOffset: null,
  endOffset: null,
  text: ''
})

/**
 * 处理右键菜单事件（阻止浏览器默认菜单）
 */
function handleContextMenu(event) {
  const selection = window.getSelection()
  const text = selection.toString().trim()

  if (text && text.length > 0) {
    // 有选中文本时，显示自定义菜单
    event.preventDefault()
    
    selectedText.value = text
    selectionRange.value = selection.rangeCount > 0 ? selection.getRangeAt(0) : null
    
    // 尝试获取选中位置的块信息
    const blockInfo = getSelectionBlockInfo(selection)
    if (blockInfo) {
      Object.assign(selectionInfo, {
        blockId: blockInfo.blockId,
        elementIndex: blockInfo.elementIndex,
        startOffset: blockInfo.startOffset,
        endOffset: blockInfo.endOffset,
        text: text
      })
    } else {
      Object.assign(selectionInfo, {
        blockId: null,
        elementIndex: null,
        startOffset: null,
        endOffset: null,
        text: text
      })
    }
    
    // 计算菜单位置，确保不超出屏幕
    const menuWidth = 220
    const menuHeight = 350
    let x = event.clientX
    let y = event.clientY
    
    if (x + menuWidth > window.innerWidth) {
      x = window.innerWidth - menuWidth - 10
    }
    if (y + menuHeight > window.innerHeight) {
      y = window.innerHeight - menuHeight - 10
    }
    
    contextMenuPos.x = x
    contextMenuPos.y = y
    contextMenuVisible.value = true
  } else {
    // 没有选中文本时，允许浏览器默认右键菜单
    contextMenuVisible.value = false
  }
}

/**
 * 获取选中文本所在的块信息
 */
function getSelectionBlockInfo(selection) {
  if (!selection.rangeCount) return null
  
  const range = selection.getRangeAt(0)
  let node = range.startContainer
  
  // 向上查找带有 data-block-id 的元素
  while (node && node !== document) {
    if (node.nodeType === Node.ELEMENT_NODE) {
      const blockId = node.getAttribute?.('data-block-id')
      if (blockId) {
        // 找到块，现在需要确定元素索引和偏移量
        const elementIndex = findElementIndex(node, range.startContainer)
        return {
          blockId,
          elementIndex: elementIndex,
          startOffset: range.startOffset,
          endOffset: range.endOffset
        }
      }
    }
    node = node.parentNode
  }
  
  return null
}

/**
 * 查找元素在块中的索引
 */
function findElementIndex(blockElement, textNode) {
  // 简化实现：遍历块内的文本节点
  const walker = document.createTreeWalker(
    blockElement,
    NodeFilter.SHOW_TEXT,
    null,
    false
  )
  
  let index = 0
  let node
  while (node = walker.nextNode()) {
    if (node === textNode) {
      return index
    }
    index++
  }
  
  return 0
}

/**
 * 标记为实体（调用后端 API）
 */
async function markAsVariable(entityType) {
  if (!selectedText.value) return
  
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) {
    ElMessage.warning('没有关联的文档')
    contextMenuVisible.value = false
    return
  }

  // 映射前端类别到后端实体类型
  const entityTypeMap = {
    'entity': 'ENTITY',
    'concept': 'CONCEPT',
    'data': 'DATA',
    'location': 'LOCATION',
    'asset': 'ASSET',
    'person': 'PERSON',
    'org': 'ORGANIZATION',
    'date': 'DATE'
  }
  
  const backendEntityType = entityTypeMap[entityType] || entityType.toUpperCase()
  
  // 如果有完整的块信息，调用后端 API
  if (selectionInfo.blockId && selectionInfo.elementIndex !== null) {
    markingEntity.value = true
    try {
      const entityId = await documentApi.markEntity(baseDocumentId, selectionInfo.blockId, {
        elementIndex: selectionInfo.elementIndex,
        startOffset: selectionInfo.startOffset,
        endOffset: selectionInfo.endOffset,
        entityType: backendEntityType
      })
      
      // 添加到本地实体列表
      entities.value.push({
        id: entityId,
        text: selectedText.value,
        type: backendEntityType,
        confirmed: false
      })
      
      // 刷新文档内容以显示新标记
      await refreshDocumentContent()
      
      ElMessage.success('实体标记成功')
    } catch (error) {
      console.error('标记实体失败:', error)
      ElMessage.error('标记失败: ' + (error.message || '未知错误'))
    } finally {
      markingEntity.value = false
    }
  } else {
    // 没有块信息时，使用本地标记（临时方案）
    const newEntity = {
      id: 'local_' + Date.now(),
      text: selectedText.value,
      type: backendEntityType,
      confirmed: false,
      isLocal: true
    }
    entities.value.push(newEntity)
    ElMessage.success('实体已添加（本地）')
  }

  // 关闭菜单
  contextMenuVisible.value = false
  selectedText.value = ''
}

/**
 * 刷新文档内容
 */
async function refreshDocumentContent() {
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) return
  
  try {
    const structuredDoc = await documentApi.getStructured(baseDocumentId)
    if (structuredDoc && structuredDoc.blocks && structuredDoc.blocks.length > 0) {
      blocks.value = structuredDoc.blocks
      documentContent.value = renderStructuredDocument(structuredDoc)
      entities.value = extractEntitiesFromBlocks(structuredDoc.blocks)
    }
  } catch (error) {
    console.error('刷新文档内容失败:', error)
  }
}

/**
 * 取消实体标记
 */
async function handleUnmarkEntity(entity) {
  if (!entity || !entity.id) return
  
  // 本地实体直接删除
  if (entity.isLocal || entity.id.startsWith('local_')) {
    entities.value = entities.value.filter(e => e.id !== entity.id)
    ElMessage.success('已取消标记')
    return
  }
  
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) return
  
  // 需要找到实体所在的块
  const blockId = findEntityBlockId(entity.id)
  if (!blockId) {
    ElMessage.warning('找不到实体所在的块')
    return
  }
  
  try {
    await ElMessageBox.confirm('确定要取消该实体的标记吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    
    await documentApi.unmarkEntity(baseDocumentId, blockId, entity.id)
    
    // 刷新内容
    await refreshDocumentContent()
    
    ElMessage.success('已取消标记')
  } catch (error) {
    if (error !== 'cancel') {
      console.error('取消标记失败:', error)
      ElMessage.error('取消失败: ' + (error.message || '未知错误'))
    }
  }
}

/**
 * 确认实体
 */
async function handleConfirmEntity(entity) {
  if (!entity || !entity.id) return
  
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) return
  
  const blockId = findEntityBlockId(entity.id)
  if (!blockId) {
    // 本地实体直接标记确认
    entity.confirmed = true
    ElMessage.success('已确认')
    return
  }
  
  try {
    await documentApi.confirmEntity(baseDocumentId, blockId, entity.id)
    
    // 更新本地状态
    const idx = entities.value.findIndex(e => e.id === entity.id)
    if (idx !== -1) {
      entities.value[idx].confirmed = true
    }
    
    ElMessage.success('实体已确认')
  } catch (error) {
    console.error('确认实体失败:', error)
    ElMessage.error('确认失败: ' + (error.message || '未知错误'))
  }
}

/**
 * 更新实体类型
 */
async function handleUpdateEntityType(entity, newType) {
  if (!entity || !entity.id) return
  
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) return
  
  const blockId = findEntityBlockId(entity.id)
  if (!blockId) {
    // 本地实体直接更新
    entity.type = newType
    ElMessage.success('类型已更新')
    return
  }
  
  try {
    await documentApi.updateEntity(baseDocumentId, blockId, entity.id, newType)
    
    // 更新本地状态
    const idx = entities.value.findIndex(e => e.id === entity.id)
    if (idx !== -1) {
      entities.value[idx].type = newType
    }
    
    ElMessage.success('实体类型已更新')
  } catch (error) {
    console.error('更新实体类型失败:', error)
    ElMessage.error('更新失败: ' + (error.message || '未知错误'))
  }
}

/**
 * 从 blocks 中查找实体所在的块ID
 */
function findEntityBlockId(entityId) {
  for (const block of blocks.value) {
    if (!block.elements) continue
    for (const el of block.elements) {
      if (el.type === 'entity' && el.entityId === entityId) {
        return block.id
      }
    }
  }
  return null
}

function handleFileUpload(response) {
  if (response.code === 200) {
    ElMessage.success('文件上传成功')
    // 可以在这里处理上传成功后的逻辑，如关联到项目
  }
}

// 点击其他地方关闭右键菜单
function handleClickOutside(event) {
  if (contextMenuVisible.value && !event.target.closest('.context-menu')) {
    contextMenuVisible.value = false
  }
}

// ESC 键关闭右键菜单
function handleKeyDown(event) {
  if (event.key === 'Escape' && contextMenuVisible.value) {
    contextMenuVisible.value = false
  }
}

onMounted(() => {
  document.addEventListener('click', handleClickOutside)
  document.addEventListener('keydown', handleKeyDown)
})

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside)
  document.removeEventListener('keydown', handleKeyDown)
  // 清理全局函数
  delete window.handleEntityClick
})
</script>

<style lang="scss" scoped>
// ==========================================
// Editor 页面样式 - 参考 V2 原型设计
// ==========================================

.editor-page {
  height: calc(100vh - 56px);
  display: flex;
  flex-direction: column;
  background: var(--bg);
}


.editor-body {
  flex: 1;
  display: flex;
  overflow: hidden;
}

// ==========================================
// 拖拽分隔条
// ==========================================
.resize-handle {
  width: 4px;
  background: transparent;
  cursor: col-resize;
  flex-shrink: 0;
  position: relative;
  z-index: 10;
  transition: background 0.2s;
  
  &:hover, &:active {
    background: var(--primary);
  }
  
  &::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: -3px;
    right: -3px;
  }
}

// ==========================================
// 左侧面板 - V2 风格
// ==========================================
.left-panel {
  background: var(--white);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  min-width: 240px;
  max-width: 500px;
  overflow: hidden;

  // Tab 导航 - V2 风格（圆角填充）
  .panel-tabs {
    display: flex;
    gap: 6px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    background: var(--white);
    overflow: hidden;
    
    .panel-tab {
      padding: 6px 10px;
      font-size: 12px;
      font-weight: 600;
      text-align: center;
      cursor: pointer;
      color: var(--text-2);
      border-radius: 10px;
      border: 1px solid transparent;
      transition: all 0.2s;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 4px;
      white-space: nowrap;
      flex-shrink: 0;
      
      &:hover {
        color: var(--primary);
        background: var(--primary-light);
      }
      
      &.active {
        background: var(--primary);
        color: #fff;
        border-color: rgba(0, 0, 0, 0.04);
        box-shadow: var(--shadow-md);
      }
      
      .tab-count {
        font-size: 10px;
        font-weight: 500;
        background: rgba(255, 255, 255, 0.2);
        padding: 1px 6px;
        border-radius: 10px;
        color: inherit;
      }
      
      &:not(.active) .tab-count {
        background: var(--bg);
        color: var(--text-3);
      }
    }
  }
  
  // Tab 滑入动画 - 简化为淡入淡出
  .tab-slide-enter-active {
    transition: opacity 0.25s ease-out;
  }
  
  .tab-slide-leave-active {
    transition: opacity 0.15s ease-in;
  }
  
  .tab-slide-enter-from,
  .tab-slide-leave-to {
    opacity: 0;
  }

  .panel-header {
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 600;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .file-count {
      font-size: 12px;
      color: var(--text-3);
      font-weight: normal;
    }
  }

  .panel-body {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
    min-height: 0;
    
    &.toc-panel {
      padding: 8px;
    }
    
    &.reports-panel {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
  }
  
  // ==========================================
  // 我的报告面板 - V2 风格
  // ==========================================
  .new-report-btn {
    width: 100%;
    border-radius: var(--radius-md);
    height: 40px;
    font-size: 14px;
    font-weight: 600;
    background: var(--primary-gradient);
    border: none;
    
    &:hover {
      box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
    }
  }
  
  // 新建报告下拉菜单样式
  .new-report-menu {
    padding: 4px 0;
    
    .menu-item {
      display: flex;
      align-items: flex-start;
      gap: 12px;
      padding: 12px 14px;
      cursor: pointer;
      border-radius: var(--radius-sm);
      transition: all 0.2s;
      
      &:hover {
        background: var(--bg);
      }
      
      .menu-icon {
        font-size: 24px;
        flex-shrink: 0;
        line-height: 1;
      }
      
      .menu-content {
        flex: 1;
        min-width: 0;
      }
      
      .menu-title {
        font-size: 14px;
        font-weight: 500;
        color: var(--text-1);
        margin-bottom: 4px;
      }
      
      .menu-desc {
        font-size: 12px;
        color: var(--text-3);
        line-height: 1.4;
      }
    }
  }
  
  .report-search {
    :deep(.el-input__wrapper) {
      border-radius: 18px;
      background: var(--bg);
      box-shadow: none;
      border: 1px solid var(--border);
      
      &:hover, &.is-focus {
        border-color: var(--primary);
        background: var(--white);
      }
    }
  }
  
  .report-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1;
    overflow-y: auto;
    padding: 4px 0;
    
    .report-item {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 12px;
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      cursor: pointer;
      transition: all 0.2s;
      
      &:hover {
        border-color: var(--primary);
        background: var(--primary-light);
        transform: translateY(-1px);
        box-shadow: var(--shadow-sm);
      }
      
      &.active {
        border-color: var(--primary);
        background: var(--primary-light);
        box-shadow: var(--shadow-sm);
        
        &::before {
          content: '';
          position: absolute;
          left: 0;
          top: 50%;
          transform: translateY(-50%);
          width: 3px;
          height: 18px;
          background: var(--primary);
          border-radius: 0 2px 2px 0;
        }
        
        .report-name {
          color: var(--primary);
        }
      }
      
      .report-icon {
        width: 40px;
        height: 40px;
        border-radius: var(--radius-sm);
        background: var(--bg);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 18px;
        flex-shrink: 0;
      }
      
      .report-info {
        flex: 1;
        min-width: 0;
        
        .report-name {
          font-weight: 600;
          font-size: 13px;
          color: var(--text-1);
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          margin-bottom: 4px;
        }
        
        .report-meta {
          display: flex;
          align-items: center;
          gap: 8px;
          font-size: 11px;
          color: var(--text-3);
          
          .report-status {
            padding: 2px 8px;
            border-radius: 4px;
            background: var(--bg);
            font-weight: 500;
            
            &.draft { color: var(--text-3); }
            &.editing { color: var(--primary); background: var(--primary-light); }
            &.published { color: var(--success); background: #f6ffed; }
            &.archived { color: var(--text-3); }
          }
        }
      }
    }
  }
  
  .report-empty, .report-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    color: var(--text-3);
    
    .empty-icon {
      font-size: 48px;
      margin-bottom: 16px;
      opacity: 0.4;
    }
    
    .empty-text {
      font-size: 14px;
      font-weight: 500;
      color: var(--text-2);
      margin-bottom: 6px;
    }
    
    .empty-hint {
      font-size: 12px;
    }
  }
  
  .report-loading {
    flex-direction: row;
    gap: 10px;
    padding: 24px;
  }
  
  // ==========================================
  // 目录列表 - V2 风格
  // ==========================================
  .toc-list {
    .toc-item {
      display: flex;
      align-items: flex-start;
      padding: 10px 12px;
      border-radius: var(--radius-sm);
      cursor: pointer;
      transition: all 0.2s;
      font-size: 13px;
      line-height: 1.5;
      
      &:hover {
        background: var(--primary-light);
      }
      
      .toc-bullet {
        flex-shrink: 0;
        width: 14px;
        color: var(--primary);
        font-size: 8px;
        margin-top: 5px;
      }
      
      .toc-text {
        flex: 1;
        color: var(--text-1);
        word-break: break-word;
      }
      
      .toc-page {
        flex-shrink: 0;
        margin-left: 8px;
        color: var(--text-3);
        font-size: 11px;
      }
      
      // 层级缩进
      &.toc-level-1 {
        padding-left: 12px;
        font-weight: 600;
        .toc-bullet { font-size: 10px; }
      }
      
      &.toc-level-2 {
        padding-left: 28px;
        font-weight: 500;
      }
      
      &.toc-level-3 {
        padding-left: 44px;
        font-size: 12px;
        color: var(--text-2);
      }
    }
  }
  
  .toc-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    color: var(--text-3);
    
    .empty-icon {
      font-size: 48px;
      margin-bottom: 16px;
      opacity: 0.4;
    }
    
    .empty-text {
      font-size: 14px;
      color: var(--text-2);
      margin-bottom: 6px;
    }
    
    .empty-hint {
      font-size: 12px;
    }
  }
}

// ==========================================
// 上传区 - V2 风格
// ==========================================
.upload-zone {
  border: 2px dashed var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 16px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--white);
  transition: all 0.2s;

  &:hover {
    border-color: var(--primary);
    background: var(--primary-light);
  }

  :deep(.el-upload-dragger) {
    padding: 0 12px;
    border: none;
    background: transparent;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .upload-content {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .upload-icon {
    font-size: 18px;
  }

  .upload-text {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-1);
  }

  .upload-hint {
    display: block;
    font-size: 11px;
    color: var(--text-3);
    margin-top: 8px;
    text-align: center;
  }
}

.file-list {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

// ==========================================
// 文件项 - V2 风格
// ==========================================
.file-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all 0.2s;
  position: relative;

  &:hover {
    border-color: var(--primary);
    background: var(--primary-light);
  }
  
  &.active {
    border-color: var(--primary);
    background: var(--primary-light);
  }

  .file-icon {
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 13px;
    flex-shrink: 0;
    
    &.pdf { background: #ff6b6b; }
    &.docx, &.doc { background: #4dabf7; }
    &.xlsx, &.xls { background: #73d13d; }
    &.md { background: #9254de; }
    &.default { background: var(--text-3); }
  }

  .file-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;

    .file-name {
      font-size: 13px;
      font-weight: 600;
      color: var(--text-1);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .file-meta {
      font-size: 11px;
      color: var(--text-3);
      margin-top: 4px;

      .required {
        color: var(--danger);
      }
    }
  }
  
  .file-status {
    font-size: 11px;
    white-space: nowrap;
    
    &.parsing { color: var(--primary); }
    &.done { color: var(--success); }
  }
}

.add-source-btn {
  width: 100%;
  border-radius: var(--radius-md);
}

// ==========================================
// 中间面板 - V2 风格
// ==========================================
.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: var(--white);
  overflow: hidden;
  border-radius: var(--radius-md);
  margin: 0 8px;
  box-shadow: var(--shadow-sm);

  // ==========================================
  // 欢迎页 - V2 风格
  // ==========================================
  .welcome-page {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--white);
    
    .welcome-content {
      text-align: center;
      max-width: 600px;
      padding: 48px;
    }
    
    .welcome-logo {
      width: 80px;
      height: 80px;
      margin: 0 auto 32px;
      background: linear-gradient(135deg, var(--primary) 0%, #69c0ff 100%);
      border-radius: 16px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 40px;
      font-weight: 700;
      color: white;
      box-shadow: 0 12px 32px rgba(24, 144, 255, 0.3);
    }
    
    .welcome {
      h1 {
        font-size: 28px;
        font-weight: 700;
        color: var(--text-1);
        margin-bottom: 12px;
        line-height: 1.4;
        
        span {
          display: block;
          font-size: 20px;
          font-weight: 500;
          background: var(--ai-gradient);
          background-clip: text;
          -webkit-background-clip: text;
          -webkit-text-fill-color: transparent;
          margin-top: 8px;
        }
      }
      
      p {
        font-size: 15px;
        color: var(--text-3);
        line-height: 1.6;
      }
    }
  }

  // ==========================================
  // 编辑器标题栏 - V2 风格（集成工具栏）
  // ==========================================
  .editor-title-bar {
    padding: 12px 20px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--white);
    flex-shrink: 0;
    
    // 左侧：标题和保存状态
    .title-section {
      display: flex;
      align-items: center;
      gap: 10px;
      flex: 1;
      min-width: 0;
    }

    .title-input-wrapper {
      position: relative;
      display: inline-block;
      min-width: 150px;
      max-width: 300px;
      
      .title-input {
        width: 100%;

        :deep(.el-input__wrapper) {
          box-shadow: none;
          background: transparent;
          border-radius: var(--radius-sm);
          padding: 0 8px;

          &:hover {
            background: var(--bg);
          }
          
          &.is-focus {
            background: var(--white);
            box-shadow: 0 0 0 2px var(--primary-light);
          }
        }
        
        :deep(.el-input__inner) {
          font-size: 15px;
          font-weight: 600;
          color: var(--text-1);
        }
      }
      
      .title-measure {
        position: absolute;
        visibility: hidden;
        white-space: nowrap;
        font-size: 15px;
        font-weight: 600;
        padding: 0 8px;
        pointer-events: none;
      }
    }

    .save-status {
      display: flex;
      align-items: center;
      gap: 4px;
      color: var(--success);
      font-size: 12px;
      white-space: nowrap;
    }
    
    // 中间：视图切换
    .view-toggle {
      display: flex;
      align-items: center;
      
      :deep(.el-radio-group) {
        .el-radio-button__inner {
          padding: 6px 12px;
          font-size: 12px;
        }
      }
    }
    
    // 右侧：操作按钮
    .toolbar-actions {
      display: flex;
      gap: 8px;
      align-items: center;
      flex-shrink: 0;
      
      :deep(.el-button) {
        border-radius: var(--radius-sm);
        
        &:not(.el-button--primary) {
          border-color: var(--border);
          
          &:hover {
            border-color: var(--primary);
            color: var(--primary);
            background: var(--primary-light);
          }
        }
        
        &.el-button--primary {
          background: var(--primary-gradient);
          border: none;
          
          &:hover {
            box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
          }
        }
      }
      
      :deep(.el-divider--vertical) {
        height: 20px;
        margin: 0 4px;
      }
    }
  }

  // ==========================================
  // 编辑器滚动区 - V2 风格
  // ==========================================
  .editor-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 40px 48px;
    background: var(--white);
  }

  .editor-content {
    max-width: 1000px;
    margin: 0 auto;
    outline: none;
    
    // 文档块样式
    :deep(.doc-block) {
      position: relative;
      transition: background-color 0.2s;
      
      &:hover {
        background-color: rgba(24, 144, 255, 0.02);
      }
      
      // 被选中时的样式
      &.selected {
        background-color: rgba(24, 144, 255, 0.08);
        outline: 1px dashed var(--primary);
      }
    }

    :deep(h1) {
      font-size: 24px;
      font-weight: 700;
      margin-bottom: 24px;
    }

    :deep(h2) {
      font-size: 18px;
      font-weight: 600;
      margin: 28px 0 16px;
    }

    :deep(p) {
      margin-bottom: 12px;
      line-height: 1.6;
    }

    :deep(ul) {
      margin-bottom: 16px;
      padding-left: 24px;

      li {
        margin-bottom: 8px;
      }
    }
    
    // 目录样式
    :deep(.doc-toc-title) {
      font-size: 18pt;
      font-weight: bold;
      text-align: center;
      margin: 20px 0 16px;
    }
    
    :deep(.doc-toc-item) {
      display: flex;
      align-items: baseline;
      padding: 6px 0;
      line-height: 1.6;
      cursor: pointer;
      transition: background-color 0.2s;
      
      &:hover {
        background-color: #f5f5f5;
      }
      
      .toc-title {
        flex-shrink: 0;
        white-space: nowrap;
      }
      
      .toc-dots {
        flex: 1;
        border-bottom: 1px dotted #999;
        margin: 0 8px;
        min-width: 20px;
        height: 0.6em;
      }
      
      .toc-page {
        flex-shrink: 0;
        color: #666;
        min-width: 20px;
        text-align: right;
      }
    }
    
    // 表格样式
    :deep(.doc-table-container) {
      margin: 16px 0;
      overflow-x: auto;
    }
    
    :deep(.doc-table) {
      width: 100%;
      border-collapse: collapse;
      font-size: 14px;
      
      th, td {
        border: 1px solid #ddd;
        padding: 8px 12px;
        text-align: left;
        vertical-align: top;
        line-height: 1.5;
      }
      
      th {
        background-color: #f5f5f5;
        font-weight: bold;
      }
      
      tr:nth-child(even) td {
        background-color: #fafafa;
      }
      
      tr:hover td {
        background-color: #f0f7ff;
      }
    }
    
    :deep(.doc-table-empty) {
      padding: 20px;
      text-align: center;
      color: #999;
      border: 1px dashed #ddd;
      margin: 16px 0;
    }
    
    // 列表项样式
    :deep(.doc-list-item) {
      position: relative;
      margin-bottom: 8px;
      line-height: 1.6;
      
      &.bullet {
        padding-left: 1.5em;
        &::before {
          content: '•';
          position: absolute;
          left: 0;
        }
      }
      
      &.ordered {
        padding-left: 2em;
        counter-increment: doc-list;
        &::before {
          content: counter(doc-list) '.';
          position: absolute;
          left: 0;
        }
      }
    }
    
    // 重置列表计数器
    :deep(p + .doc-list-item.ordered:first-of-type),
    :deep(.doc-list-item.bullet + .doc-list-item.ordered) {
      counter-reset: doc-list;
    }
    
    // 块引用样式
    :deep(blockquote) {
      margin: 16px 0;
      padding: 12px 20px;
      border-left: 4px solid #ddd;
      background: #f9f9f9;
      color: #666;
    }
    
    // 代码块样式
    :deep(pre) {
      margin: 16px 0;
      padding: 16px;
      background: #f5f5f5;
      border-radius: 4px;
      overflow-x: auto;
      
      code {
        font-family: 'Consolas', 'Monaco', monospace;
        font-size: 13px;
      }
    }
    
    // 实体高亮样式 - 匹配原型 UI（边框 + 背景）
    :deep(.entity-highlight) {
      display: inline;
      padding: 2px 8px;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.2s;
      font-weight: 500;
      border: 1px solid #1890ff;
      color: #1890ff;
      background: rgba(24, 144, 255, 0.1);
      
      &:hover {
        background: #1890ff;
        color: white;
      }
      
      // 实体类型颜色
      &.entity {
        border-color: #1890ff;
        color: #1890ff;
        background: rgba(24, 144, 255, 0.1);
        &:hover { background: #1890ff; color: white; }
      }
      
      &.concept {
        border-color: #722ed1;
        color: #722ed1;
        background: rgba(114, 46, 209, 0.1);
        &:hover { background: #722ed1; color: white; }
      }
      
      &.data {
        border-color: #52c41a;
        color: #52c41a;
        background: rgba(82, 196, 26, 0.1);
        &:hover { background: #52c41a; color: white; }
      }
      
      &.location {
        border-color: #faad14;
        color: #d48806;
        background: rgba(250, 173, 20, 0.1);
        &:hover { background: #faad14; color: white; }
      }
      
      &.asset {
        border-color: #eb2f96;
        color: #eb2f96;
        background: rgba(235, 47, 150, 0.1);
        &:hover { background: #eb2f96; color: white; }
      }
      
      &.person {
        border-color: #1890ff;
        color: #1890ff;
        background: rgba(24, 144, 255, 0.1);
        &:hover { background: #1890ff; color: white; }
      }
      
      &.org {
        border-color: #722ed1;
        color: #722ed1;
        background: rgba(114, 46, 209, 0.1);
        &:hover { background: #722ed1; color: white; }
      }
      
      &.date {
        border-color: #13c2c2;
        color: #13c2c2;
        background: rgba(19, 194, 194, 0.1);
        &:hover { background: #13c2c2; color: white; }
      }
      
      &.product {
        border-color: #eb2f96;
        color: #eb2f96;
        background: rgba(235, 47, 150, 0.1);
        &:hover { background: #eb2f96; color: white; }
      }
      
      &.event {
        border-color: #fa8c16;
        color: #fa8c16;
        background: rgba(250, 140, 22, 0.1);
        &:hover { background: #fa8c16; color: white; }
      }
      
      &.law {
        border-color: #2f54eb;
        color: #2f54eb;
        background: rgba(47, 84, 235, 0.1);
        &:hover { background: #2f54eb; color: white; }
      }
    }
  }
}

// ==========================================
// 右侧面板 - V2 风格
// ==========================================
.right-panel {
  background: var(--white);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  min-width: 280px;
  max-width: 500px;
  overflow: hidden;
  
  // 右侧面板分为上下两部分
  .element-section {
    flex: 4;
    overflow-y: auto;
    min-height: 0;
  }
  
  .ai-assistant {
    flex: 6;
    overflow-y: auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
}

// ==========================================
// 要素管理区 - V2 风格
// ==========================================
.element-section {
  padding: 16px;
  border-bottom: 1px dashed var(--border);
  
  // 模块标题样式 - V2 风格
  .module-title {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-1);
    margin-bottom: 14px;
    
    .module-icon {
      width: 36px;
      height: 36px;
      border-radius: 8px;
      background: var(--primary-gradient);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 18px;
      color: white;
      box-shadow: var(--shadow-md);
    }
  }

  .element-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;

    .element-title {
      font-size: 13px;
      font-weight: 600;
      display: flex;
      align-items: center;
      gap: 6px;

      .element-count {
        font-size: 11px;
        color: var(--text-3);
        font-weight: normal;
      }
    }
    
    // 要素 Tab 切换 - V2 风格
    .element-tabs {
      display: flex;
      gap: 8px;
      
      .element-tab {
        padding: 6px 12px;
        border-radius: 12px;
        background: transparent;
        border: 1px solid transparent;
        font-size: 13px;
        cursor: pointer;
        color: var(--text-2);
        transition: all 0.2s;
        
        &:hover {
          background: var(--bg);
        }
        
        &.active {
          background: var(--primary);
          color: #fff;
          border-color: rgba(0, 0, 0, 0.04);
          box-shadow: var(--shadow-md);
        }
      }
    }
  }

  .element-filter {
    padding: 0 0 12px;
    
    .entity-search {
      margin-bottom: 12px;
      
      :deep(.el-input__wrapper) {
        border-radius: 18px;
        background: var(--bg);
        box-shadow: none;
        border: 1px solid var(--border);
        
        &:hover, &.is-focus {
          border-color: var(--primary);
          background: var(--white);
        }
      }
    }
    
    .entity-type-filter {
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
      
      .filter-tag {
        cursor: pointer;
        transition: all 0.2s;
        border-radius: 12px;
        font-size: 11px;
        
        &:hover {
          border-color: var(--primary);
          color: var(--primary);
        }
        
        &.active {
          background: var(--primary);
          color: white;
          border-color: var(--primary);
        }
        
        &.clear {
          background: transparent;
          border-style: dashed;
          color: var(--text-3);
          
          &:hover {
            border-color: var(--danger);
            color: var(--danger);
          }
        }
      }
    }
  }

  .element-body {
    padding: 0;
  }

  // 要素标签容器 - V2 风格
  .element-tags-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    max-height: 200px;
    overflow-y: auto;
    padding-right: 4px;
    padding-bottom: 16px;
    
    &::-webkit-scrollbar {
      width: 4px;
    }
    
    &::-webkit-scrollbar-track {
      background: var(--bg);
      border-radius: 2px;
    }
    
    &::-webkit-scrollbar-thumb {
      background: var(--border);
      border-radius: 2px;
      
      &:hover {
        background: var(--text-3);
      }
    }
  }
  
  .load-more-wrap {
    width: 100%;
    text-align: center;
    padding: 10px 0;
    margin-top: 8px;
    border-top: 1px dashed var(--border);
  }
  
  // ==========================================
  // 要素标签样式 - V2 风格
  // ==========================================
  .var-tag {
    height: 28px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px;
    border-radius: 2px;
    font-size: 12px;
    cursor: pointer;
    transition: all 0.2s;
    background: var(--bg);
    border: 1px solid var(--border);
    user-select: none;
    
    &:hover {
      border-color: var(--primary);
      background: var(--primary-light);
      transform: translateY(-1px);
    }
    
    &:active {
      cursor: grabbing;
    }
    
    .tag-icon {
      font-size: 12px;
    }
    
    .tag-name {
      max-width: 120px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      font-weight: 500;
      line-height: 28px;
    }
    
    .tag-status {
      color: #52c41a;
      font-size: 10px;
    }
    
    // 动态要素样式（圆角）
    &.dynamic {
      border-radius: 14px;
    }
    
    // 静态要素样式（微圆角）
    &.static {
      border-radius: 2px;
    }
    
    // 已确认状态
    &.confirmed {
      background: rgba(82, 196, 26, 0.1);
      border-color: #52c41a;
      
      .tag-name {
        color: #389e0d;
      }
    }
    
    // 实体类型样式 - 左边框颜色区分
    &.entity-person, &.entity {
      border-left: 3px solid var(--primary);
    }
    &.entity-org, &.concept {
      border-left: 3px solid #722ed1;
    }
    &.entity-location, &.location {
      border-left: 3px solid var(--warning);
    }
    &.entity-date {
      border-left: 3px solid #13c2c2;
    }
    &.entity-data, &.data {
      border-left: 3px solid var(--success);
    }
    &.entity-product, &.asset {
      border-left: 3px solid #eb2f96;
    }
    &.entity-event {
      border-left: 3px solid #fa8c16;
    }
    &.entity-law {
      border-left: 3px solid #2f54eb;
    }
    &.entity-default {
      border-left: 3px solid #8c8c8c;
    }
  }

  .element-hint {
    font-size: 12px;
    color: var(--text-3);
    text-align: center;
    padding: 24px;
  }
}

// 实体高亮闪烁效果
@keyframes entity-flash {
  0%, 100% { background-color: inherit; }
  50% { background-color: #ffe58f; }
}

.entity-highlight-flash {
  animation: entity-flash 0.5s ease-in-out 3;
}

// 实体编辑弹窗样式
.entity-edit-form {
  .entity-edit-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 16px;
    background: var(--primary-light);
    border: 1px dashed var(--primary);
    border-radius: 8px;
    margin-bottom: 20px;
    
    .preview-icon {
      font-size: 24px;
    }
    
    .preview-text {
      font-size: 16px;
      font-weight: 600;
      color: var(--primary);
    }
  }
}

.category-section {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);

  .category-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 10px;

    .category-dot {
      width: 10px;
      height: 10px;
      border-radius: 50%;
    }

    .category-count {
      color: var(--text-3);
      font-weight: normal;
      background: var(--bg);
      padding: 2px 8px;
      border-radius: 10px;
    }
  }

  .category-items {
    .category-item {
      display: flex;
      justify-content: space-between;
      padding: 8px 12px;
      background: var(--bg);
      border-radius: 6px;
      margin-bottom: 6px;
      cursor: pointer;
      font-size: 12px;
      transition: all 0.2s;

      &:hover {
        background: var(--primary-light);
      }

      .item-value {
        color: var(--text-3);
      }
    }
  }
}

// ==========================================
// 右键菜单 - V2 风格
// ==========================================
.context-menu {
  position: fixed;
  min-width: 180px;
  background: var(--white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: 3000;
  overflow: hidden;

  .context-menu-header {
    padding: 12px 14px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    
    .selected-preview {
      font-size: 12px;
      color: var(--primary);
      font-weight: 600;
      max-width: 150px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
  
  .context-menu-section {
    padding: 8px 14px 4px;
    font-size: 10px;
    color: var(--text-3);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }

  .context-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    font-size: 13px;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-1);

    &:hover {
      background: var(--primary-light);
      color: var(--primary);
    }
    
    &[disabled="true"] {
      opacity: 0.5;
      pointer-events: none;
    }

    .icon {
      font-size: 14px;
      width: 20px;
      text-align: center;
    }
    
    .shortcut {
      margin-left: auto;
      font-size: 11px;
      color: var(--text-3);
    }
  }
  
  .context-menu-divider {
    height: 1px;
    background: var(--border);
    margin: 4px 0;
  }
  
  .context-menu-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px;
    color: var(--primary);
    font-size: 12px;
    border-top: 1px solid var(--border);
    background: var(--bg);
  }
}

// ==========================================
// 实体弹出框样式 - V2 风格
// ==========================================
.entity-popover {
  .entity-popover-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
    
    .entity-text {
      font-weight: 600;
      font-size: 14px;
      max-width: 140px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      color: var(--text-1);
    }
  }
  
  .entity-popover-type {
    font-size: 12px;
    color: var(--text-2);
    margin-bottom: 14px;
    padding: 4px 8px;
    background: var(--bg);
    border-radius: 4px;
    display: inline-block;
  }
  
  .entity-popover-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    
    :deep(.el-button) {
      border-radius: var(--radius-sm);
    }
  }
}

// ==========================================
// 知识图谱容器 - V2 风格
// ==========================================
.graph-container {
  height: 500px;
  position: relative;
  background: linear-gradient(45deg, #f8f9fa 25%, transparent 25%), 
              linear-gradient(-45deg, #f8f9fa 25%, transparent 25%), 
              linear-gradient(45deg, transparent 75%, #f8f9fa 75%), 
              linear-gradient(-45deg, transparent 75%, #f8f8f8 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
  border-radius: var(--radius-md);

  .graph-legend {
    position: absolute;
    top: 16px;
    left: 16px;
    background: var(--white);
    border-radius: var(--radius-md);
    padding: 14px 18px;
    box-shadow: var(--shadow-md);

    .legend-title {
      font-size: 12px;
      font-weight: 600;
      margin-bottom: 10px;
      color: var(--text-1);
    }

    .legend-item {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 12px;
      color: var(--text-2);
      margin-bottom: 6px;
      
      &:last-child {
        margin-bottom: 0;
      }
    }

    .legend-dot {
      width: 12px;
      height: 12px;
      border-radius: 50%;

      &.core, &.entity { background: var(--primary); }
      &.concept { background: #722ed1; }
      &.data { background: var(--success); }
      &.location { background: var(--warning); }
    }
  }

  .graph-body {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;

    .graph-placeholder {
      text-align: center;
      color: var(--text-3);
      
      .placeholder-icon {
        font-size: 48px;
        margin-bottom: 16px;
        opacity: 0.5;
      }

      p {
        margin-top: 12px;
        font-size: 14px;
      }
    }
  }
}

// ==========================================
// 空白编辑器占位提示样式 - V2 风格
// ==========================================
:deep(.empty-editor-placeholder) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 40px;
  text-align: center;
  min-height: 400px;

  .empty-icon {
    font-size: 64px;
    margin-bottom: 24px;
    opacity: 0.8;
  }

  h2 {
    font-size: 24px;
    font-weight: 600;
    margin-bottom: 12px;
    color: var(--text-1);
  }

  .empty-subtitle {
    font-size: 15px;
    color: var(--text-3);
    margin-bottom: 32px;
  }

  .empty-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 32px;
    width: 100%;
    max-width: 400px;
  }

  .action-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 20px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all 0.2s;
    text-align: left;

    &:hover {
      border-color: var(--primary);
      background: var(--primary-light);
      transform: translateX(4px);
    }

    .action-icon {
      font-size: 24px;
      flex-shrink: 0;
    }

    .action-text {
      font-size: 14px;
      color: var(--text-1);
      font-weight: 500;
    }
  }

  .empty-hint {
    font-size: 13px;
    color: var(--text-3);
    padding: 12px 20px;
    background: var(--bg);
    border-radius: var(--radius-md);
    border-left: 3px solid var(--primary);
  }
}

// 高亮块动画
.highlight-block {
  animation: highlight-pulse 2s ease-out;
}

@keyframes highlight-pulse {
  0% {
    background: rgba(24, 144, 255, 0.3);
    box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
  }
  100% {
    background: transparent;
    box-shadow: none;
  }
}
</style>
