<!--
 * @Author: wrh
 * @Date: 2025-01-01 00:00:00
 * @LastEditors: wrh
 * @LastEditTime: 2026-04-28 11:12:00
-->
<template>
  <div class="agent-detail-container" v-loading="loading">
    <div v-if="agentInfo" class="detail-content">

      <div class="agent-header">
        <div class="header-left">
          <el-button class="collapse-icon-btn" :icon="showLeftPanel ? 'el-icon-s-fold' : 'el-icon-s-unfold'"
            @click="toggleLeftPanel" />
          <h3>{{ agentInfo.agentName }}</h3>
        </div>
        <!-- 模式切换 -->
        <div class="mode-switcher">
          <el-radio-group v-model="currentMode" @change="handleModeChange">
            <el-radio-button label="conversation">对话模式</el-radio-button>
            <el-radio-button label="task">任务模式</el-radio-button>
          </el-radio-group>
        </div>
      </div>
      <!-- 对话模式 -->
      <div v-if="currentMode === 'conversation'" class="chat-section">
        <!-- 话题列表 -->
        <div v-if="topicList.length > 0 && showTopicList" class="topic-list">
          <div class="topic-header">
            <h4>历史对话</h4>
          </div>
          <div class="topic-content">
            <div v-for="topic in topicList" :key="topic.topicId" class="topic-item"
              :class="{ 'active': currentTopicId === topic.topicId }">
              <div class="topic-info" @click="selectTopic(topic)">
                <div class="topic-name">{{ topic.topic }}</div>
                <div class="topic-time">{{ topic.createTime }}</div>
              </div>
              <div class="topic-actions">
                <el-button type="danger" size="small" icon="el-icon-delete" circle
                  @click.stop="handleDeleteTopic(topic)" class="delete-btn" title="删除对话" />
              </div>
            </div>
          </div>
        </div>

        <!-- 对话内容区域 -->
        <div class="chat-content">
          <div class="section-header">
            <el-button v-if="topicList.length > 0" class="collapse-icon-btn" icon="el-icon-s-fold"
              @click="showTopicList = !showTopicList" />
            <h3>{{ chatTitle }}</h3>
            <div class="header-actions">
              <el-button v-if="currentTopicId" size="small" type="primary" @click="startNewChat" icon="el-icon-plus">
                新建对话
              </el-button>
              <el-button v-if="!currentTopicId && chatMessages.length > 0" size="small" @click="clearChat">
                清空对话
              </el-button>
            </div>
          </div>

          <!-- 聊天消息列表 -->
          <div class="chat-messages" ref="messagesContainer">
            <!-- 开场白 -->
            <div v-if="openingMessage && !currentTopicId" class="message-item assistant-message">
              <div class="message-avatar">
                <svg-icon icon-class="robot" />
              </div>
              <div class="message-content">
                <div class="message-text">{{ openingMessage }}</div>
              </div>
            </div>

            <!-- 文件上传提示消息 -->
            <div v-if="openingMessage && !currentTopicId" class="message-item assistant-message">
              <div class="message-avatar">
                <svg-icon icon-class="robot" />
              </div>
              <div class="message-content">
                <div class="message-upload-area">
                  <p class="upload-tip"> {{ selectDocumentTip }}</p>
                  <el-upload class="inline-upload" :action="uploadAction" :multiple="false" :auto-upload="false"
                    :file-list="chatFileList" :on-change="handleChatFileChange" :before-upload="beforeUpload"
                    :show-file-list="true" :limit="1">
                    <el-button type="primary" size="small" icon="el-icon-upload">
                      {{ selectDocument }}
                    </el-button>
                  </el-upload>
                  <div v-if="chatFileList.length > 0" class="chat-upload-actions">
                    <el-button size="small" type="success" @click="submitChatUpload" icon="el-icon-check">
                      确认上传
                    </el-button>
                  </div>
                  <div v-if="percentageDisplay">
                    <p class="upload-tip"> </p>
                    <p class="upload-tip">{{ step }}</p>
                    <el-progress :percentage="percentage" :stroke-width="25" :text-inside="true">
                      <el-button text>{{ progress }}</el-button>
                    </el-progress>
                  </div>
                </div>
              </div>
            </div>

            <!-- 对话消息 -->
            <div v-for="(message, index) in chatMessages" :key="index" class="message-item" :class="[
              message.role === 'user' ? 'user-message' : 'assistant-message',
              message.isFileInfo ? 'file-info-message' : ''
            ]">
              <div class="message-avatar">
                <i v-if="message.role === 'user'" class="el-icon-user"></i>
                <svg-icon v-else icon-class="robot" />
              </div>
              <div class="message-content">
                <div v-if="message.isHtml" class="message-text" v-html="message.content"></div>
                <div v-else class="message-text">{{ message.content }}</div>
                <div class="message-actions">
                  <span class="message-time">{{ message.timestamp }}</span>
                  <el-button v-if="message.canRetry" type="text" size="small" @click="retryMessage(message)"
                    class="retry-btn" icon="el-icon-refresh">
                    重新发送
                  </el-button>
                </div>
              </div>
            </div>

            <!-- 文件上传提示消息 -->
            <div v-if="techUploadDisplay" class="message-item assistant-message">
              <div class="message-avatar">
                <svg-icon icon-class="robot" />
              </div>
              <div class="message-content">
                <div class="message-upload-area">
                  <p class="upload-tip">请上传大纲修改后的技术文件：</p>
                  <el-upload class="inline-upload" :action="uploadAction" :multiple="false" :auto-upload="false"
                    :file-list="chatFileList" :on-change="handleChatFileChange" :before-upload="beforeUpload"
                    :show-file-list="true" :limit="1">
                    <el-button type="primary" size="small" icon="el-icon-upload">
                      选择技术文件
                    </el-button>
                  </el-upload>
                  <div v-if="chatFileList.length > 0" class="chat-upload-actions">
                    <el-button size="small" type="success" @click="submitFileUpload" icon="el-icon-check">
                      确认上传
                    </el-button>
                  </div>
                  <div v-if="percentageDisplay">
                    <p class="upload-tip"> </p>
                    <p class="upload-tip">{{ step }}</p>
                    <el-progress :percentage="percentage" :stroke-width="25" :text-inside="true">
                      <el-button text>{{ progress }}</el-button>
                    </el-progress>
                  </div>
                </div>
              </div>
            </div>

            <!-- 正在输入指示器 -->
            <div v-if="isTyping" class="message-item assistant-message">
              <div class="message-avatar">
                <svg-icon icon-class="robot" />
              </div>
              <div class="message-content">
                <div class="typing-indicator">
                  <span></span>
                  <span></span>
                  <span></span>
                </div>
              </div>
            </div>
          </div>

          <!-- 输入区域 -->
          <div class="chat-input-area">
            <el-input v-model="inputMessage" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
              placeholder="请输入您的问题..." @keyup.enter.native="handleEnterKeydown" />
            <div class="input-actions">
              <span class="input-tip">Enter 发送，Shift + Enter 换行</span>
              <el-button type="primary" @click="sendMessage()" :disabled="!inputMessage.trim() || isTyping">
                发送
              </el-button>
            </div>
          </div>
        </div>
      </div>

      <!-- 任务模式 -->
      <div v-else-if="currentMode === 'task'" class="task-section">
        <!-- 历史任务列表 -->
        <div v-if="topicList.length > 0 && showTopicList" class="topic-list">
          <div class="topic-header">
            <h4>历史任务</h4>
          </div>
          <div class="topic-content">
            <div v-for="topic in topicList" :key="topic.topicId" class="topic-item"
              :class="{ 'active': currentTopicId === topic.topicId }">
              <div class="topic-info" @click="selectTask(topic)">
                <div class="topic-name">{{ topic.topic }}</div>
                <div class="topic-time">{{ topic.createTime }}</div>
              </div>
              <div class="topic-actions">
                <el-button type="danger" size="small" icon="el-icon-delete" circle
                  @click.stop="handleDeleteTopic(topic)" class="delete-btn" title="删除任务" />
              </div>
            </div>
          </div>
        </div>

        <!-- 主内容区域 -->
        <div class="task-main-content">
          <div class="section-header">
            <el-button v-if="topicList.length > 0" class="collapse-icon-btn" icon="el-icon-s-fold"
              @click="showTopicList = !showTopicList" />
            <h3>{{ taskTitle }}</h3>
            <div class="header-actions">
            </div>
          </div>
          <el-tabs v-model="activeTaskTab">
            <!-- 文档上传 -->
            <el-tab-pane label="文档上传" name="upload">
              <div class="task-content">
                <div class="upload-section">
                  <el-upload class="upload-area" :action="uploadAction" :multiple="false" :auto-upload="false"
                    :file-list="taskFileList" :on-change="handleTaskFileChange" :before-upload="beforeUpload"
                    :show-file-list="true" :limit="1">
                    <el-button type="primary" size="large" icon="el-icon-upload">
                      {{ selectDocument }}
                    </el-button>
                    <div class="upload-tip">支持 DOC、DOCX 格式</div>
                  </el-upload>
                  <div v-if="taskFileList.length > 0" class="task-upload-actions">
                    <el-button size="medium" type="success" @click="submitTaskUpload" icon="el-icon-check">
                      确认上传
                    </el-button>
                  </div>
                  <div v-if="taskPercentageDisplay" class="upload-progress">
                    <p class="upload-tip"></p>
                    <p class="upload-tip">{{ taskStep }}</p>
                    <el-progress :percentage="taskPercentage" :stroke-width="25" :text-inside="true">
                      <el-button text>{{ taskProgress }}</el-button>
                    </el-progress>
                  </div>

                  <!-- 显示已上传的招标文件地址 -->
                  <div v-if="uploadedDocumentPath" class="document-path-section">
                    <h4>已上传文件</h4>
                    <div class="document-path">
                      <i class="el-icon-document"></i>
                      <span>{{ uploadedDocumentPath }}</span>
                    </div>
                  </div>
                </div>
              </div>
            </el-tab-pane>

            <!-- 文档分析 -->
            <el-tab-pane label="文档分析" name="analysis">
              <div class="task-content">
                <el-tabs v-model="activeAnalysisTab">
                  <el-tab-pane label="项目概况" name="overview">
                    <div class="analysis-content">
                      <div v-if="analysisResults.overview" class="analysis-result">
                        <div v-html="analysisResults.overview"></div>
                      </div>
                      <div v-else class="empty-state">
                        <i class="el-icon-document"></i>
                        <p>请先上传文件进行分析</p>
                      </div>
                    </div>
                  </el-tab-pane>
                  <el-tab-pane v-if="!agentInfo.agentName.includes('设计')" :label="scoringTabLabel" name="scoring">
                    <div class="analysis-content">
                      <div v-if="analysisResults.scoring" class="analysis-result">
                        <div v-html="analysisResults.scoring"></div>
                      </div>
                      <div v-else class="empty-state">
                        <i class="el-icon-document"></i>
                        <p>请先上传文件进行分析</p>
                      </div>
                    </div>
                  </el-tab-pane>
                </el-tabs>
              </div>
            </el-tab-pane>

            <!-- 标书内容 -->
            <el-tab-pane :label="bidTabLabel" name="bid">
              <div class="task-content">
                <div class="bid-content">
                  <el-form :model="bidForm" label-width="70px">
                    <el-form-item :label="bidTitleLabel">
                      <div class="bid-title-row">
                        <div v-if="currentFilename" class="bid-title-display">
                          <i clabidTabLabels="el-icon-file-word"></i>
                          <span>{{ currentFilename }}</span>
                        </div>
                        <el-upload v-else class="upload-area" :action="uploadAction" :multiple="false"
                          :auto-upload="false" :file-list="bidFileList" :on-change="handleBidFileChange"
                          :before-upload="beforeUpload" :show-file-list="true" :limit="1"
                          :disabled="bidFileList.length > 0">
                        </el-upload>
                        <el-button type="primary" @click="isStreaming ? stopGeneration() : generateBid()"
                          :disabled="!currentFilename && !isStreaming">
                          {{ isStreaming ? '停止生成' : generateButtonText }}
                        </el-button>
                        <el-button type="primary" icon="el-icon-download" @click="exportWord"
                          :disabled="isStreaming">
                          导出Word文档
                        </el-button>
                      </div>
                    </el-form-item>
                  </el-form>
                  <div v-if="directoryTree.length > 0" class="chapter-section">
                    <div class="chapter-content-wrapper">
                      <div class="directory-tree">
                        <div class="tree-container">
                          <div v-for="(item, index) in directoryTree" :key="index" class="directory-item level-1"
                            :class="{ 'selected': selectedNode === item }">
                            <div class="directory-node">
                              <el-input v-model="item.title" placeholder="请输入目录名称" size="small"
                                @click.native.stop="selectNode(item)" />
                              <div class="node-actions">
                                <el-button type="primary" size="mini" icon="el-icon-plus" circle
                                  @click.stop="addChildNode(item)" title="添加子节点" />
                                <el-button type="danger" size="mini" icon="el-icon-delete" circle
                                  @click.stop="deleteNode(item)" title="删除节点" />
                              </div>
                            </div>
                            <div v-if="item.children && item.children.length > 0">
                              <div v-for="(child, childIndex) in item.children" :key="childIndex"
                                class="directory-item level-2" :class="{ 'selected': selectedNode === child }">
                                <div class="directory-node">
                                  <el-input v-model="child.title" placeholder="请输入子目录名称" size="small"
                                    @click.native.stop="selectNode(child)" />
                                  <div class="node-actions">
                                    <el-button type="primary" size="mini" icon="el-icon-plus" circle
                                      @click.stop="addChildNode(child)" title="添加子节点" />
                                    <el-button type="danger" size="mini" icon="el-icon-delete" circle
                                      @click.stop="deleteNode(child)" title="删除节点" />
                                  </div>
                                </div>
                                <div v-if="child.children && child.children.length > 0">
                                  <div v-for="(grandchild, grandchildIndex) in child.children" :key="grandchildIndex"
                                    class="directory-item level-3" :class="{ 'selected': selectedNode === grandchild }">
                                    <div class="directory-node">
                                      <el-input v-model="grandchild.title" placeholder="请输入子目录名称" size="small"
                                        @click.native.stop="selectNode(grandchild)" />
                                      <div class="node-actions">
                                        <el-button type="primary" size="mini" icon="el-icon-plus" circle
                                          @click.stop="addChildNode(grandchild)" title="添加子节点" />
                                        <el-button type="danger" size="mini" icon="el-icon-delete" circle
                                          @click.stop="deleteNode(grandchild)" title="删除节点" />
                                      </div>
                                    </div>
                                  </div>
                                </div>
                              </div>
                            </div>
                          </div>
                        </div>
                      </div>
                      <div class="bid-content-area">
                        <!-- 生成进度提示（仅在生成章节内容时显示） -->
                        <div v-if="isStreaming" class="generation-progress"
                          style="padding: 8px 12px; background: #ecf5ff; border-radius: 4px; margin-bottom: 12px;">
                          <i class="el-icon-loading" style="margin-right: 8px;"></i>
                          <span>正在生成中... {{ currentChapterIndex }}/{{ totalChapters }} 章</span>
                        </div>
                        <!-- 章节内容（生成中显示，生成完成后不再显示） -->
                        <div v-if="isStreaming && bidResult" class="bid-result-content">
                          <div v-html="bidResult"></div>
                        </div>
                        <!-- 已选中章节的预览内容（非生成状态且不是完成状态） -->
                        <div v-if="!isStreaming && !generationCompleted && bidResult" class="bid-result-content">
                          <div v-html="bidResult"></div>
                        </div>
                        <!-- 生成完成提示（居中显示，不与章节内容同时出现） -->
                        <div v-if="generationCompleted" class="empty-bid-content generation-completed"
                          style="color: #67c23a;">
                          <i class="el-icon-success" style="font-size: 64px; margin-bottom: 20px; opacity: 0.8;"></i>
                          <p style="font-size: 18px; font-weight: 500;">生成完成</p>
                        </div>
                        <!-- 初始空状态（未选中章节且未开始生成） -->
                        <div v-if="!isStreaming && !generationCompleted && !bidResult" class="empty-bid-content">
                          <i class="el-icon-file-text"></i>
                          <p>{{ selectedNode ? '已选中章节: ' + selectedNode.title : '请选择章节或直接生成全部内容' }}</p>
                        </div>
                      </div>
                    </div>
                    <div class="directory-toolbar">
                      <el-button type="success" size="small" @click="saveDirectory" icon="el-icon-check"
                        title="保存目录">保存目录</el-button>
                      <div class="token-info-container">
                        <div class="token-info-row">
                          <span class="token-label">提示词:</span>
                          <span class="token-value">{{ tokenUsage.promptTokens }}</span>
                        </div>
                        <div class="token-info-row">
                          <span class="token-label">生成:</span>
                          <span class="token-value">{{ tokenUsage.completionTokens }}</span>
                        </div>
                        <div class="token-info-row">
                          <span class="token-label">总计:</span>
                          <span class="token-value">{{ tokenUsage.totalTokens }}</span>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
      </div>
    </div>

    <!-- 空状态 -->
    <div v-else class="empty-main-content">
      <div class="agent-header">
        <h3>智能体详情</h3>
        <div class="header-actions">
        </div>
      </div>
      <div class="empty-state">
        <i class="el-icon-search" style="font-size: 48px;"></i>
        <p>请选择一个智能体查看详细信息</p>
      </div>
    </div>
  </div>
