<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 === 'projects' }"
            @click="leftPanelTab = 'projects'"
          >
            📄 项目
            <span class="tab-count">{{ projects.length }}</span>
          </div>
          <transition name="tab-slide">
            <div 
              v-if="hasActiveProject"
              class="panel-tab" 
              :class="{ active: leftPanelTab === 'attachments' }"
              @click="leftPanelTab = 'attachments'"
            >
              📁 附件
              <span class="tab-count">{{ attachments.length }}</span>
            </div>
          </transition>
          <transition name="tab-slide">
            <div 
              v-if="hasActiveProject"
              class="panel-tab" 
              :class="{ active: leftPanelTab === 'rules' }"
              @click="leftPanelTab = 'rules'"
            >
              ⚙️ 规则
              <span class="tab-count">{{ rules.length }}</span>
            </div>
          </transition>
        </div>

        <!-- 项目列表面板 -->
        <div class="panel-body reports-panel" v-show="leftPanelTab === 'projects'">
          <el-button 
            class="new-report-btn" 
            type="primary" 
            :icon="Plus"
            @click="showNewProjectDialog = true"
          >
            新建项目
          </el-button>

          <el-input
            v-model="projectSearchKeyword"
            placeholder="搜索项目..."
            :prefix-icon="Search"
            clearable
            class="report-search"
          />

          <div class="report-list" v-if="filteredProjects.length > 0">
            <div
              v-for="project in filteredProjects"
              :key="project.id"
              class="report-item"
              :class="{ active: currentProjectId === project.id }"
              @click="switchProject(project)"
            >
              <div class="report-icon">📄</div>
              <div class="report-info">
                <div class="report-name">{{ project.title }}</div>
                <div class="report-meta">
                  <span class="report-time">{{ formatTime(project.updatedAt || project.createdAt) }}</span>
                  <span class="report-status" :class="project.status">
                    {{ getStatusText(project.status) }}
                  </span>
                </div>
              </div>
              <el-dropdown trigger="click" @command="(cmd) => handleProjectCommand(cmd, project)" @click.stop>
                <el-button class="report-delete-btn" circle size="small">
                  <el-icon><MoreFilled /></el-icon>
                </el-button>
                <template #dropdown>
                  <el-dropdown-menu>
                    <el-dropdown-item command="copy">复制项目</el-dropdown-item>
                    <el-dropdown-item command="archive">归档</el-dropdown-item>
                    <el-dropdown-item command="delete" divided>删除</el-dropdown-item>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </div>
          </div>
          
          <div class="report-empty" v-else-if="!loadingProjects">
            <div class="empty-icon">📄</div>
            <div class="empty-text">{{ projectSearchKeyword ? '未找到匹配的项目' : '暂无项目' }}</div>
            <div class="empty-hint">点击上方按钮创建新项目</div>
          </div>

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

        <!-- 附件面板 -->
        <div class="panel-body" v-show="leftPanelTab === 'attachments'">
          <el-upload
            class="upload-zone"
            drag
            :auto-upload="false"
            :on-change="handleAttachmentUpload"
            :show-file-list="false"
            accept=".pdf,.doc,.docx,.xls,.xlsx"
          >
            <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="att in attachments"
              :key="att.id"
              class="file-item"
              :class="{ active: selectedAttachment?.id === att.id }"
              @click="selectAttachment(att)"
            >
              <span class="file-icon">{{ getFileIcon(att) }}</span>
              <div class="file-info">
                <div class="file-name">{{ att.displayName }}</div>
                <div class="file-meta">
                  <span>{{ att.entityCount || 0 }} 个实体</span>
                </div>
              </div>
              <el-button
                size="small"
                :icon="Delete"
                circle
                @click.stop="removeAttachment(att)"
              />
            </div>
          </div>
        </div>

        <!-- 规则面板 -->
        <div class="panel-body" v-show="leftPanelTab === 'rules'">
          <el-button
            class="new-report-btn"
            :icon="Plus"
            @click="showNewRuleDialog = true"
          >
            添加规则
          </el-button>
          <el-button
            v-if="rules.length > 0"
            type="success"
            size="small"
            style="margin: 8px 0; width: 100%;"
            @click="handleBatchExecuteRules"
            :loading="executingRules"
          >
            批量执行规则
          </el-button>
          <div class="file-list">
            <div
              v-for="rule in rules"
              :key="rule.id"
              class="file-item"
            >
              <span class="file-icon">⚙️</span>
              <div class="file-info">
                <div class="file-name">{{ rule.ruleName }}</div>
                <div class="file-meta">
                  <el-tag size="small" :type="rule.lastRunStatus === 'success' ? 'success' : rule.lastRunStatus === 'failed' ? 'danger' : 'info'">
                    {{ rule.ruleType }}
                  </el-tag>
                </div>
              </div>
              <el-button size="small" type="primary" text @click.stop="handleExecuteRule(rule)" title="执行">▶</el-button>
              <el-button size="small" :icon="Delete" circle @click.stop="handleDeleteRule(rule)" />
            </div>
          </div>
        </div>
      </div>

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

      <!-- 中间主区域 -->
      <div class="center-panel">
        <!-- 欢迎页 -->
        <div class="welcome-page" v-if="!hasActiveProject">
          <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">
              <el-input v-model="projectTitle" class="title-input" placeholder="请输入项目标题" style="width: 300px;" />
              <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="document">📄 文档</el-radio-button>
                <el-radio-button value="elements">📝 要素</el-radio-button>
                <el-radio-button value="entities">🏷️ 实体</el-radio-button>
              </el-radio-group>
            </div>
            <div class="toolbar-actions">
              <el-button size="small" @click="handleCopyProject" :icon="CopyDocument">复制</el-button>
              <el-divider direction="vertical" />
              <el-button size="small" type="primary" :icon="Check" @click="handleSave">保存</el-button>
            </div>
          </div>

          <div class="editor-scroll" ref="editorRef" v-loading="loading" element-loading-text="正在加载项目...">
            <!-- 文档视图 -->
            <div class="document-view" v-if="viewMode === 'document'">
              <!-- 工具栏 -->
              <div class="doc-toolbar">
                <div class="doc-toolbar-left" v-if="attachments.length > 0">
                  <span class="doc-att-label">附件：</span>
                  <el-select v-model="docAttachmentId" placeholder="选择附件" size="small" style="width: 240px;" @change="loadDocContent">
                    <el-option v-for="att in attachments" :key="att.id" :label="att.displayName" :value="att.id" />
                  </el-select>
                </div>
                <div class="doc-toolbar-right">
                  <el-switch v-model="highlightEnabled" active-text="要素高亮" inactive-text="" size="small" style="margin-right: 12px;" @change="renderDocHtml" />
                  <el-tag v-if="highlightEnabled" size="small" type="info">{{ elementHighlightCount }} 处高亮</el-tag>
                </div>
              </div>

              <!-- 文档渲染区域（可编辑） -->
              <div
                class="doc-paper"
                v-if="docHtml"
                :style="docPaperStyle"
                contenteditable="true"
                spellcheck="false"
                v-html="docHtml"
                @input="onDocInput"
                @click="onDocClick"
                ref="docPaperRef"
              ></div>

              <!-- 无内容提示 -->
              <div class="doc-empty" v-else-if="!docLoading && docAttachmentId">
                <el-empty description="该附件暂无解析内容" />
              </div>
              <div class="doc-empty" v-else-if="!docLoading && attachments.length === 0">
                <el-empty description="暂无附件，请先在左侧上传文档" />
              </div>
              <div class="doc-empty" v-else-if="!docLoading && !docAttachmentId">
                <el-empty description="请选择一个附件查看文档内容" />
              </div>
              <div class="doc-loading" v-if="docLoading">
                <el-icon class="is-loading" :size="24"><Loading /></el-icon>
                <span>正在加载文档内容...</span>
              </div>
            </div>

            <!-- 要素高亮弹出框 -->
            <div
              v-if="highlightPopover.visible"
              class="element-popover"
              :style="{ top: highlightPopover.y + 'px', left: highlightPopover.x + 'px' }"
            >
              <div class="popover-header">
                <span class="popover-label">{{ highlightPopover.elementName }}</span>
                <el-tag size="small">{{ highlightPopover.elementKey }}</el-tag>
              </div>
              <div class="popover-body">
                <div class="popover-field">
                  <span class="popover-field-label">当前值：</span>
                  <el-input
                    v-model="highlightPopover.currentValue"
                    size="small"
                    placeholder="输入要素值"
                    @keyup.enter="savePopoverValue"
                  />
                </div>
                <div class="popover-field" v-if="highlightPopover.originalValue">
                  <span class="popover-field-label">原始值：</span>
                  <span class="popover-original">{{ highlightPopover.originalValue }}</span>
                </div>
              </div>
              <div class="popover-footer">
                <el-button size="small" @click="highlightPopover.visible = false">关闭</el-button>
                <el-button size="small" type="primary" @click="savePopoverValue">保存</el-button>
              </div>
            </div>

            <!-- 要素视图 -->
            <div class="elements-view" v-if="viewMode === 'elements'">
              <div class="elements-grid">
                <div class="element-card" v-for="elem in elements" :key="elem.id">
                  <div class="element-card-header">
                    <span class="element-label">{{ elem.elementName }}</span>
                    <el-tag size="small" :type="elem.dataType === 'text' ? '' : 'warning'">{{ elem.dataType || '文本' }}</el-tag>
                  </div>
                  <div class="element-card-body">
                    <div class="element-value-row" v-for="val in getElementValues(elem.elementKey)" :key="val.valueId">
                      <el-input v-model="val.valueText" placeholder="暂无值" size="small" @change="onValueChange(val)" />
                      <div class="value-meta" v-if="val.fillSource">
                        <span class="original-label">来源:</span>
                        <span class="original-value">{{ val.fillSource }}</span>
                      </div>
                      <div class="value-status">
                        <el-tag v-if="val.isFilled" type="success" size="small">已填充</el-tag>
                        <el-tag v-else type="info" size="small">待填充</el-tag>
                      </div>
                    </div>
                    <div class="element-empty" v-if="getElementValues(elem.elementKey).length === 0">
                      <span class="empty-hint">暂无值，请通过规则填充或手动输入</span>
                    </div>
                  </div>
                </div>
              </div>
              <div class="elements-empty" v-if="elements.length === 0">
                <el-empty description="暂无要素定义">
                  <el-button type="primary" :icon="Plus" @click="showAddElementDialog = true">添加要素</el-button>
                </el-empty>
              </div>
            </div>

            <!-- 实体视图 -->
            <div class="entities-view" v-if="viewMode === 'entities'">
              <div class="entity-filter-bar">
                <el-input v-model="entitySearchKeyword" placeholder="搜索实体..." :prefix-icon="Search" clearable style="width: 300px;" />
                <el-select v-model="entityTypeFilter" placeholder="实体类型" clearable style="width: 150px; margin-left: 12px;">
                  <el-option label="全部" value="" />
                  <el-option label="组织机构" value="ORG" />
                  <el-option label="人物" value="PERSON" />
                  <el-option label="日期" value="DATE" />
                  <el-option label="编号" value="CODE" />
                  <el-option label="数值" value="NUMBER" />
                </el-select>
              </div>
              <el-table :data="filteredEntities" style="width: 100%" stripe max-height="calc(100vh - 220px)">
                <el-table-column prop="entityText" label="实体文本" min-width="200" />
                <el-table-column prop="entityType" label="类型" width="120">
                  <template #default="{ row }">
                    <el-tag size="small">{{ getEntityTypeName(row.entityType) }}</el-tag>
                  </template>
                </el-table-column>
                <el-table-column prop="businessLabel" label="业务标签" width="150" />
                <el-table-column prop="confidence" label="置信度" width="100">
                  <template #default="{ row }">
                    <span v-if="row.confidence">{{ (row.confidence * 100).toFixed(0) }}%</span>
                    <span v-else>-</span>
                  </template>
                </el-table-column>
                <el-table-column prop="sourceAttachment" label="来源附件" width="150" />
              </el-table>
              <div class="entities-empty" v-if="entities.length === 0">
                <el-empty description="暂无实体，请先上传附件并解析" />
              </div>
            </div>
          </div>
        </template>
      </div>

      <!-- 右侧拖拽分隔条 -->
      <div v-if="hasActiveProject" class="resize-handle right-resize" @mousedown="startResizeRight"></div>

      <!-- 右侧面板 -->
      <div v-if="hasActiveProject" class="right-panel" :style="{ width: rightPanelWidth + 'px' }">
        <div class="element-section">
          <div class="element-header">
            <span class="element-title">📊 项目概览</span>
          </div>
          <div class="element-body">
            <div class="overview-stats">
              <div class="stat-item"><span class="stat-label">要素数</span><span class="stat-value">{{ elements.length }}</span></div>
              <div class="stat-item"><span class="stat-label">已填充</span><span class="stat-value filled">{{ filledValueCount }}</span></div>
              <div class="stat-item"><span class="stat-label">附件数</span><span class="stat-value">{{ attachments.length }}</span></div>
              <div class="stat-item"><span class="stat-label">实体数</span><span class="stat-value">{{ entities.length }}</span></div>
              <div class="stat-item"><span class="stat-label">规则数</span><span class="stat-value">{{ rules.length }}</span></div>
            </div>
          </div>
        </div>

        <div class="element-section">
          <div class="element-header">
            <span class="element-title">🏷️ 要素列表 <span class="element-count">({{ elements.length }})</span></span>
            <el-button size="small" type="primary" :icon="Plus" @click="showAddElementDialog = true">添加</el-button>
          </div>
          <div class="element-body">
            <div class="element-tags-wrap" v-if="elements.length > 0">
              <div v-for="elem in elements" :key="elem.id" class="var-tag confirmed" :title="elem.elementName">
                <span class="tag-name">{{ elem.elementName }}</span>
                <span class="tag-status" v-if="hasFilledValue(elem.elementKey)">✓</span>
              </div>
            </div>
            <div class="element-hint" v-else>暂无要素，点击添加按钮创建</div>
          </div>
        </div>

        <div class="element-section" v-if="entities.length > 0">
          <div class="element-header">
            <span class="element-title">🔍 实体摘要 <span class="element-count">({{ entities.length }})</span></span>
          </div>
          <div class="element-body">
            <div class="element-tags-wrap">
              <div v-for="entity in entities.slice(0, 20)" :key="entity.id" class="var-tag" :class="getEntityTypeClass(entity.entityType)" :title="entity.entityText">
                <span class="tag-icon">{{ getEntityTypeIcon(entity.entityType) }}</span>
                <span class="tag-name">{{ entity.entityText }}</span>
              </div>
              <div v-if="entities.length > 20" class="element-hint" style="margin-top: 8px;">还有 {{ entities.length - 20 }} 个实体...</div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 新建项目对话框 -->
    <el-dialog v-model="showNewProjectDialog" title="新建项目" width="460" :close-on-click-modal="false">
      <el-form :model="newProjectForm" label-width="80px">
        <el-form-item label="项目名称" required>
          <el-input v-model="newProjectForm.title" placeholder="请输入项目名称" maxlength="100" show-word-limit />
        </el-form-item>
        <el-form-item label="项目描述">
          <el-input v-model="newProjectForm.description" type="textarea" :rows="3" placeholder="项目描述（可选）" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showNewProjectDialog = false">取消</el-button>
        <el-button type="primary" @click="handleCreateProject" :disabled="!newProjectForm.title.trim()" :loading="creatingProject">创建</el-button>
      </template>
    </el-dialog>

    <!-- 添加要素对话框 -->
    <el-dialog v-model="showAddElementDialog" title="添加要素" width="500">
      <el-form :model="newElementForm" label-width="100px">
        <el-form-item label="要素名称" required>
          <el-input v-model="newElementForm.elementName" placeholder="如：项目编号" />
        </el-form-item>
        <el-form-item label="要素标识" required>
          <el-input v-model="newElementForm.elementKey" placeholder="如：basicInfo.projectCode" />
        </el-form-item>
        <el-form-item label="数据类型">
          <el-select v-model="newElementForm.dataType" style="width: 100%">
            <el-option label="文本" value="text" />
            <el-option label="数字" value="number" />
            <el-option label="日期" value="date" />
            <el-option label="金额" value="money" />
          </el-select>
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="newElementForm.description" type="textarea" :rows="2" placeholder="要素描述" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showAddElementDialog = false">取消</el-button>
        <el-button type="primary" @click="handleAddElement" :disabled="!newElementForm.elementName || !newElementForm.elementKey">添加</el-button>
      </template>
    </el-dialog>

    <!-- 添加规则对话框 -->
    <el-dialog v-model="showNewRuleDialog" title="添加规则" width="500">
      <el-form :model="newRuleForm" label-width="100px">
        <el-form-item label="规则名称" required>
          <el-input v-model="newRuleForm.ruleName" placeholder="如：项目编号-直接引用实体" />
        </el-form-item>
        <el-form-item label="规则类型" required>
          <el-select v-model="newRuleForm.ruleType" style="width: 100%">
            <el-option label="直接引用实体" value="direct_entity" />
            <el-option label="AI 提取" value="ai_extract" />
            <el-option label="固定值" value="fixed_value" />
            <el-option label="计算公式" value="formula" />
          </el-select>
        </el-form-item>
        <el-form-item label="目标要素">
          <el-select v-model="newRuleForm.targetElementKey" style="width: 100%" placeholder="选择要填充的要素">
            <el-option v-for="elem in elements" :key="elem.elementKey" :label="elem.elementName" :value="elem.elementKey" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showNewRuleDialog = false">取消</el-button>
        <el-button type="primary" @click="handleCreateRule" :disabled="!newRuleForm.ruleName">创建</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { Plus, Delete, Search, Loading, Check, CopyDocument, MoreFilled } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { projectApi, elementApi, valueApi, attachmentApi, entityApi, ruleApi } from '@/api'

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