</template>

<script>
import { Message } from 'element-ui';
import { getAgent, opening, uploadFile, uploadModifyFile, getProcessValue, writeTitles, streamGenerateChapters } from '@/api/llm/agent';
import { answer } from '@/api/llm/mcp';
import { listTopic, getTopic, delTopic, addTopic, updateTopic } from "@/api/llm/topic";
import { listChat, addChat, updateChat } from "@/api/llm/chat";
import { listDocument } from "@/api/llm/document";
import { marked } from 'marked';
import { parseTime } from "@/utils/ruoyi";

export default {
  name: 'AgentDetail',
  props: {
    agentId: {
      type: [String, Number],
      default: null
    },
    showLeftPanel: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      // 响应式数据
      loading: false,
      agentInfo: null,
      openingMessage: '',
      scoringTabLabel: '评分标准',
      chatMessages: [],
      inputMessage: '',
      isTyping: false,
      messagesContainer: null,
      topicList: [],
      currentTopicId: null,
      showTopicList: true,
      chatTitle: '智能体新对话',
      taskTitle: '智能体新任务',
      percentage: 0,
      progress: "",
      step: "",
      percentageDisplay: false,
      techUploadDisplay: false,
      selectDocument: '',
      selectDocumentTip: '',
      chatFileList: [], // 聊天内的文件列表

      // 任务模式相关数据
      currentMode: 'task', // conversation 或 task
      activeTaskTab: 'upload', // upload, analysis, bid
      activeAnalysisTab: 'overview', // scoring, overview, directory
      taskFileList: [], // 任务模式文件列表
      taskPercentage: 0,
      taskProgress: "",
      taskStep: "",
      taskPercentageDisplay: false,
      analysisResults: {
        scoring: '',
        overview: '',
        directory: ''
      },
      // 目录管理相关数据
      directoryTree: [],
      isDirectoryEditing: false,
      currentFilename: '',
      selectedNode: null,
      bidForm: {},
      bidFileList: [], // 标书文件列表
      bidResult: '',
      bidFilePath: '', // 生成的标书文件路径
      uploadedDocumentPath: '', // 上传的招标文件路径
      selectedChapter: null,
      selectedChapterContent: '',
      chapterLoading: false,

      // 流式生成相关
      chapterContents: {}, // 存储每个章节的内容
      currentStreamingChapter: null, // 当前正在流式生成的章节标题
      streamingContent: '', // 当前流式生成的内容
      isStreaming: false, // 是否正在流式生成
      generationCompleted: false, // 标书生成是否已完成
      abortController: null, // 用于取消流式请求
      currentChapterIndex: 0, // 当前章节索引
      totalChapters: 0, // 总章节数

      // token用量相关
      tokenUsage: {
        promptTokens: 0,
        completionTokens: 0,
        totalTokens: 0
      },
      chapterTokenUsage: {} // 存储每个章节的token用量
    }
  },
  computed: {
    uploadAction() {
      return '/llm/agent/upload'
    },
    bidTabLabel() {
      return this.agentInfo?.agentName.includes('设计') ? '设计书内容' : '标书内容'
    },
    bidTitleLabel() {
      return this.agentInfo?.agentName.includes('设计') ? '设计书标题' : '标书标题'
    },
    generateButtonText() {
      return this.agentInfo?.agentName.includes('设计') ? '生成设计书' : '生成标书'
    }
  },
  watch: {
    agentId: {
      immediate: true,
      handler(newAgentId) {
        if (newAgentId) {
          this.loadAgentDetail(newAgentId)
        } else {
          this.agentInfo = null
          this.openingMessage = ''
          this.chatMessages = []
          this.chatFileList = []
          this.currentTopicId = null
          this.chatTitle = '智能体新对话'
        }
      }
    }
  },
  methods: {
    // 切换左侧智能体列表面板
    toggleLeftPanel() {
      this.$emit('toggle-left-panel')
    },

    // 加载智能体详细信息
    async loadAgentDetail(agentId) {
      this.loading = true
      try {
        // 获取智能体详细信息
        const response = await getAgent(agentId)
        this.agentInfo = response.data

        // 设置评分标准/应价人须知标签
        if (this.agentInfo?.agentName) {
          if (this.agentInfo.agentName.includes('技术标书') && this.agentInfo.agentName.includes('询价')) {
            this.scoringTabLabel = '应价人须知'
          } else {
            this.scoringTabLabel = '评分标准'
          }
        }

        // 获取开场白
        if (this.agentInfo?.agentName) {
          const res = await opening(this.agentInfo.agentName)
          this.openingMessage = res.data.resultContent;
          if (this.agentInfo.agentName.includes('技术标书')) {
            this.selectDocument = '选择招标文件'
            this.selectDocumentTip = '请上传您需要分析的招标文件（单个文件）：'
          }
          else if (this.agentInfo.agentName.includes('技术设计书')) {
            this.selectDocument = '选择项目任务书'
            this.selectDocumentTip = '请上传您需要分析的项目任务书（单个文件）：'
          }
          else if (this.agentInfo.agentName.includes('商务')) {
          }
          else if (this.agentInfo.agentName.includes('文档检查')) {
            this.selectDocument = '选择检查文件'
            this.selectDocumentTip = '请上传您需要检查的文件（单个文件）：'
          }
        }
        // 查询当前智能体的话题列表
        await this.loadTopic()
        // 自动滚动到底部
        this.$nextTick(() => {
          this.scrollToBottom()
        })
      } catch (error) {
        console.error('加载智能体详细信息失败:', error)
        this.$message.error('加载智能体信息失败')
      } finally {
        this.loading = false
      }
    },
    // 加载选择智能体的话题列表
    async loadTopic() {
      const res = await listTopic({ agentId: this.agentId })
      if (res.rows.length > 0) {
        this.topicList = res.rows
      }
      else {
        this.topicList = res.rows
        this.techUploadDisplay = false
      }
    },

    // 加载指定话题的聊天记录（公共函数）
    async loadChatMessages(topicId) {
      try {
        const res = await listChat({ topicId: topicId });
        if (res.rows.length > 0) {
          // 处理聊天消息格式
          const messages = []
          for (const chat of res.rows) {
            // 加载该聊天记录相关的文件，优先显示
            if (chat.chatId) {
              try {
                const fileResponse = await listDocument({ chatId: chat.chatId });
                if (fileResponse.rows && fileResponse.rows.length > 0) {
                  const fileNames = fileResponse.rows.map(doc => doc.path.split("/")[doc.path.split("/").length - 1]).join(', ');
                  // 先添加文件信息消息
                  messages.push({
                    role: 'assistant',
                    content: `📎 相关文件: ${fileNames}`,
                    isHtml: false,
                    isFileInfo: true // 标记为文件信息消息
                  })
                }
              } catch (error) {
                console.warn('加载文件信息失败:', error)
              }
            }
            // 添加用户输入消息（如果存在）
            if (chat.input) {
              messages.push({
                role: 'user',
                content: chat.input,
                timestamp: chat.inputTime || new Date(chat.createTime).toLocaleTimeString(),
                isHtml: false,
                originalContent: chat.input, // 为历史消息添加原始内容
                canRetry: false // 历史消息默认不显示重试按钮
              })
            }
            // 添加助手回复消息
            if (chat.output) {
              messages.push({
                role: 'assistant',
                content: chat.output,
                timestamp: chat.outputTime || new Date(chat.createTime).toLocaleTimeString(),
                isHtml: true // 历史消息可能包含HTML内容
              })
            }
          }
          // 更新聊天消息
          this.chatMessages = messages
          return messages.length > 0
        } else {
          this.chatMessages = []
          return false
        }
      } catch (error) {
        console.error('加载话题对话记录失败:', error)
        this.chatMessages = []
        throw error
      }
    },

    // 选择话题（对话模式）
    async selectTopic(topic) {
      this.currentTopicId = topic.topicId
      this.chatTitle = topic.topic

      try {
        const hasMessages = await this.loadChatMessages(topic.topicId)

        // 滚动到底部
        this.$nextTick(() => {
          this.scrollToBottom()
        })

        if (hasMessages) {
          this.$message.success(`已加载话题"${topic.topic}"的对话记录`)
          this.techUploadDisplay = true;
        } else {
          this.$message.info('该话题暂无对话记录')
        }

        // 加载任务模式所需的数据
        await this.loadTaskDataForTopic(topic.topicId)
      } catch (error) {
        this.$message.error('加载对话记录失败')
      }
    },

    // 选择任务（任务模式）
    async selectTask(topic) {
      this.currentTopicId = topic.topicId
      this.taskTitle = topic.topic

      try {
        // 加载任务数据
        await this.loadTaskDataForTopic(topic.topicId)
        this.$message.success(`已加载任务"${topic.topic}"`)

        // 切换到分析标签页显示数据
        this.activeTaskTab = 'analysis'
      } catch (error) {
        this.$message.error('加载任务数据失败')
      }
    },

    // 加载话题对应的任务模式数据
    async loadTaskDataForTopic(topicId) {
      try {
        // 重置选中的节点，避免显示之前选中的章节
        this.selectedNode = null

        // 获取该话题的聊天记录
        const chatRes = await listChat({ topicId: topicId })
        if (chatRes.rows && chatRes.rows.length > 0) {
          const chat = chatRes.rows[0]

          // 解析output中的分析结果
          if (chat.output) {
            this.parseAnalysisResults(chat.output)
          }

          // 获取招标文件地址和已生成的投标文件
          if (chat.chatId) {
            const docRes = await listDocument({ chatId: chat.chatId })
            if (docRes.rows && docRes.rows.length > 0) {
              // 查找投标文件（包含agentName的文件）
              const bidFile = docRes.rows.find(doc => doc.path.includes(this.agentInfo.agentName))
              if (bidFile) {
                let filenameSplit = bidFile.path.split("/")[bidFile.path.split("/").length - 1]
                let filenameSplit2 = filenameSplit.split(".")
                this.currentFilename = filenameSplit.replace(filenameSplit2[filenameSplit2.length - 2], filenameSplit2[filenameSplit2.length - 2] + "_" + this.agentInfo.agentName)
                const bidFileUrl = process.env.VUE_APP_BASE_API + '/profile/upload/agent/' + this.agentInfo.agentName + '/' + this.currentFilename
                this.bidFilePath = bidFileUrl
                this.bidFileList = [{
                  name: this.currentFilename,
                  url: bidFileUrl,
                  raw: null
                }]
              } else {
                // 如果没有找到投标文件，设置招标文件路径
                this.uploadedDocumentPath = docRes.rows[0].path.split("/")[docRes.rows[0].path.split("/").length - 1]
              }
            }
          }
        }
      } catch (error) {
        console.error('加载任务模式数据失败:', error)
      }
    },

    // 解析分析结果
    parseAnalysisResults(output) {
      if (!output) return

      // 使用正则匹配【项目概况】【评分标准】【应价人须知】【详细目录】
      // 匹配项目概况（结束标记可以是评分标准或应价人须知）
      const overviewMatch = output.match(/【项目概况】\n([\s\S]*?)(?=\n\n【评分标准】|\n\n【应价人须知】)/)
      // 匹配评分标准或应价人须知
      const scoringMatch = output.match(/【评分标准】\n([\s\S]*?)(?=\n\n【详细目录】)/)
      const biddingMatch = output.match(/【应价人须知】\n([\s\S]*?)(?=\n\n【详细目录】)/)
      const directoryMatch = output.match(/【详细目录】\n([\s\S]*)/)

      this.analysisResults = {
        overview: overviewMatch ? marked(overviewMatch[1]) : '',
        scoring: scoringMatch ? marked(scoringMatch[1]) : (biddingMatch ? marked(biddingMatch[1]) : ''),
        directory: directoryMatch ? marked(directoryMatch[1]) : ''
      }

      // 尝试解析目录树
      if (directoryMatch) {
        this.directoryTree = this.parseDirectoryTree(directoryMatch[1])
      }
    },

    // 解析目录文本为树结构
    parseDirectoryTree(directoryText) {
      const lines = directoryText.split('\n').filter(line => line.trim())
      const tree = []
      const level1Map = {}
      const level2Map = {}

      for (const line of lines) {
        const trimmedLine = line.trim()
        const match = trimmedLine.match(/^(\d+\.\d+(?:\.\d+)?)\s+(.+)/)
        if (!match) continue

        const number = match[1]
        const title = match[2]
        const parts = number.split('.')

        if (parts.length === 2) {
          // 二级标题（如 6.1）
          const node = { title: trimmedLine, children: [] }
          tree.push(node)
          level1Map[number] = node
        } else if (parts.length === 3) {
          // 三级标题（如 6.1.1）
          const parentNumber = parts.slice(0, 2).join('.')
          const node = { title: trimmedLine, children: [] }
          if (level1Map[parentNumber]) {
            level1Map[parentNumber].children.push(node)
            level2Map[number] = node
          }
        }
      }

      return tree.length > 0 ? [{ title: '6 技术文件', children: tree }] : []
    },

    // 删除话题
    async handleDeleteTopic(topic) {
      try {
        await this.$confirm(
          `确定要删除话题"${topic.topic}"吗？删除后无法恢复。`,
          '删除确认',
          {
            confirmButtonText: '确定删除',
            cancelButtonText: '取消',
            type: 'warning',
            confirmButtonClass: 'el-button--danger'
          }
        )

        // 调用删除API
        await delTopic(topic.topicId)

        // 如果删除的是当前选中的话题，则重置对话状态
        if (this.currentTopicId === topic.topicId) {
          this.currentTopicId = null
          this.chatMessages = []
          this.chatTitle = '智能体新对话'

          // 任务模式下清空相关数据
          if (this.currentMode === 'task') {
            // 清空文档分析内容
            this.analysisResults = {
              overview: '',
              scoring: '',
              directory: ''
            }
            // 清空标书内容相关数据
            this.directoryTree = []
            this.currentFilename = ''
            this.bidResult = ''
            this.bidFilePath = ''
            this.uploadedDocumentPath = ''
            this.bidFileList = []
          }
        }

        // 重新加载话题列表
        await this.loadTopic()

        this.techUploadDisplay = false;
        this.$message.success('话题删除成功')
      } catch (error) {
        if (error !== 'cancel') {
          console.error('删除话题失败:', error)
          this.$message.error('删除话题失败')
        }
      }
    },

    // 处理 Enter 键事件
    handleEnterKeydown(event) {
      // 如果按住 Shift 键，允许换行
      if (event.shiftKey) {
        return
      }
      // 阻止默认的换行行为
      event.preventDefault()
      // 发送消息
      this.sendMessage()
    },

    // 发送消息（支持重试）
    async sendMessage(retryContent = null) {
      // 确保 retryContent 是字符串类型，如果是事件对象则忽略
      const validRetryContent = (typeof retryContent === 'string') ? retryContent : null
      const message = validRetryContent || this.inputMessage.trim()
      if (!message || this.isTyping) return

      // 添加用户消息
      const userMessage = {
        role: 'user',
        content: message,
        timestamp: new Date().toLocaleTimeString(),
        isHtml: false, // 用户消息不使用HTML渲染
        originalContent: message, // 保存原始内容用于重试
        canRetry: false // 初始时不显示重试按钮
      }
      this.chatMessages.push(userMessage)

      // 只有在非重试模式下才清空输入框
      if (!retryContent) {
        this.inputMessage = ''
      }

      this.isTyping = true

      this.$nextTick(() => {
        this.scrollToBottom()
      })

      try {
        // 调用智能体回答API
        const response = await answer({
          topicId: this.currentTopicId,
          question: message
        })
        let content = JSON.parse(response.resultContent).content;

        // 检查是否是默认的失败回复
        const defaultFailureMessage = '抱歉，我暂时无法回答这个问题。';
        const finalContent = this.formatContentLinks(content) || defaultFailureMessage;

        // 添加助手回复
        const assistantMessage = {
          role: 'assistant',
          content: finalContent,
          timestamp: new Date().toLocaleTimeString(),
          isHtml: true // 普通聊天消息使用HTML渲染
        }
        this.chatMessages.push(assistantMessage)

        // 如果是默认失败回复，为用户消息添加重试按钮
        if (finalContent === defaultFailureMessage) {
          userMessage.canRetry = true
        }
      } catch (error) {
        console.error('发送消息失败:', error)
        this.$message.error('发送消息失败')

        // 添加错误消息
        const errorMessage = {
          role: 'assistant',
          content: '抱歉，发生了一些错误，请稍后再试。',
          timestamp: new Date().toLocaleTimeString(),
          isHtml: false
        }
        this.chatMessages.push(errorMessage)

        // 为用户消息添加重试按钮
        userMessage.canRetry = true
      } finally {
        this.isTyping = false
        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }
    },

    // 重新发送消息
    async retryMessage(message) {
      // 找到当前消息在数组中的索引
      const messageIndex = this.chatMessages.findIndex(msg => msg === message)
      if (messageIndex === -1) return

      // 获取原始消息内容
      const originalContent = message.originalContent || message.content
      if (!originalContent || typeof originalContent !== 'string') {
        this.$message.error('无法获取原始消息内容')
        return
      }

      // 移除从当前用户消息开始的所有消息（包括后续的助手回复）
      const messagesToKeep = this.chatMessages.slice(0, messageIndex)
      this.chatMessages = messagesToKeep

      // 重新发送原始消息
      await this.sendMessage(originalContent)
    },

    // 滚动到底部
    scrollToBottom() {
      // 确保在 DOM 更新后执行滚动操作
      this.$nextTick(() => {
        // 直接从 $refs 中获取滚动容器，确保每次都能获取到最新的 DOM 元素
        const container = this.$refs.messagesContainer;
        if (container) {
          container.scrollTop = container.scrollHeight;
        }
      });
    },

    // 聊天内文件上传相关方法
    handleChatFileChange(file, fileList) {
      // 只保留最新选择的文件（限制为单文件）
      this.chatFileList = fileList.slice(-1)
    },

    beforeUpload(file) {
      const isValidType = ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(file.type)
      if (!isValidType) {
        this.$message.error('只支持 DOC、DOCX 格式的文件！')
        return false
      }
      return false // 阻止自动上传
    },
    // 聊天内文件上传提交
    async submitChatUpload() {
      if (this.chatFileList.length === 0) {
        this.$message.warning('请先选择文件')
        return
      }
      try {
        this.percentageDisplay = true;
        var timer;
        clearInterval(timer);
        const getProcess = () => {
          timer = setInterval(() => { //隔2000毫秒获取进度
            getProcessValue().then(res => {
              if (res.code == 200 & res.msg.includes(":")) {
                this.progress = res.msg;
                this.step = res.msg.split(":")[0]
                this.percentage = Number(res.msg.split(":")[1].replace("%", ""))
              }
            });
          }, 2000)
        }
        getProcess();
        const file = this.chatFileList[0].raw // 只取第一个文件
        const fileName = file.name;
        try {
          const response = await uploadFile(file, this.agentInfo.agentName)

          // 解析返回的数据
          if (response.data && response.data.assistantMessage) {
            this.percentageDisplay = false;
            // 格式化链接：在href前加上基础API地址
            let assistantContent = this.formatContentLinks(response.data.assistantMessage)
            clearInterval(timer);
            // 添加上传成功的消息到聊天记录
            const uploadMessage = {
              role: 'assistant',
              content: assistantContent,
              timestamp: new Date().toLocaleTimeString(),
              isHtml: true // 标记这是HTML内容
            }
            this.chatMessages.push(uploadMessage);
            if (this.agentInfo.agentName.includes('技术标书'))
              this.techUploadDisplay = true;
            // this.$message.success('文件上传成功');
            const topicId = response.data.topicId;
            // 刷新话题列表
            await this.loadTopic();

            // 激活当前话题并加载聊天记录
            this.currentTopicId = topicId;
            this.chatTitle = fileName;

            // 重新加载该话题的聊天记录以显示文件相关内容
            try {
              await this.loadChatMessages(topicId)
            } catch (error) {
              console.error('加载话题聊天记录失败:', error)
            }

            // 清空文件上传列表
            this.chatFileList = [];

            this.$nextTick(() => {
              this.scrollToBottom()
            })
          }
        }
        catch (error) {
          clearInterval(timer);
          console.error('文件上传失败:', error)
        }

      } catch (error) {
        console.error('文件上传失败:', error)
        this.$message.error('文件上传失败')

        // 添加上传失败的消息到聊天记录
        const errorMessage = {
          role: 'assistant',
          content: '文件上传失败，请检查文件格式或网络连接后重试。',
          timestamp: new Date().toLocaleTimeString(),
          isHtml: false
        }
        this.chatMessages.push(errorMessage)

        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }
    },

    // 聊天内文件上传提交
    async submitFileUpload() {
      if (this.chatFileList.length === 0) {
        this.$message.warning('请先选择文件')
        return
      }
      try {
        this.percentageDisplay = true;
        var timer;
        clearInterval(timer);
        const getProcess = () => {
          timer = setInterval(() => { //隔2000毫秒获取进度
            getProcessValue().then(res => {
              if (res.code == 200 & res.msg.includes(":")) {
                this.progress = res.msg;
                this.step = res.msg.split(":")[0]
                this.percentage = Number(res.msg.split(":")[1].replace("%", ""))
              }
            });
          }, 2000)
        }
        getProcess();
        const file = this.chatFileList[0].raw // 只取第一个文件
        const fileName = file.name;
        try {
          const response = await uploadModifyFile(this.currentTopicId, file, this.agentInfo.agentName)
          const chatId = response.data.chatId; //获取保存后的chatId
          // 解析返回的数据
          if (response.data && response.data.assistantMessage) {
            this.percentageDisplay = false;
            // 格式化链接：在href前加上基础API地址
            let assistantContent = this.formatContentLinks(response.data.assistantMessage)
            clearInterval(timer);
            // 添加上传成功的消息到聊天记录
            const uploadMessage = {
              role: 'assistant',
              content: assistantContent,
              timestamp: new Date().toLocaleTimeString(),
              isHtml: true // 标记这是HTML内容
            }
            this.chatMessages.push(uploadMessage);
            this.techUploadDisplay = false;
            await updateChat({ userId: this.$store.state.user.id, chatId, topicId: this.currentTopicId, output: assistantContent, outputTime: parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}') });

            // 清空文件上传列表
            this.chatFileList = [];

            this.$nextTick(() => {
              this.scrollToBottom()
            })
          }
        }
        catch (error) {
          clearInterval(timer);
          console.error('文件上传失败:', error)
        }

      } catch (error) {
        console.error('文件上传失败:', error)
        this.$message.error('文件上传失败')

        // 添加上传失败的消息到聊天记录
        const errorMessage = {
          role: 'assistant',
          content: '文件上传失败，请检查文件格式或网络连接后重试。',
          timestamp: new Date().toLocaleTimeString(),
          isHtml: false
        }
        this.chatMessages.push(errorMessage)

        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }
    },
    // 开始新对话
    startNewChat() {
      this.currentTopicId = null
      this.chatMessages = []
      this.chatFileList = []
      this.chatTitle = '智能体新对话'
      // 重置选中的节点
      this.selectedNode = null

      // 滚动到顶部显示开场白
      this.$nextTick(() => {
        if (this.messagesContainer) {
          this.messagesContainer.scrollTop = 0
        }
      })
      this.techUploadDisplay = false
      this.$message.success('已切换到新对话模式')
    },

    // 清空对话
    clearChat() {
      this.chatMessages = []
      this.chatFileList = []
      this.chatTitle = '智能体新对话'

      // 滚动到顶部显示开场白
      this.$nextTick(() => {
        if (this.messagesContainer) {
          this.messagesContainer.scrollTop = 0
        }
      })

      this.$message.success('对话已清空')
    },

    // 格式化内容中的链接
    formatContentLinks(content) {
      if (!content) return content

      // 使用正则表达式匹配 <a href='/profile/...'>...</a> 格式的链接
      const linkRegex = /<a\s+href=['"]([^'"]*?)['"][^>]*?>(.*?)<\/a>/gi

      let formattedContent = content.replace(linkRegex, (match, href, text) => {
        // 如果href不是以http开头的，说明是相对路径，需要添加基础API地址
        if (!href.startsWith('http')) {
          const baseApi = process.env.VUE_APP_BASE_API || ''
          const fullUrl = baseApi + href
          return `<a href="${fullUrl}" target="_blank" style="color: #1890ff; text-decoration: underline;">${text}</a>`
        }
        return match
      })

      // 将普通换行符转换为HTML换行符
      formattedContent = formattedContent.replace(/\n/g, '<br>')

      return formattedContent
    },

    // 下载文件并返回Blob对象
    async downloadFileAsBlob(url, filename) {
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error('下载文件失败')
      }
      const blob = await response.blob()
      // 创建File对象
      return new File([blob], filename, { type: blob.type })
    },

    // 模式切换处理
    handleModeChange(mode) {
      this.currentMode = mode
      if (mode === 'task') {
        // 切换到任务模式时的初始化
        this.activeTaskTab = 'upload'
        this.taskFileList = []
        this.taskPercentageDisplay = false
        this.bidFileList = []
        // 重置选中的节点
        this.selectedNode = null
      }
    },

    // 任务模式文件上传相关方法
    handleTaskFileChange(file, fileList) {
      // 只保留最新选择的文件（限制为单文件）
      this.taskFileList = fileList.slice(-1)
    },

    // 标书文件上传相关方法（不可修改）
    handleBidFileChange(file, fileList) {
      // 标书文件列表不可修改，保持原有值
      // 如果当前没有文件，则允许设置
      if (this.bidFileList.length === 0 && fileList.length > 0) {
        this.bidFileList = fileList.slice(-1)
      } else {
        // 如果已有文件，不允许修改
        this.$message.warning('标书文件已设置，不可修改')
      }
    },

    // 任务模式文件上传提交
    async submitTaskUpload() {
      if (this.taskFileList.length === 0) {
        this.$message.warning('请先选择文件')
        return
      }
      try {
        this.taskPercentageDisplay = true
        var timer
        clearInterval(timer)
        const getProcess = () => {
          timer = setInterval(() => { //隔2000毫秒获取进度
            getProcessValue().then(res => {
              if (res.code == 200 & res.msg.includes(":")) {
                this.taskProgress = res.msg
                this.taskStep = res.msg.split(":")[0]
                this.taskPercentage = Number(res.msg.split(":")[1].replace("%", ""))
              }
            })
          }, 2000)
        }
        getProcess()
        const file = this.taskFileList[0].raw // 只取第一个文件
        const fileName = file.name
        try {
          const response = await uploadFile(file, this.agentInfo.agentName)

          // 解析返回的数据
          if (response.data) {
            this.taskPercentageDisplay = false
            clearInterval(timer)

            const topicId = response.data.topicId;
            this.currentTopicId = topicId;

            // 刷新话题列表
            await this.loadTopic();

            // 激活当前话题并加载聊天记录
            this.chatTitle = fileName;

            // 重新加载该话题的聊天记录以显示文件相关内容
            try {
              await this.loadChatMessages(topicId)
            } catch (error) {
              console.error('加载话题聊天记录失败:', error)
            }

            // 保存文件名（从上传文件的响应中获取）
            // 从API返回的response.data中获取完整的文件路径
            if (response.data.filename) {
              this.currentFilename = response.data.filename
              // 生成标书文件名（原始文件名 + _agentName + .docx）
              const bidFileUrl = process.env.VUE_APP_BASE_API + '/profile/upload/agent/' + this.agentInfo.agentName + '/' + this.currentFilename

              // 设置标书文件列表的默认值
              // url: 指向生成的标书文件地址（投标文件）
              // raw: 暂时为空，稍后下载后填充
              this.bidFileList = [{
                name: response.data.filename,
                url: bidFileUrl,
                raw: null  // 将在generateBid时下载填充
              }]
            }

            // 使用API返回的真实分析结果
            if (response.data.scoringRequirements && response.data.projectOverview && response.data.detailedDirectory) {
              // 兼容旧的数据结构
              this.analysisResults = {
                scoring: marked(response.data.scoringRequirements),
                overview: marked(response.data.projectOverview),
                directory: marked(response.data.directoryText || response.data.detailedDirectory)
              }
            }

            this.$message.success('文件上传成功并已分析')

            // 使用后端返回的真实目录树结构
            if (response.data.detailedDirectory) {
              this.directoryTree = response.data.detailedDirectory
            }

            // 切换到分析标签
            this.activeTaskTab = 'analysis'
          }
        }
        catch (error) {
          clearInterval(timer)
          console.error('文件上传失败:', error)
        }

      } catch (error) {
        console.error('文件上传失败:', error)
        this.$message.error('文件上传失败')
      }
    },
    /**
       * 生成标书（流式版本）
       */
    async generateBid() {
      if (this.bidFileList.length === 0) {
        this.$message.warning('请先上传文件')
        return
      }

      try {
        const bidTitle = this.bidFileList[0].name
        const bidFileUrl = this.bidFileList[0].url

        let file = this.bidFileList[0].raw
        if (!file) {
          try {
            file = await this.downloadFileAsBlob(bidFileUrl, bidTitle)
            this.bidFileList[0].raw = file
          } catch (error) {
            this.$message.error('下载文件失败')
            return
          }
        }

        const selectedNodeTitle = this.selectedNode?.title || null

        // 重置流式生成状态
        this.isStreaming = true
        this.generationCompleted = false
        this.streamingContent = ''
        this.currentStreamingChapter = null
        this.chapterContents = {}
        this.bidResult = ''

        // 重置token用量
        this.tokenUsage = {
          promptTokens: 0,
          completionTokens: 0,
          totalTokens: 0
        }
        this.chapterTokenUsage = {}

        // 创建FormData
        const formData = new FormData()
        formData.append('topicId', this.currentTopicId)
        formData.append('agentName', this.agentInfo.agentName)
        formData.append('file', file)
        if (selectedNodeTitle) {
          formData.append('selectedNode', selectedNodeTitle)
        }

        // 使用流式响应
        this.fetchStreamGeneration(formData, bidTitle)

      } catch (error) {
        console.error('生成失败:', error)
        this.$message.error('生成失败')
        this.isStreaming = false
      }
    },

    /**
     * 使用API进行流式请求
     */
    fetchStreamGeneration(formData, bidTitle) {
      const onMessage = (data, eventType) => {
        this.handleStreamMessage(data, eventType)
      }

      const onError = (error) => {
        console.error('流式请求失败:', error)
        this.$message.error('生成失败: ' + error.message)
        this.isStreaming = false
        this.abortController = null
        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }

      const onComplete = () => {
        this.isStreaming = false
        this.abortController = null
        // 完成消息由轮询方法在文档写入完成后显示
      }

      // 使用封装的API，并保存controller用于取消
      this.abortController = streamGenerateChapters(formData, onMessage, onError, onComplete)
    },

    /**
     * 停止生成标书
     */
    stopGeneration() {
      if (this.abortController) {
        this.abortController.abort()
        this.abortController = null
        this.isStreaming = false
        this.generationCompleted = false
        this.$message.warning('已停止生成')
      }
    },

    /**
     * 处理流式消息 - 支持逐字输出
     */
    handleStreamMessage(data, eventType) {
      // 处理完成事件
      if (data.completed) {
        this.isStreaming = false
        this.generationCompleted = true
        this.currentStreamingChapter = null
        this.bidResult = ''

        // 设置标书文件路径，使导出功能立即可用
        if (this.currentFilename) {
          this.bidFilePath = process.env.VUE_APP_BASE_API + '/profile/upload/agent/' + this.agentInfo.agentName + '/' + this.currentFilename
        }

        this.$message.success('生成完成')
        return
      }

      // 处理错误事件
      if (data.error) {
        this.$message.error('生成章节出错: ' + data.error)
        return
      }

      const title = data.title
      const content = data.content
      const isLast = data.isLast
      const chapterIndex = data.chapterIndex
      const totalChapters = data.totalChapters

      // 获取token用量信息
      const promptTokens = data.promptTokens || 0
      const completionTokens = data.completionTokens || 0
      const totalTokens = data.totalTokens || 0

      // 保存总章节数
      if (totalChapters) {
        this.totalChapters = totalChapters
      }

      // 如果是新章节，重置状态
      if (title !== this.currentStreamingChapter) {
        this.currentStreamingChapter = title
        this.currentChapterIndex = chapterIndex || 1
        this.streamingContent = ''

        // 在文本域中显示当前章节标题
        this.bidResult = `<h3 style="color: #409EFF; margin: 10px 0;">【${title}】</h3>`

        // 自动滚动到顶部查看新章节
        this.$nextTick(() => {
          const contentArea = document.querySelector('.bid-content-area')
          if (contentArea) {
            contentArea.scrollTop = 0
          }
        })
      }

      // 追加内容到文本域（逐字输出）
      if (content) {
        this.streamingContent += content

        // 使用 marked 进行 Markdown 格式化
        const formattedContent = marked(this.streamingContent)
        this.bidResult = `<h3 style="color: #409EFF; margin: 10px 0;">【${this.currentStreamingChapter}】</h3>
                        <div style="line-height: 1.8;">${formattedContent}</div>`

        // 自动滚动到最新内容
        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }

      // 保存章节内容到存储中（用于最终的Word导出）
      if (!this.chapterContents[title]) {
        this.chapterContents[title] = ''
      }
      this.chapterContents[title] += content || ''

      // 实时更新并显示token用量（每个章节发送的是当前章节的累计值）
      if (promptTokens > 0 || completionTokens > 0 || totalTokens > 0) {
        // 保存当前章节的token用量（如果值更大则更新，避免重复累加）
        const currentChapterTokens = this.chapterTokenUsage[title] || { promptTokens: 0, completionTokens: 0, totalTokens: 0 }

        // 只在有新值时更新
        if (promptTokens > currentChapterTokens.promptTokens ||
          completionTokens > currentChapterTokens.completionTokens ||
          totalTokens > currentChapterTokens.totalTokens) {

          this.chapterTokenUsage[title] = {
            promptTokens,
            completionTokens,
            totalTokens
          }

          // 重新计算总token用量
          this.recalculateTotalTokenUsage()
        }
      }
    },

    /**
     * 重新计算总token用量
     */
    recalculateTotalTokenUsage() {
      let totalPrompt = 0
      let totalCompletion = 0
      let totalAll = 0

      // 遍历所有章节的token用量
      for (const chapterTokens of Object.values(this.chapterTokenUsage)) {
        totalPrompt += chapterTokens.promptTokens || 0
        totalCompletion += chapterTokens.completionTokens || 0
        totalAll += chapterTokens.totalTokens || 0
      }

      // 更新总token用量
      this.tokenUsage.promptTokens = totalPrompt
      this.tokenUsage.completionTokens = totalCompletion
      this.tokenUsage.totalTokens = totalAll
    },

    /**
     * 滚动到底部（用于bid-content-area区域）
     */
    scrollToBottom() {
      this.$nextTick(() => {
        const contentArea = document.querySelector('.bid-content-area')
        if (contentArea) {
          contentArea.scrollTop = contentArea.scrollHeight
        }
      })
    },

    // 在目录树中选中指定标题的节点
    selectDirectoryNode(title) {
      const findNode = (nodes) => {
        for (const node of nodes) {
          if (node.title === title) {
            this.selectedNode = node
            return true
          }
          if (node.children && node.children.length > 0) {
            if (findNode(node.children)) {
              return true
            }
          }
        }
        return false
      }
      findNode(this.directoryTree)
    },

    // 导出Word
    exportWord() {
      if (!this.bidFilePath) {
        this.$message.warning('暂无文件可导出')
        return
      }
      // 构建完整的下载URL
      const downloadUrl = this.bidFilePath
      // 创建隐藏的a标签触发下载
      const link = document.createElement('a')
      link.href = downloadUrl
      link.download = this.bidFilePath.substring(this.bidFilePath.lastIndexOf('/') + 1)
      link.target = '_blank'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      this.$message.success('Word文档导出成功')
    },

    // 点击章节节点
    async handleChapterClick(node) {
      this.selectedChapter = node
      this.chapterLoading = true
      this.selectedChapterContent = ''

      try {
        const bidTitle = this.bidFileList[0]?.name
        const bidFileUrl = this.bidFileList[0]?.url

        let file = this.bidFileList[0]?.raw
        if (!file && bidFileUrl) {
          file = await this.downloadFileAsBlob(bidFileUrl, bidTitle)
        }

        if (file) {
          const response = await uploadModifyFile(this.currentTopicId, file, this.agentInfo.agentName, node.title)
          if (response.data && response.data.assistantMessage) {
            this.selectedChapterContent = response.data.chapterContent[node.title] || ''
            // 更新文本域内容为返回结果
            this.inputMessage = response.data.chapterContent[node.title] || ''
          } else {
            this.selectedChapterContent = '暂无内容'
          }
        } else {
          this.selectedChapterContent = '请先上传文件'
        }
      } catch (error) {
        console.error('获取章节内容失败:', error)
        this.selectedChapterContent = '获取章节内容失败'
        this.$message.error('获取章节内容失败')
      } finally {
        this.chapterLoading = false
      }
    },

    // 解析章节内容
    parseChapterContent(chapterContent) {
      // chapterContent 是一个对象，键是章节标题，值是章节内容
      if (typeof chapterContent === 'object') {
        for (const [title, content] of Object.entries(chapterContent)) {
          // 如果选中了节点，且当前章节标题匹配选中节点，则更新选中章节内容
          if (this.selectedNode && this.selectedNode.title === title) {
            this.selectedChapterContent = content
          }
        }
      }
    },

    // 增加子节点
    addChildNode(node) {
      if (!node.children) {
        node.children = []
      }
      node.children.push({ title: '新目录', children: [] })
    },

    // 删除节点
    deleteNode(node) {
      this.removeNode(this.directoryTree, node)
      // 删除后重新编号
      this.renumberDirectory(node)
    },

    // 递归删除节点
    removeNode(nodes, nodeToRemove) {
      for (let i = 0; i < nodes.length; i++) {
        if (nodes[i] === nodeToRemove) {
          nodes.splice(i, 1)
          return true
        }
        if (nodes[i].children) {
          if (this.removeNode(nodes[i].children, nodeToRemove)) {
            return true
          }
        }
      }
      return false
    },

    // 重新编号目录树
    /**
 * 重新编号目录树，并可选删除指定节点
 * @param {string|null} deleteTarget - 需要删除的节点编号，不传则仅重新编号
 */
    renumberDirectory(deleteTarget = null) {
      // directoryTree 结构: [{ title: '6 技术文件', children: [二级标题...] }]
      if (!this.directoryTree || this.directoryTree.length === 0) return

      const rootNode = this.directoryTree[0]
      if (!rootNode || !rootNode.children) return

      // 提取根标题的前缀（如 "6"）
      const rootMatch = rootNode.title.match(/^(\d+)/)
      const rootPrefix = rootMatch ? rootMatch[1] : '6'

      // 递归重新编号节点
      const renumberNodes = (nodes, parentPrefix) => {
        // 1. 如果指定了删除目标，则倒序遍历删除目标节点及其子节点
        if (deleteTarget) {
          for (let i = nodes.length - 1; i >= 0; i--) {
            // 提取当前节点原始的编号部分
            const numMatch = nodes[i].title.match(/^(\d+(?:\.\d+)*)/)
            const originalNum = numMatch ? numMatch[1] : ''

            // 如果原始编号等于目标，或者是目标的子级（以 目标. 开头），则移除
            if (originalNum === deleteTarget || originalNum.startsWith(`${deleteTarget}.`)) {
              nodes.splice(i, 1)
            }
          }
        }

        // 2. 遍历剩余节点，进行重新编号
        nodes.forEach((node, index) => {
          const num = index + 1
          const newPrefix = `${parentPrefix}.${num}`

          // 从当前标题中提取文本内容（匹配任意层级的编号格式）
          const numberPattern = /^\d+(?:\.\d+)*\s+(.+)/
          const titleMatch = node.title.match(numberPattern)
          const text = titleMatch ? titleMatch[1].trim() : node.title.replace(/^\d+(?:\.\d+)*\s*/, '').trim()

          // 更新标题
          node.title = `${newPrefix} ${text}`

          // 递归处理子节点
          if (node.children && node.children.length > 0) {
            renumberNodes(node.children, newPrefix)
          }
        })
      }

      // 从二级标题开始重新编号
      renumberNodes(rootNode.children, rootPrefix)
    },

    // 选择节点
    async selectNode(node) {
      this.selectedNode = node
      // 重置生成状态，确保 bidResult 能正常显示
      this.isStreaming = false
      this.generationCompleted = false
      // 更新文本域内容为已选中章节标题
      if (node && node.title) {
        console.log(node.title)
        // 判断是否为叶子节点（没有 children 或 children 为空），只有叶子节点才查询数据库
        const isLeafNode = !node.children || node.children.length === 0
        if (isLeafNode && this.currentTopicId) {
          try {
            const chatRes = await listChat({ topicId: this.currentTopicId, input: node.title })
            if (chatRes.rows && chatRes.rows.length > 0) {
              // 如果找到了，显示已保存的内容
              this.bidResult = `<h3 style="color: #409EFF; margin: 10px 0;">【${node.title}】（已保存）</h3>
                                 <div style="line-height: 1.8;">${marked(chatRes.rows[0].output)}</div>`
              this.inputMessage = '已选中章节: ' + node.title + '（已有内容）'
              return
            }
          } catch (error) {
            console.error('查询章节内容失败:', error)
          }
        }
        // 如果没有找到已保存的内容，或非叶子节点，显示选中标题和暂无内容提示
        this.inputMessage = '已选中章节: ' + node.title
        this.bidResult = `<h3 style="color: #409EFF; margin: 10px 0;">【${node.title}】</h3>
                          <div class="empty-bid-content" style="padding: 40px; text-align: center; color: #999;">
                           <p>${isLeafNode ? '暂无内容' : '该节点为目录节点，请选择子章节'}</p>
                           <p style="font-size: 12px; margin-top: 8px;">${isLeafNode ? '点击"生成"按钮生成该章节内容' : '请展开并选择具体章节'}</p>
                         </div>`
      }
    },

    // 保存目录
    async saveDirectory() {
      try {
        const response = await writeTitles({
          filename: this.currentFilename,
          agentName: this.agentInfo.agentName,
          titles: this.directoryTree,
          topicId: this.currentTopicId
        })
        if (response.code === 200) {
          this.$message.success('目录保存成功')
        } else {
          this.$message.error('目录保存失败')
        }
      } catch (error) {
        console.error('保存目录失败:', error)
        this.$message.error('保存目录失败')
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.agent-detail-container {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.detail-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;

  .agent-header {
    padding: 16px 20px;
    border-bottom: 1px solid #e4e4e4;
    background: #f5f7fa;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .header-left {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .collapse-icon-btn {
      padding: 0;
      width: 24px;
      height: 24px;
      border: none;
      background: transparent;
      color: #6c757d;
      transition: all 0.3s;

      &:hover {
        background: #e9ecef;
        color: #495057;
      }
    }

    .mode-switcher {
      margin-left: 20px;
    }
  }
}

.chat-section {
  background: white;
  margin: 16px 24px;
  border-radius: 8px;
  border: 1px solid #e4e4e4;
  overflow: hidden;
  display: flex;
  height: calc(100vh - 150px);

  // 话题列表样式
  .topic-list {
    width: 25%;
    border-right: 1px solid #e4e4e4;
    display: flex;
    flex-direction: column;
    background: #f8f9fa;

    .topic-header {
      padding: 16px 20px;
      border-bottom: 1px solid #e4e4e4;
      background: #f5f7fa;
      color: #495057;

      h4 {
        margin: 0;
        font-size: 14px;
        font-weight: 600;
        color: #495057;
        display: flex;
        align-items: center;

        &::before {
          content: "📚";
          margin-right: 8px;
          font-size: 16px;
        }
      }
    }

    .topic-content {
      flex: 1;
      overflow-y: auto;
      padding: 8px 0;

      .topic-item {
        padding: 12px 16px;
        border-bottom: 1px solid #e9ecef;
        transition: all 0.3s ease;
        background: white;
        margin: 4px 8px;
        border-radius: 6px;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        display: flex;
        justify-content: space-between;
        align-items: center;

        &:hover {
          background: #e3f2fd;
          transform: translateX(2px);
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);

          .topic-actions {
            opacity: 1;
          }
        }

        &.active {
          background: #f5f7fa;
          color: #495057;
          transform: translateX(3px);
          box-shadow: 0 3px 12px rgba(73, 80, 87, 0.2);
          border-left: 3px solid #409EFF;

          .topic-info {
            .topic-name {
              color: #495057;
              font-weight: 600;

              &::before {
                content: "💬";
                filter: none;
              }
            }

            .topic-time {
              color: #6c757d;
            }
          }
        }

        &:last-child {
          border-bottom: none;
        }

        .topic-info {
          flex: 1;
          cursor: pointer;
          min-width: 0; // 允许flex项目缩小到内容以下
          max-width: calc(100% - 40px); // 为删除按钮预留40px空间

          .topic-name {
            font-size: 13px;
            font-weight: 500;
            color: #495057;
            margin-bottom: 4px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 100%;

            &::before {
              content: "💬";
              margin-right: 6px;
              font-size: 12px;
            }
          }

          .topic-time {
            font-size: 11px;
            color: #6c757d;
            font-style: italic;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 100%;
          }
        }

        .topic-actions {
          flex-shrink: 0; // 防止删除按钮被压缩
          width: 32px; // 固定宽度
          display: flex;
          justify-content: center;
          opacity: 0;
          transition: opacity 0.3s ease;

          .delete-btn {
            width: 24px;
            height: 24px;
            padding: 0;
            border: none;
            background: #ff4757;

            &:hover {
              background: #ff3742;
              transform: scale(1.1);
            }

            .el-icon {
              font-size: 12px;
            }
          }
        }
      }
    }
  }

  // 对话内容区域样式
  .chat-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    background: #fdfdfd;

    .section-header {
      padding: 16px 20px;
      border-bottom: 1px solid #e4e4e4;
      background: #f5f7fa;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .collapse-icon-btn {
        padding: 0;
        width: 24px;
        height: 24px;
        border: none;
        background: transparent;
        color: #6c757d;
        margin-right: 8px;
        transition: all 0.3s;

        &:hover {
          background: #e9ecef;
          color: #495057;
        }
      }

      h3 {
        margin: 0;
        font-size: 16px;
        font-weight: 600;
        color: #495057;
        display: flex;
        align-items: center;

        &::before {
          content: "✨";
          margin-right: 8px;
          font-size: 18px;
        }
      }

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

    .chat-messages {
      flex: 1;
      padding: 16px 20px;
      overflow-y: auto;
      max-height: 900px;

      .message-item {
        display: flex;
        margin-bottom: 16px;
        align-items: flex-start;

        &.user-message {
          flex-direction: row-reverse;

          .message-avatar {
            background: #1890ff;
            color: white;
            margin-left: 12px;
            margin-right: 0;
          }

          .message-content {
            text-align: right;

            .message-text {
              background: #1890ff;
              color: white;
            }

            .message-actions {
              justify-content: flex-end;

              .retry-btn {
                order: -1; // 将重试按钮放在时间前面
                margin-left: 0;
                margin-right: 8px;
                color: #1890ff;
                background-color: rgba(255, 255, 255, 0.9);

                &:hover {
                  background-color: white;
                }
              }
            }
          }
        }

        &.assistant-message {
          .message-avatar {
            background: #f0f0f0;
            color: #666;
            margin-right: 12px;
          }

          .message-content {
            .message-text {
              background: #f0f0f0;
              color: #333;
            }
          }

          // 文件信息消息特殊样式
          &.file-info-message {
            .message-avatar {
              background: #e3f2fd;
              color: #1976d2;
            }

            .message-content {
              .message-text {
                background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%);
                color: #1565c0;
                border-left: 4px solid #2196f3;
                font-weight: 500;

                &::before {
                  content: "📋";
                  margin-right: 8px;
                  font-size: 16px;
                }
              }
            }
          }
        }

        .message-avatar {
          width: 32px;
          height: 32px;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          font-size: 30px;
          flex-shrink: 0;
        }

        .message-content {
          max-width: 70%;

          .message-text {
            padding: 8px 12px;
            border-radius: 8px;
            font-size: 14px;
            line-height: 1.5;
            word-wrap: break-word;

            // HTML消息中的链接样式
            :deep(a) {
              color: #1890ff;
              text-decoration: underline;

              &:hover {
                color: #40a9ff;
                text-decoration: none;
              }
            }

            // 换行处理
            :deep(br) {
              display: block;
              margin: 4px 0;
            }
          }

          .message-actions {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-top: 4px;

            .message-time {
              font-size: 11px;
              color: #999;
            }

            .retry-btn {
              font-size: 11px;
              color: #1890ff;
              padding: 2px 6px;
              margin-left: 8px;

              &:hover {
                background-color: #f0f8ff;
              }

              .el-icon {
                font-size: 12px;
                margin-right: 2px;
              }
            }
          }
        }

        // 聊天内文件上传区域样式
        .message-upload-area {
          background: #f8f9fa;
          border: 1px dashed #d0d7de;
          border-radius: 8px;
          padding: 16px;

          .upload-tip {
            margin: 0 0 12px 0;
            font-size: 14px;
            color: #333;
          }

          .inline-upload {
            margin-bottom: 12px;

            :deep(.el-upload-list) {
              margin-top: 8px;

              .el-upload-list__item {
                font-size: 12px;
                margin: 2px 0;
              }

              .el-upload-list__item:first-child {
                margin-top: -30px;
              }
            }
          }

          .chat-upload-actions {
            display: flex;
            gap: 8px;
            margin-top: 8px;
          }
        }
      }
    }

    .chat-input-area {
      padding: 16px 20px;
      border-top: 1px solid #e4e4e4;

      .input-actions {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-top: 8px;

        .input-tip {
          font-size: 12px;
          color: #999;
        }
      }
    }
  }
}