const currentProjectId = ref(null)
const hasActiveProject = computed(() => !!currentProjectId.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 projectTitle = ref('')
const viewMode = ref('document')
const saved = ref(true)
const editorRef = ref(null)
const loading = ref(false)
const leftPanelWidth = ref(300)
const rightPanelWidth = ref(340)
const isResizing = ref(false)
const resizeType = ref('')
const leftPanelTab = ref('projects')

const projects = ref([])
const loadingProjects = ref(false)
const projectSearchKeyword = ref('')
const elements = ref([])
const values = ref([])
const attachments = ref([])
const entities = ref([])
const rules = ref([])
const selectedAttachment = ref(null)
const entitySearchKeyword = ref('')
const entityTypeFilter = ref('')
const executingRules = ref(false)

// 文档预览状态
const docAttachmentId = ref(null)
const docContent = ref(null)
const docLoading = ref(false)
const docHtml = ref('')
const docPaperRef = ref(null)
const highlightEnabled = ref(true)
const elementHighlightCount = ref(0)
const highlightPopover = reactive({
  visible: false, x: 0, y: 0,
  elementKey: '', fullElementKey: '', elementName: '', currentValue: '', originalValue: '', valueId: null
})

const showNewProjectDialog = ref(false)
const showAddElementDialog = ref(false)
const showNewRuleDialog = ref(false)
const creatingProject = ref(false)
const newProjectForm = reactive({ title: '', description: '' })
const newElementForm = reactive({ elementName: '', elementKey: '', dataType: 'text', description: '' })
const newRuleForm = reactive({ ruleName: '', ruleType: 'direct_entity', targetElementKey: '' })

const filteredProjects = computed(() => {
  if (!projectSearchKeyword.value) return projects.value
  const kw = projectSearchKeyword.value.toLowerCase()
  return projects.value.filter(p => p.title?.toLowerCase().includes(kw))
})

const filteredEntities = computed(() => {
  let result = entities.value || []
  if (entityTypeFilter.value) result = result.filter(e => e.entityType === entityTypeFilter.value)
  if (entitySearchKeyword.value) {
    const kw = entitySearchKeyword.value.toLowerCase()
    result = result.filter(e => e.entityText?.toLowerCase().includes(kw) || e.businessLabel?.toLowerCase().includes(kw))
  }
  return result
})

const filledValueCount = computed(() => values.value.filter(v => v.isFilled).length)

// 面板拖拽
function startResizeLeft() {
  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() {
  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') leftPanelWidth.value = Math.max(240, Math.min(500, e.clientX))
  else if (resizeType.value === 'right') rightPanelWidth.value = Math.max(280, Math.min(500, window.innerWidth - e.clientX))
}
function stopResize() {
  isResizing.value = false; resizeType.value = ''
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
  document.body.style.cursor = ''; document.body.style.userSelect = ''
}

// 项目操作
async function loadProjects() {
  loadingProjects.value = true
  try {
    const data = await projectApi.list({ page: 1, size: 50 })
    projects.value = data?.records || data || []
  } catch (error) {
    console.warn('获取项目列表失败:', error)
    projects.value = []
  } finally { loadingProjects.value = false }
}

async function switchProject(project) {
  if (currentProjectId.value === project.id) { unselectProject(); return }
  currentProjectId.value = project.id
  projectTitle.value = project.title || ''
  leftPanelTab.value = 'projects'
  await loadProjectData(project.id)
}

function unselectProject() {
  currentProjectId.value = null; projectTitle.value = ''
  elements.value = []; values.value = []; attachments.value = []; entities.value = []; rules.value = []
  docAttachmentId.value = null; docContent.value = null
  leftPanelTab.value = 'projects'
}

async function loadProjectData(projectId) {
  loading.value = true
  try {
    const [elemData, valData, attData, entData, ruleData] = await Promise.all([
      elementApi.list(projectId).catch(() => []),
      valueApi.list(projectId).catch(() => []),
      attachmentApi.list(projectId).catch(() => []),
      entityApi.listByProject(projectId).catch(() => []),
      ruleApi.list(projectId).catch(() => [])
    ])
    elements.value = elemData || []; values.value = valData || []
    attachments.value = attData || []; entities.value = entData || []; rules.value = ruleData || []
    // 自动加载第一个附件的文档内容
    if (attachments.value.length > 0) {
      docAttachmentId.value = attachments.value[0].id
      loadDocContent(attachments.value[0].id)
    } else {
      docAttachmentId.value = null
      docContent.value = null
    }
  } catch (error) { console.error('加载项目数据失败:', error) }
  finally { loading.value = false }
}

async function handleCreateProject() {
  if (!newProjectForm.title.trim()) return
  creatingProject.value = true
  try {
    const project = await projectApi.create({ title: newProjectForm.title.trim(), description: newProjectForm.description })
    showNewProjectDialog.value = false; newProjectForm.title = ''; newProjectForm.description = ''
    await loadProjects()
    if (project) await switchProject(project)
    ElMessage.success('项目创建成功')
  } catch (error) { ElMessage.error('创建失败: ' + error.message) }
  finally { creatingProject.value = false }
}

async function handleProjectCommand(cmd, project) {
  switch (cmd) {
    case 'copy':
      try { await projectApi.copy(project.id); await loadProjects(); ElMessage.success('项目复制成功') }
      catch (e) { ElMessage.error('复制失败: ' + e.message) }
      break
    case 'archive':
      try { await projectApi.archive(project.id); await loadProjects(); ElMessage.success('项目已归档') }
      catch (e) { ElMessage.error('归档失败: ' + e.message) }
      break
    case 'delete':
      try {
        await ElMessageBox.confirm(`确定要删除项目「${project.title}」吗？`, '删除确认', { confirmButtonText: '删除', cancelButtonText: '取消', type: 'warning' })
        await projectApi.delete(project.id)
        if (currentProjectId.value === project.id) unselectProject()
        await loadProjects(); ElMessage.success('项目已删除')
      } catch (e) { if (e !== 'cancel') ElMessage.error('删除失败: ' + e.message) }
      break
  }
}

async function handleCopyProject() {
  if (!currentProjectId.value) return
  try {
    const copied = await projectApi.copy(currentProjectId.value)
    await loadProjects(); ElMessage.success('项目复制成功')
    if (copied) await switchProject(copied)
  } catch (e) { ElMessage.error('复制失败: ' + e.message) }
}

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

// ==================== 文档预览 + 可编辑 + 要素高亮 ====================

async function loadDocContent(attId) {
  if (!attId) return
  docLoading.value = true
  docContent.value = null
  docHtml.value = ''
  try {
    const data = await attachmentApi.getDocContent(attId)
    docContent.value = data
    renderDocHtml()
  } catch (e) {
    console.warn('加载文档内容失败:', e)
    docContent.value = null
    docHtml.value = ''
  } finally {
    docLoading.value = false
  }
}

const docPaperStyle = computed(() => {
  const page = docContent.value?.page
  if (!page) return {}
  return {
    maxWidth: `${page.widthMm * 3.78}px`,
    paddingTop: `${page.marginTopMm * 3.78}px`,
    paddingBottom: `${page.marginBottomMm * 3.78}px`,
    paddingLeft: `${page.marginLeftMm * 3.78}px`,
    paddingRight: `${page.marginRightMm * 3.78}px`,
  }
})

// 从值的 elementKey 中提取不含项目前缀的 key
// 例如 "PRJ-2024-001:basicInfo.projectCode" -> "basicInfo.projectCode"
function stripValueKeyPrefix(valueElementKey) {
  const idx = valueElementKey?.indexOf(':')
  return idx >= 0 ? valueElementKey.substring(idx + 1) : valueElementKey
}

// 构建要素值映射表，分为长文本和短文本两类
function buildElementValueMap() {
  const longTexts = []   // paragraph/table 类型的长文本要素
  const shortTexts = []  // text 类型的短文本要素
  const colors = [
    '#fff3cd', '#cce5ff', '#d4edda', '#f8d7da', '#e2d5f1',
    '#d1ecf1', '#ffeeba', '#c3e6cb', '#f5c6cb', '#d6d8db'
  ]
  let colorIdx = 0
  for (const elem of elements.value) {
    const elemValues = values.value.filter(v => stripValueKeyPrefix(v.elementKey) === elem.elementKey)
    const elemType = elem.elementType || 'text'
    for (const val of elemValues) {
      const text = val.valueText
      if (!text || text.length < 2) continue
      const entry = {
        text,
        elementKey: elem.elementKey,
        fullElementKey: val.elementKey,
        elementName: elem.elementName,
        valueId: val.valueId,
        elemType,
        color: colors[colorIdx % colors.length]
      }
      // paragraph/table 类型或多行文本视为长文本
      if (elemType === 'paragraph' || elemType === 'table' || text.includes('\n') || text.length > 100) {
        longTexts.push(entry)
      } else {
        shortTexts.push(entry)
      }
    }
    colorIdx++
  }
  // 长文本按长度降序
  longTexts.sort((a, b) => b.text.length - a.text.length)
  // 短文本按长度降序
  shortTexts.sort((a, b) => b.text.length - a.text.length)
  return { longTexts, shortTexts }
}

// 将文档 blocks 渲染为 HTML 字符串（含要素高亮）
function renderDocHtml() {
  if (!docContent.value?.blocks) { docHtml.value = ''; return }
  const blocks = docContent.value.blocks
  const { longTexts, shortTexts } = highlightEnabled.value ? buildElementValueMap() : { longTexts: [], shortTexts: [] }
  let highlightCount = 0
  const parts = []

  // 预处理：为每个长文本要素，将其 valueText 按行拆分为句子集合
  // 用于判断某个 block 的文本是否属于某个长文本要素
  const longTextLines = longTexts.map(lt => ({
    ...lt,
    lines: new Set(lt.text.split('\n').map(l => l.trim()).filter(l => l.length > 0))
  }))

  // 收集被长文本高亮覆盖的 block IDs，这些 block 内的短文本不再单独高亮
  const longHighlightedBlockIds = new Set()

  // 第一遍：确定哪些 block 属于长文本要素
  for (const block of blocks) {
    const blockText = getBlockPlainText(block)
    if (!blockText) continue
    for (const lt of longTextLines) {
      if (lt.lines.has(blockText)) {
        longHighlightedBlockIds.add(block.id)
        break
      }
    }
  }

  // 第二遍：渲染，连续属于同一长文本要素的 block 合并到一个边框内
  let currentLongKey = null   // 当前正在收集的长文本要素 key
  let currentLongMatch = null // 当前长文本要素匹配信息
  let longGroupHtml = ''      // 当前长文本分组的 HTML 累积

  function flushLongGroup() {
    if (currentLongKey && longGroupHtml) {
      const borderColor = darkenColor(currentLongMatch.color)
      parts.push(`<div class="elem-highlight-wrap" data-elem-key="${currentLongMatch.elementKey}" data-value-id="${currentLongMatch.valueId || ''}" title="${escapeAttr(currentLongMatch.elementName)}" style="border:2px solid ${borderColor};border-radius:4px;padding:6px 8px;margin:4px 0;cursor:pointer;">${longGroupHtml}</div>`)
      highlightCount++
    }
    currentLongKey = null
    currentLongMatch = null
    longGroupHtml = ''
  }

  for (const block of blocks) {
    if (block.type === 'table') {
      flushLongGroup()
      const tableMatch = findTableLongTextMatch(block, longTextLines)
      parts.push(renderTableHtml(block, tableMatch))
      if (tableMatch) highlightCount++
    } else {
      const blockText = getBlockPlainText(block)
      const longMatch = findBlockLongTextMatch(blockText, longTextLines)

      if (longMatch) {
        // 如果和当前分组是同一个要素，继续累积
        if (currentLongKey === longMatch.elementKey) {
          longGroupHtml += renderBlockHtml(block, [], null, () => {})
        } else {
          // 不同要素，先 flush 上一组，再开始新组
          flushLongGroup()
          currentLongKey = longMatch.elementKey
          currentLongMatch = longMatch
          longGroupHtml = renderBlockHtml(block, [], null, () => {})
        }
      } else {
        // 非长文本 block，先 flush 再正常渲染
        flushLongGroup()
        parts.push(renderBlockHtml(block, shortTexts, null, (n) => { highlightCount += n }))
      }
    }
  }
  flushLongGroup() // flush 最后一组

  elementHighlightCount.value = highlightCount
  docHtml.value = parts.join('')
}

// 获取 block 的纯文本
function getBlockPlainText(block) {
  if (!block.runs) return ''
  return block.runs.map(r => r.text).join('').trim()
}

// 查找 block 文本是否匹配某个长文本要素
function findBlockLongTextMatch(blockText, longTextLines) {
  if (!blockText) return null
  for (const lt of longTextLines) {
    if (lt.lines.has(blockText)) return lt
  }
  return null
}

// 查找表格是否匹配某个长文本要素（通过表格第一行文本匹配）
function findTableLongTextMatch(block, longTextLines) {
  if (!block.table?.data?.length) return null
  const firstRowText = block.table.data[0].map(c => c.text).join(' | ')
  for (const lt of longTextLines) {
    if (lt.text.includes(firstRowText)) return lt
  }
  return null
}

function renderBlockHtml(block, shortMap, longMatch, countFn) {
  const tag = getBlockTag(block.type)
  const cls = `doc-block doc-${block.type}`
  const styleStr = buildStyleStr(block.style)
  const styleAttr = styleStr ? ` style="${styleStr}"` : ''

  let inner = ''
  // 图片
  if (block.images?.length > 0) {
    for (const img of block.images) {
      const imgStyle = []
      if (img.widthInch) imgStyle.push(`width:${img.widthInch}in`)
      if (img.heightInch) imgStyle.push(`height:${img.heightInch}in`)
      imgStyle.push('max-width:100%', 'display:block', 'margin:8px auto')
      inner += `<img src="${img.src}" style="${imgStyle.join(';')}" class="doc-inline-image" contenteditable="false" />`
    }
  }
  // Runs
  if (block.runs) {
    let runsHtml = ''
    for (const run of block.runs) {
      const text = escapeHtml(run.text)
      const rs = buildRunStyleStr(run)
      runsHtml += rs ? `<span style="${rs}">${text}</span>` : text
    }

    // 长文本高亮：不在 runs 层面处理，在外层 block 包裹
    if (longMatch) {
      countFn(1)
    } else if (shortMap.length > 0 && runsHtml.length > 0) {
      // 短文本高亮：只替换 HTML 标签外的纯文本部分，避免破坏已有标签
      let count = 0
      for (const em of shortMap) {
        const escaped = escapeHtml(em.text)
        const hl = `<span class="elem-highlight" data-elem-key="${em.elementKey}" data-value-id="${em.valueId || ''}" style="border:1.5px solid ${darkenColor(em.color)};border-radius:3px;padding:0 2px;cursor:pointer;" contenteditable="false" title="${escapeAttr(em.elementName)}">${escaped}</span>`
        const newHtml = replaceTextOutsideTags(runsHtml, escaped, hl)
        if (newHtml !== runsHtml) {
          runsHtml = newHtml
          count++
        }
      }
      if (count > 0) countFn(count)
    }
    inner += runsHtml
  }

  if (!inner) inner = '&nbsp;'
  return `<${tag} class="${cls}"${styleAttr} data-block-id="${block.id}">${inner}</${tag}>`
}

function renderTableHtml(block, longMatch) {
  const t = block.table
  if (!t?.data) return ''
  let html = `<table class="doc-table" data-block-id="${block.id}">`
  for (let ri = 0; ri < t.data.length; ri++) {
    html += '<tr>'
    for (const cell of t.data[ri]) {
      const cs = cell.colspan > 1 ? ` colspan="${cell.colspan}"` : ''
      html += `<td class="doc-table-cell"${cs}>${escapeHtml(cell.text)}</td>`
    }
    html += '</tr>'
  }
  html += '</table>'
  if (longMatch) {
    const borderColor = darkenColor(longMatch.color)
    html = `<div class="elem-highlight-wrap" data-elem-key="${longMatch.elementKey}" data-value-id="${longMatch.valueId || ''}" title="${escapeAttr(longMatch.elementName)}" style="border:2px solid ${borderColor};border-radius:4px;padding:6px;margin:4px auto;cursor:pointer;display:flex;justify-content:center;">${html}</div>`
  }
  return html
}

function getBlockTag(type) {
  if (type === 'heading1') return 'h1'
  if (type === 'heading2') return 'h2'
  if (type === 'heading3') return 'h3'
  if (type?.startsWith('toc')) return 'div'
  return 'p'
}

function buildStyleStr(style) {
  if (!style) return ''
  const parts = []
  if (style.alignment) {
    const map = { left: 'left', center: 'center', right: 'right', justify: 'justify', both: 'justify' }
    parts.push(`text-align:${map[style.alignment] || style.alignment}`)
  }
  if (style.indentLeft) parts.push(`padding-left:${style.indentLeft / 914400}in`)
  if (style.indentRight) parts.push(`padding-right:${style.indentRight / 914400}in`)
  if (style.indentFirstLine) parts.push(`text-indent:${style.indentFirstLine / 914400}in`)
  if (style.indentHanging) parts.push(`text-indent:-${style.indentHanging / 914400}in`)
  if (style.spacingBefore) parts.push(`margin-top:${style.spacingBefore / 914400}in`)
  if (style.spacingAfter) parts.push(`margin-bottom:${style.spacingAfter / 914400}in`)
  if (style.lineSpacing && style.lineSpacing >= 1 && style.lineSpacing <= 5) parts.push(`line-height:${style.lineSpacing}`)
  return parts.join(';')
}

function buildRunStyleStr(run) {
  const parts = []
  if (run.fontFamily) parts.push(`font-family:${run.fontFamily}`)
  if (run.fontSize) parts.push(`font-size:${run.fontSize}pt`)
  if (run.bold) parts.push('font-weight:bold')
  if (run.italic) parts.push('font-style:italic')
  if (run.color) parts.push(`color:${run.color.startsWith('#') ? run.color : '#' + run.color}`)
  if (run.underline) parts.push('text-decoration:underline')
  if (run.strikeThrough) parts.push('text-decoration:line-through')
  return parts.join(';')
}

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

function escapeAttr(text) {
  if (!text) return ''
  return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;')
}

// 只替换 HTML 标签外部的纯文本中的目标字符串，避免破坏已有标签和属性
function replaceTextOutsideTags(html, search, replacement) {
  // 将 HTML 拆分为：标签部分 和 文本部分
  // 正则匹配所有 HTML 标签（包括自闭合标签）
  const parts = html.split(/(<[^>]+>)/g)
  let replaced = false
  for (let i = 0; i < parts.length; i++) {
    // 奇数索引是标签，偶数索引是文本
    if (i % 2 === 0 && parts[i].includes(search)) {
      parts[i] = parts[i].split(search).join(replacement)
      replaced = true
    }
  }
  return replaced ? parts.join('') : html
}

function darkenColor(hex) {
  // 简单加深颜色用于下边框
  const map = {
    '#fff3cd': '#e0a800', '#cce5ff': '#3d8bfd', '#d4edda': '#28a745',
    '#f8d7da': '#dc3545', '#e2d5f1': '#6f42c1', '#d1ecf1': '#17a2b8',
    '#ffeeba': '#d39e00', '#c3e6cb': '#1e7e34', '#f5c6cb': '#c82333',
    '#d6d8db': '#6c757d'
  }
  return map[hex] || '#999'
}

// 文档编辑事件
function onDocInput() {
  saved.value = false
}

// 点击文档中的高亮要素
function onDocClick(e) {
  const target = e.target.closest('.elem-highlight') || e.target.closest('.elem-highlight-wrap') || e.target.closest('.elem-highlight-table')
  if (!target) {
    highlightPopover.visible = false
    return
  }

  const elemKey = target.dataset.elemKey
  const valueId = target.dataset.valueId
  const elem = elements.value.find(el => el.elementKey === elemKey)
  const val = values.value.find(v => String(v.valueId) === String(valueId)) ||
              values.value.find(v => stripValueKeyPrefix(v.elementKey) === elemKey)

  if (!elem) return

  const rect = target.getBoundingClientRect()
  const scrollEl = editorRef.value
  const scrollRect = scrollEl?.getBoundingClientRect() || { top: 0, left: 0 }

  highlightPopover.elementKey = elemKey
  highlightPopover.fullElementKey = val?.elementKey || ''
  highlightPopover.elementName = elem.elementName
  highlightPopover.currentValue = val?.valueText || ''
  highlightPopover.originalValue = ''
  highlightPopover.valueId = val?.valueId || null
  highlightPopover.x = rect.left - scrollRect.left + scrollEl.scrollLeft
  highlightPopover.y = rect.bottom - scrollRect.top + scrollEl.scrollTop + 4
  highlightPopover.visible = true
}

async function savePopoverValue() {
  if (!highlightPopover.elementKey || !currentProjectId.value) {
    ElMessage.warning('无法保存：未找到对应的值记录')
    return
  }
  try {
    // API: PUT /projects/{projectId}/values/{elementKey} with { valueText }
    const apiKey = highlightPopover.fullElementKey || highlightPopover.elementKey
    const result = await valueApi.update(currentProjectId.value, apiKey, { valueText: highlightPopover.currentValue })
    // 更新本地数据
    const val = values.value.find(v => stripValueKeyPrefix(v.elementKey) === highlightPopover.elementKey)
    if (val) {
      val.valueText = highlightPopover.currentValue
      val.isFilled = !!highlightPopover.currentValue
    }
    highlightPopover.visible = false
    renderDocHtml()
    ElMessage.success('要素值已更新')
  } catch (e) {
    ElMessage.error('保存失败: ' + e.message)
  }
}

// 要素/值
function getElementValues(elementKey) { return values.value.filter(v => stripValueKeyPrefix(v.elementKey) === elementKey) }
function hasFilledValue(elementKey) { return values.value.some(v => stripValueKeyPrefix(v.elementKey) === elementKey && v.isFilled) }
function onValueChange(val) { saved.value = false; val.isModified = true }

async function handleAddElement() {
  if (!newElementForm.elementName || !newElementForm.elementKey) return
  try {
    const elem = await elementApi.add(currentProjectId.value, { ...newElementForm })
    elements.value.push(elem); showAddElementDialog.value = false
    Object.assign(newElementForm, { elementName: '', elementKey: '', dataType: 'text', description: '' })
    ElMessage.success('要素添加成功')
  } catch (e) { ElMessage.error('添加失败: ' + e.message) }
}

// 附件
async function handleAttachmentUpload(file) {
  if (!currentProjectId.value) return
  try {
    const att = await attachmentApi.upload(currentProjectId.value, file.raw, file.name)
    attachments.value.push(att); ElMessage.success('附件上传成功')
  } catch (e) { ElMessage.error('上传失败: ' + e.message) }
}
function selectAttachment(att) { selectedAttachment.value = att }
async function removeAttachment(att) {
  try {
    await ElMessageBox.confirm(`确定删除附件「${att.displayName}」？`, '删除确认', { type: 'warning' })
    await attachmentApi.delete(att.id)
    attachments.value = attachments.value.filter(a => a.id !== att.id); ElMessage.success('附件已删除')
  } catch (e) { if (e !== 'cancel') ElMessage.error('删除失败') }
}
function getFileIcon(att) {
  const name = att.displayName || ''
  if (name.endsWith('.pdf')) return '📕'
  if (name.endsWith('.doc') || name.endsWith('.docx')) return '📘'
  if (name.endsWith('.xls') || name.endsWith('.xlsx')) return '📗'
  return '📄'
}

// 规则
async function handleCreateRule() {
  if (!newRuleForm.ruleName) return
  try {
    const rule = await ruleApi.create(currentProjectId.value, { ...newRuleForm })
    rules.value.push(rule); showNewRuleDialog.value = false
    Object.assign(newRuleForm, { ruleName: '', ruleType: 'direct_entity', targetElementKey: '' })
    ElMessage.success('规则创建成功')
  } catch (e) { ElMessage.error('创建失败: ' + e.message) }
}
async function handleDeleteRule(rule) {
  try {
    await ElMessageBox.confirm(`确定删除规则「${rule.ruleName}」？`, '删除确认', { type: 'warning' })
    await ruleApi.delete(rule.id); rules.value = rules.value.filter(r => r.id !== rule.id); ElMessage.success('规则已删除')
  } catch (e) { if (e !== 'cancel') ElMessage.error('删除失败') }
}
async function handleExecuteRule(rule) {
  try { await ruleApi.execute(rule.id); ElMessage.success(`规则「${rule.ruleName}」执行成功`); await loadProjectData(currentProjectId.value) }
  catch (e) { ElMessage.error('执行失败: ' + e.message) }
}
async function handleBatchExecuteRules() {
  if (!currentProjectId.value) return
  executingRules.value = true
  try { await ruleApi.batchExecute(currentProjectId.value); ElMessage.success('批量执行完成'); await loadProjectData(currentProjectId.value) }
  catch (e) { ElMessage.error('执行失败: ' + e.message) }
  finally { executingRules.value = false }
}

// 实体工具
function getEntityTypeName(type) {
  const map = { 'ORG': '组织机构', 'PERSON': '人物', 'DATE': '日期', 'CODE': '编号', 'NUMBER': '数值', 'LOCATION': '地点', 'MONEY': '金额', 'PERCENT': '百分比' }
  return map[type] || type || '其他'
}
function getEntityTypeIcon(type) {
  const map = { 'ORG': '🏢', 'PERSON': '👤', 'DATE': '📅', 'CODE': '🔢', 'NUMBER': '📊', 'LOCATION': '📍', 'MONEY': '💰', 'PERCENT': '📊' }
  return map[type] || '🏷️'
}
function getEntityTypeClass(type) {
  const map = { 'ORG': 'entity-org', 'PERSON': 'entity-person', 'DATE': 'entity-date', 'CODE': 'entity-data', 'NUMBER': 'entity-data', 'LOCATION': 'entity-location' }
  return map[type] || 'entity-default'
}

// 工具函数
function formatTime(dateStr) {
  if (!dateStr) return ''
  const date = new Date(dateStr); const now = new Date()
  const diffDays = Math.floor((now - date) / (1000 * 60 * 60 * 24))
  if (diffDays === 0) return '今天'
  if (diffDays === 1) return '昨天'
  if (diffDays < 7) return `${diffDays}天前`
  return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' })
}
function getStatusText(status) {
  const map = { 'draft': '草稿', 'active': '进行中', 'archived': '已归档', 'completed': '已完成' }
  return map[status] || '草稿'
}

onMounted(async () => {
  await loadProjects()
  const pid = route.query.project
  if (pid) {
    const p = projects.value.find(p => String(p.id) === String(pid))
    if (p) await switchProject(p)
  }
})
</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);
    }
  }
  
  
  .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;
      position: relative;
      
      &: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-delete-btn {
        opacity: 0;
        flex-shrink: 0;
        transition: opacity 0.2s;
        border: none;
        background: transparent;
        color: var(--text-3);
        
        &:hover {
          color: var(--danger);
          background: rgba(255, 77, 79, 0.1);
        }
      }
      
      &:hover .report-delete-btn {
        opacity: 1;
      }
    }
  }
  
  .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; }
      }
      
      // 未确认的 AI 建议（文档中虚线样式）
      &.ai-suggestion-pending {
        border-style: dashed;
        opacity: 0.9;
      }
      
      // 点击 AI 建议后，文档中该要素的「待确认」高亮
      &.entity-pending-confirm {
        box-shadow: 0 0 0 2px #1890ff;
        opacity: 1;
      }
    }
  }
}

// ==========================================
// 右侧面板 - 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;
      }
    }
    
    .header-actions {
      display: flex;
      gap: 4px;
      
      .el-button {
        padding: 4px 8px;
        font-size: 12px;
      }
    }
  }
  
  // AI 建议区块特殊样式
  &.ai-section {
    background: var(--bg);
    border-bottom: none;
    
    .element-header {
      .element-title {
        color: var(--text-2);
      }
    }
    
    .element-option.ai-highlight-option {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px 16px;
      font-size: 12px;
      color: var(--text-2);
      .option-label {
        flex: 1;
      }
    }
    
    .element-tags-wrap {
      max-height: 300px;
    }
  }
    
  // 要素 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;
    display: flex;
    flex-direction: column;
    gap: 16px;
  }

  // 要素标签容器 - 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);
      }
    }
  }
  
  // ==========================================
  // 要素标签样式 - 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;
    }
    
    .tag-action {
      color: var(--primary);
      font-size: 14px;
      font-weight: bold;
      margin-left: 2px;
    }
    
    // 已确认的要素
    &.confirmed {
      background: var(--white);
      border-color: var(--primary);
      
      .tag-name {
        color: var(--text-1);
      }
    }
    
    // AI 建议的要素（虚线边框、淡色）
    &.ai-suggestion {
      background: transparent;
      border-style: dashed;
      border-color: var(--border);
      opacity: 0.85;
      
      .tag-name {
        color: var(--text-2);
      }
      
      &:hover {
        opacity: 1;
        border-color: var(--primary);
        border-style: solid;
        background: var(--primary-light);
        
        .tag-action {
          transform: scale(1.2);
        }
      }
    }
    
    // 动态要素样式（圆角）
    &.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;
    }
    
    // 当前正在确认的 AI 建议 tag
    &.is-pending {
      border-color: var(--primary);
      background: var(--primary-light);
      border-style: solid;
    }
  }
  
  // AI 建议确认栏已移至「+」按钮的悬浮框内，此处样式仅作保留注释

  .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);
    position: relative;

    &: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;
      flex-shrink: 0;
    }
    
    .shortcut {
      margin-left: auto;
      font-size: 11px;
      color: var(--text-3);
    }
    
    .submenu-arrow {
      margin-left: auto;
      font-size: 14px;
      color: var(--text-3);
    }
    
    &.has-submenu {
      &:hover .submenu-arrow {
        color: var(--primary);
      }
    }
  }
  
  // 子菜单
  .context-submenu {
    position: absolute;
    left: 100%;
    top: 0;
    min-width: 150px;
    background: var(--white);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    
    .context-menu-item {
      padding: 8px 12px;
      font-size: 12px;
      gap: 8px;
      
      .icon {
        font-size: 12px;
        width: 16px;
      }
    }
  }
  
  .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;
  }
}