// 打字指示器动画
.typing-indicator {
  display: flex;
  gap: 4px;
  padding: 8px 12px;
  background: #f0f0f0;
  border-radius: 8px;

  span {
    width: 6px;
    height: 6px;
    background: #999;
    border-radius: 50%;
    animation: typing 1.4s infinite ease-in-out;

    &:nth-child(1) {
      animation-delay: -0.32s;
    }

    &:nth-child(2) {
      animation-delay: -0.16s;
    }
  }
}

@keyframes typing {

  0%,
  80%,
  100% {
    transform: scale(0.8);
    opacity: 0.6;
  }

  40% {
    transform: scale(1);
    opacity: 1;
  }
}

.empty-main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;

  .agent-header {
    padding: 16px 20px;
    border-bottom: 1px solid #e4e4e4;
    background: #f5f7fa;
    display: flex;
    justify-content: space-between;
    align-items: center;

    h3 {
      margin: 0;
      font-size: 16px;
      font-weight: 600;
      color: #495057;
      display: flex;
      align-items: center;

      &::before {
        content: "✨";
        margin-right: 8px;
        font-size: 18px;
      }
    }

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

.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #999;

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

/* 任务模式样式 */
.task-section {
  background: white;
  margin: 16px 24px;
  border-radius: 8px;
  border: 1px solid #e4e4e4;
  overflow: hidden;
  display: flex;
  height: calc(100vh - 220px);

  /* 主内容区域 */
  .task-main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;

    .section-header {
      padding: 16px 20px;
      border-bottom: 1px solid #e4e4e4;
      background: #f5f7fa;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .collapse-icon-btn {
        padding: 0;
        width: 24px;
        height: 24px;
        border: none;
        background: transparent;
        color: #6c757d;
        margin-right: 8px;
        transition: all 0.3s;

        &:hover {
          background: #e9ecef;
          color: #495057;
        }
      }

      h3 {
        margin: 0;
        font-size: 16px;
        font-weight: 600;
        color: #495057;
        display: flex;
        align-items: center;

        &::before {
          content: "✨";
          margin-right: 8px;
          font-size: 18px;
        }
      }

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

  /* 任务模式历史任务列表样式 */
  .topic-list {
    width: 25%;
    border-right: 1px solid #e4e4e4;
    display: flex;
    flex-direction: column;
    background: #f8f9fa;

    .topic-header {
      padding: 16px 20px;
      border-bottom: 1px solid #e4e4e4;
      background: #f5f7fa;
      color: #495057;

      h4 {
        margin: 0;
        font-size: 14px;
        font-weight: 600;
        color: #495057;
        display: flex;
        align-items: center;

        &::before {
          content: "📋";
          margin-right: 8px;
          font-size: 16px;
        }
      }
    }

    .topic-content {
      flex: 1;
      overflow-y: auto;
      padding: 8px 0;

      .topic-item {
        padding: 12px 16px;
        border-bottom: 1px solid #e9ecef;
        transition: all 0.3s ease;
        background: white;
        margin: 4px 8px;
        border-radius: 6px;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        display: flex;
        justify-content: space-between;
        align-items: center;

        &:hover {
          background: #e3f2fd;
          transform: translateX(2px);
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);

          .topic-actions {
            opacity: 1;
          }
        }

        &.active {
          background: #f5f7fa;
          color: #495057;
          transform: translateX(3px);
          box-shadow: 0 3px 12px rgba(73, 80, 87, 0.2);
          border-left: 3px solid #409EFF;

          .topic-info {
            .topic-name {
              color: #495057;
              font-weight: 600;

              &::before {
                content: "✅";
                filter: none;
              }
            }

            .topic-time {
              color: #6c757d;
            }
          }
        }

        &:last-child {
          border-bottom: none;
        }

        .topic-info {
          flex: 1;
          cursor: pointer;
          min-width: 0;
          max-width: calc(100% - 40px);

          .topic-name {
            font-size: 13px;
            font-weight: 500;
            color: #495057;
            margin-bottom: 4px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 100%;

            &::before {
              content: "📄";
              margin-right: 6px;
              font-size: 12px;
            }
          }

          .topic-time {
            font-size: 11px;
            color: #6c757d;
            font-style: italic;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 100%;
          }
        }

        .topic-actions {
          flex-shrink: 0;
          width: 32px;
          display: flex;
          justify-content: center;
          opacity: 0;
          transition: opacity 0.3s ease;

          .delete-btn {
            width: 24px;
            height: 24px;
            padding: 0;
            border: none;
            background: #ff4757;

            &:hover {
              background: #ff3742;
              transform: scale(1.1);
            }

            .el-icon {
              font-size: 12px;
            }
          }
        }
      }
    }
  }

  :deep(.el-tabs__content) {
    height: calc(100vh - 400px);
    overflow: hidden;
  }

  /* 内层文档分析tabs */
  :deep(.el-tabs--border-card > .el-tabs__content) {
    height: calc(100vh - 400px);
    overflow: hidden;
  }

  /* 标书内容内部tabs */
  :deep(.task-content .el-tabs__content) {
    height: 100%;
    overflow: hidden;
  }
}