// ==========================================
// 报告要素管理弹窗样式
// ==========================================
.elements-modal {
  :deep(.el-dialog__header) {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    margin-right: 0;
  }
  
  :deep(.el-dialog__body) {
    padding: 0;
  }
  
  :deep(.el-dialog__footer) {
    padding: 12px 20px;
    border-top: 1px solid var(--border);
  }
}

.elements-modal-content {
  .elements-search {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--bg);
    
    .el-input {
      max-width: 300px;
    }
  }
  
  .elements-table-wrap {
    padding: 0;
    
    :deep(.el-table) {
      .element-name {
        font-weight: 500;
        color: var(--text-1);
      }
      
      .element-desc {
        color: var(--text-3);
        font-size: 12px;
      }
      
      .original-value {
        color: var(--text-2);
        font-size: 12px;
      }
      
      .element-source {
        color: var(--primary);
        font-size: 12px;
      }
      
      .el-input__wrapper {
        box-shadow: none;
        background: var(--bg);
        border-radius: var(--radius-sm);
        
        &:hover, &.is-focus {
          background: var(--white);
          box-shadow: 0 0 0 1px var(--primary);
        }
      }
    }
  }
  
  .elements-pagination {
    display: flex;
    justify-content: flex-end;
    padding: 12px 20px;
    border-top: 1px solid var(--border);
  }
}

// ==========================================
// 新建报告对话框样式
// ==========================================
.new-report-dialog {
  :deep(.el-dialog__header) {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    margin-right: 0;
  }
  
  :deep(.el-dialog__body) {
    padding: 20px;
  }
  
  :deep(.el-dialog__footer) {
    padding: 12px 20px;
    border-top: 1px solid var(--border);
  }
}

.new-report-form {
  .section-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-2);
    margin-bottom: 10px;
  }
  
  .create-type-section {
    margin-bottom: 20px;
  }
  
  .create-type-options {
    display: flex;
    gap: 12px;
  }
  
  .type-option {
    flex: 1;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px;
    background: var(--bg);
    border: 2px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all 0.2s;
    position: relative;
    
    &:hover {
      border-color: var(--primary-light);
      background: var(--white);
    }
    
    &.active {
      border-color: var(--primary);
      background: var(--primary-light);
      
      .option-title {
        color: var(--primary);
      }
    }
    
    .option-icon {
      font-size: 24px;
      flex-shrink: 0;
      line-height: 1;
    }
    
    .option-content {
      flex: 1;
      min-width: 0;
    }
    
    .option-title {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-1);
      margin-bottom: 4px;
    }
    
    .option-desc {
      font-size: 12px;
      color: var(--text-3);
      line-height: 1.4;
    }
    
    .option-check {
      position: absolute;
      top: 8px;
      right: 8px;
      width: 20px;
      height: 20px;
      background: var(--primary);
      color: white;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 12px;
      font-weight: bold;
    }
  }
  
  .name-input-section {
    margin-bottom: 20px;
    
    :deep(.el-input__wrapper) {
      border-radius: var(--radius-sm);
    }
  }
  
  .upload-section {
    .report-upload-area {
      :deep(.el-upload) {
        width: 100%;
      }
      
      :deep(.el-upload-dragger) {
        width: 100%;
        height: auto;
        padding: 24px;
        border-radius: var(--radius-md);
        border: 2px dashed var(--border);
        background: var(--bg);
        
        &:hover {
          border-color: var(--primary);
          background: var(--primary-light);
        }
      }
      
      .upload-content {
        text-align: center;
      }
      
      .upload-icon {
        font-size: 32px;
        color: var(--text-3);
        margin-bottom: 8px;
      }
      
      .upload-text {
        font-size: 14px;
        color: var(--text-2);
        margin-bottom: 4px;
        
        em {
          color: var(--primary);
          font-style: normal;
        }
      }
      
      .upload-hint {
        font-size: 12px;
        color: var(--text-3);
      }
    }
  }
}