.task-content {
  padding: 20px;
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 500px;
  box-sizing: border-box;

  .upload-section {
    flex: 1;
    text-align: center;
    padding: 40px 20px;
    background: #f8f9fa;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 400px;
    min-width: 600px;

    h4 {
      margin: 0 0 20px 0;
      font-size: 16px;
      color: #333;
    }

    .upload-area {
      margin: 20px 0;

      :deep(.el-upload-dragger) {
        width: 100%;
        max-width: 500px;
        min-width: 300px;
        min-height: 200px;
        margin: 0 auto;
      }
    }

    .upload-tip {
      margin-top: 12px;
      font-size: 14px;
      color: #666;
    }

    .task-upload-actions {
      margin-top: 20px;
    }

    .upload-progress {
      margin-top: 30px;
      max-width: 500px;
      min-width: 300px;
      margin-left: auto;
      margin-right: auto;
    }
  }
}

.analysis-content {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 400px;
  min-width: 600px;

  h4 {
    margin: 0 0 20px 0;
    font-size: 16px;
    color: #333;
    flex-shrink: 0;
  }

  .analysis-result {
    background: #f8f9fa;
    padding: 20px;
    border-radius: 8px;
    flex: 1;
    overflow-y: auto;
    min-height: 300px;
    max-height: calc(100vh - 400px);

    h4 {
      margin: 0 0 15px 0;
      font-size: 14px;
      color: #333;
    }

    p {
      margin: 8px 0;
      line-height: 1.5;
    }

    ul {
      margin: 10px 0;
      padding-left: 20px;
    }

    li {
      margin: 5px 0;
    }

  }
}