// ==========================================
// 要素视图
// ==========================================
.elements-view {
  padding: 24px;
  
  .elements-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    gap: 16px;
  }
  
  .element-card {
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    transition: all 0.2s;
    
    &:hover {
      border-color: var(--primary);
      box-shadow: var(--shadow-sm);
    }
    
    .element-card-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 12px 16px;
      background: var(--bg);
      border-bottom: 1px solid var(--border);
      
      .element-label {
        font-weight: 600;
        font-size: 14px;
        color: var(--text-1);
      }
    }
    
    .element-card-body {
      padding: 12px 16px;
      
      .element-value-row {
        margin-bottom: 8px;
        
        .value-meta {
          margin-top: 4px;
          font-size: 11px;
          color: var(--text-3);
          
          .original-label {
            margin-right: 4px;
          }
          .original-value {
            color: var(--text-2);
          }
        }
        
        .value-status {
          margin-top: 4px;
        }
      }
      
      .element-empty {
        padding: 16px 0;
        text-align: center;
        
        .empty-hint {
          font-size: 12px;
          color: var(--text-3);
        }
      }
    }
  }
  
  .elements-empty {
    padding: 60px 20px;
    text-align: center;
  }
}

// ==========================================
// 实体视图
// ==========================================
.entities-view {
  padding: 24px;
  
  .entity-filter-bar {
    display: flex;
    align-items: center;
    margin-bottom: 16px;
  }
  
  .entities-empty {
    padding: 60px 20px;
    text-align: center;
  }
}

// ==========================================
// 项目概览统计
// ==========================================
.overview-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  
  .stat-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 8px;
    background: var(--bg);
    border-radius: var(--radius-sm);
    
    .stat-label {
      font-size: 11px;
      color: var(--text-3);
      margin-bottom: 4px;
    }
    
    .stat-value {
      font-size: 20px;
      font-weight: 700;
      color: var(--text-1);
      
      &.filled {
        color: var(--success);
      }
    }
  }
}

// ==========================================
// 文档视图 - Word 排版还原 + 可编辑 + 要素高亮
// ==========================================
.document-view {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  background: #e8e8e8;
  min-height: 100%;
  position: relative;

  .doc-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
    padding: 8px 16px;
    background: var(--white);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    width: 100%;
    max-width: 820px;

    .doc-toolbar-left, .doc-toolbar-right {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .doc-att-label {
      font-size: 13px;
      font-weight: 600;
      color: var(--text-2);
      white-space: nowrap;
    }
  }

  .doc-paper {
    background: #fff;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
    border-radius: 2px;
    width: 100%;
    max-width: 820px;
    min-height: 1100px;
    padding: 96px 90px;
    font-family: 'Times New Roman', 'SimSun', '宋体', serif;
    font-size: 12pt;
    line-height: 1.6;
    color: #000;
    word-wrap: break-word;
    overflow-wrap: break-word;
  }

  .doc-block {
    margin: 0;
    padding: 0;
    min-height: 1em;
  }

  // 标题样式
  h1.doc-block {
    font-size: 18pt;
    font-weight: bold;
    margin: 16px 0 10px;
    line-height: 1.4;
  }

  h2.doc-block {
    font-size: 16pt;
    font-weight: bold;
    margin: 14px 0 8px;
    line-height: 1.4;
  }

  h3.doc-block {
    font-size: 14pt;
    font-weight: bold;
    margin: 12px 0 6px;
    line-height: 1.4;
  }

  // 段落
  p.doc-block {
    margin: 0 0 2px;
    text-align: justify;
  }

  // 目录
  .doc-toc1, .doc-toc2, .doc-toc3 {
    font-size: 14pt;
    margin: 2px 0;
    cursor: default;
  }
  .doc-toc2 {
    padding-left: 24px;
    font-size: 12pt;
  }
  .doc-toc3 {
    padding-left: 48px;
    font-size: 11pt;
  }

  // 空段落
  p.doc-paragraph:empty::after,
  p.doc-block:empty::after {
    content: '\00a0';
  }

  // 内联图片
  .doc-inline-image {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 8px auto;
  }

  // 表格
  .doc-table {
    width: 100%;
    border-collapse: collapse;
    margin: 12px 0;
    font-size: 11pt;

    .doc-table-cell {
      border: 1px solid #000;
      padding: 6px 8px;
      vertical-align: top;
      line-height: 1.4;
    }

    tr:first-child .doc-table-cell {
      font-weight: bold;
      background: #f0f0f0;
    }
  }

  // 空状态 & 加载
  .doc-empty, .doc-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 80px 20px;
    width: 100%;
    max-width: 820px;
    background: var(--white);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
  }

  .doc-loading {
    flex-direction: row;
    gap: 12px;
    padding: 40px;
    font-size: 14px;
    color: var(--text-2);
  }
}