.bid-content {
  flex: 1;
  min-height: 0;
  min-width: 700px;
  display: flex;
  flex-direction: column;

  h4 {
    margin: 0 0 20px 0;
    font-size: 16px;
    color: #333;
  }

  .el-form {
    margin-bottom: 20px;
    flex-shrink: 0;
  }

  .bid-title-row {
    display: flex;
    align-items: center;
    gap: 15px;
  }

  .directory-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
  }

  .token-info-container {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 15px;
    padding: 8px 12px;
    background: #f5f7fa;
    border-radius: 4px;
    font-size: 13px;
  }

  .token-info-row {
    display: flex;
    align-items: center;
    gap: 5px;
  }

  .token-label {
    color: #666;
    font-weight: 500;
  }

  .token-value {
    color: #409EFF;
    font-weight: 600;
    min-width: 60px;
    text-align: right;
  }

  .chapter-section {
    display: flex;
    flex-direction: column;
    gap: 15px;
    margin-top: 5px;
    flex: 1;
    overflow: hidden;
    min-height: 400px;

    .chapter-content-wrapper {
      display: flex;
      gap: 15px;
      flex: 1;
      min-height: 400px;
      overflow: hidden;

      .directory-tree {
        width: 35%;
        min-width: 250px;
        max-height: 600px;
        border: 1px solid #e4e7ed;
        border-radius: 4px;
        padding: 15px;
        background: #fafafa;
        display: flex;
        flex-direction: column;
        flex-shrink: 0;
        overflow-y: auto;

        .directory-actions {
          display: flex;
          gap: 8px;
          margin-bottom: 15px;
          flex-wrap: wrap;
          flex-shrink: 0;
        }

        .tree-container {
          flex: 1;
          min-height: 200px;
        }

        .empty-tree-container {
          flex: 1;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          color: #909399;
          min-height: 200px;

          i {
            font-size: 48px;
            margin-bottom: 16px;
            opacity: 0.5;
          }

          p {
            margin: 0;
            font-size: 14px;
          }
        }

        .directory-item {
          border-radius: 4px;
          padding: 6px;
          transition: all 0.3s;

          &:hover {
            background-color: #f5f7fa;
          }

          &.selected {
            background-color: #ecf5ff;
            border: 1px solid #d9ecff;
          }

          &.level-1 {
            margin-left: 0;
          }

          &.level-2 {
            margin-left: 6px;
          }

          &.level-3 {
            margin-left: 12px;
          }

          .directory-node {
            display: flex;
            align-items: center;
            gap: 8px;

            .el-input {
              flex: 1;
            }

            .node-actions {
              display: none;
              gap: 4px;
            }

            &:hover .node-actions {
              display: flex;
            }
          }

          .el-input {
            width: 100%;
          }
        }
      }

      .bid-content-area {
        flex: 1;
        max-height: 600px;
        border: 1px solid #e4e7ed;
        border-radius: 4px;
        padding: 15px;
        background: white;
        min-height: 400px;
        display: flex;
        flex-direction: column;
        overflow-y: auto;
        flex-shrink: 0;

        .bid-result-content {
          flex: 1;
          line-height: 1.6;
          color: #303133;
        }

        .empty-bid-content {
          flex: 1;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          color: #909399;

          i {
            font-size: 48px;
            margin-bottom: 16px;
            opacity: 0.5;
          }

          p {
            margin: 0;
            font-size: 14px;
          }
        }
      }
    }

    .export-section {
      margin-top: 40px;
      text-align: center;
    }
  }
}
</style>