// ==========================================
// 要素高亮弹出框
// ==========================================
.element-popover {
  position: absolute;
  z-index: 1000;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.15);
  width: 320px;
  overflow: hidden;

  .popover-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);

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

  .popover-body {
    padding: 12px 14px;

    .popover-field {
      margin-bottom: 10px;

      &:last-child {
        margin-bottom: 0;
      }

      .popover-field-label {
        display: block;
        font-size: 12px;
        color: var(--text-3);
        margin-bottom: 4px;
      }

      .popover-original {
        font-size: 13px;
        color: var(--text-2);
        background: var(--bg);
        padding: 4px 8px;
        border-radius: var(--radius-sm);
        display: inline-block;
      }
    }
  }

  .popover-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 14px;
    border-top: 1px solid var(--border);
    background: var(--bg);
  }
}

// 可编辑文档纸张的光标和选区样式
.doc-paper[contenteditable="true"] {
  outline: none;
  cursor: text;

  &:focus {
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15), 0 0 0 2px rgba(24, 144, 255, 0.2);
  }
}

// 高亮边框样式
.elem-highlight {
  transition: border-color 0.2s, box-shadow 0.2s;

  &:hover {
    box-shadow: 0 0 0 1px rgba(24, 144, 255, 0.4);
    border-color: #1890ff !important;
  }
}

.elem-highlight-long {
  display: inline !important;
  transition: border-color 0.2s, box-shadow 0.2s;

  &:hover {
    box-shadow: 0 0 0 1px rgba(24, 144, 255, 0.4);
    border-color: #1890ff !important;
  }
}

.elem-highlight-wrap {
  position: relative;
  transition: border-color 0.2s, box-shadow 0.2s;

  &:hover {
    border-color: #1890ff !important;
    box-shadow: 0 0 0 1px rgba(24, 144, 255, 0.4);
  }

  .doc-table {
    margin: 0 auto;
  }
}
</style>

