<template>
  <div class="ai-search-detail">
    <a-affix>
      <div class="header">
        <home-header @login="emits('login')"  sub-title="自然资源大模型" />
      </div>
    </a-affix>
    <div class="search-panel" id="pageContainer">
      <a-affix
        ref="markdownTocAffixRef"
        :style="`width: 20%;margin-left: 13%;max-height: ${tocHeight}px;`"
        :offset-top="110"
        v-show="!showDoc"
      >
        <markdown-toc :no-data="activeTab === 'original'" :toc="tocs" :class="`markdown-toc-${askType}`" />
      </a-affix>
      <div :class="`search-detail search-detail-${askType}`" ref="searchRef">
        <div
          class="search-result"
          id="searchResult"
          style="overflow-x: hidden; height: auto"
          ref="messageContainer"
        >
          <div class="top">
            <div class="title">
              <div class="icon"></div>
              <div class="question" style="cursor: pointer" @click="openAskModal">
                {{ question }}
              </div>
              <div v-show="askType === 'tdsc'" class="graph-switch">
                <a-switch v-model:checked="graph" @change="questLandMark" />
                生成图表
              </div>
            </div>
          </div>

          <div :class="`result-panel result-panel-${askType}`">
            <div class="search-steps" v-show="activeIndex !== -1 && activeIndex < 5">
              <div
                v-show="st.key <= activeIndex"
                :class="`step ${st.key < activeIndex ? 'step-done' : ''}`"
                v-for="(st, i) in steps"
                :key="`step-${i}`"
              >
                <div class="info">
                  <div class="icon"></div>
                  <div class="title">{{ st.name }}</div>
                  <div class="tags">
                    <div
                      v-if="st.key === 2 && askType === 'tdsc'"
                      style="width: 20%; font-size: 14px; line-height: 22px"
                      class="tag-last"
                    >
                      {{ st.agent }}
                    </div>
                    <div
                      :class="`tag${st.key === 0 ? ' tag-first' : ''}`"
                      v-if="st.key < 3 && askType !== 'tdsc'"
                      :title="t"
                      v-for="(t, i) in st.tags"
                      :key="`tag-${i}`"
                    >
                      {{ t }}
                    </div>
                    <div
                      class="d"
                      style="
                        width: 80%;
                        overflow: hidden;
                        animation: scroll-text-992e3d76 25s linear infinite;
                      "
                      v-if="st.key < 3 && askType === 'tdsc'"
                    >
                      <div
                        :title="t"
                        :class="`tag${askType === 'tdsc' ? ' tag-rol' : ''}`"
                        v-for="(t, i) in st.tags"
                        :key="`tag-${i}`"
                      >
                        <div>{{ t }}</div>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="progress">
                  <a-progress size="small" :show-info="false" :percent="st.prog" />
                </div>
              </div>
            </div>

            <div class="result">
              <template v-if="askType === 'zcfg'">
                <div class="tabs" style="position: relative">
                  <div
                    :class="`tab${activeTab === t.key ? ' tab-active' : ''}`"
                    v-for="t in tabs"
                    :key="t.key"
                    @click="changeTab(t.key)"
                  >
                    <div class="title">{{ t.name }}</div>
                    <div class="bottom"></div>
                  </div>
                  <div
                    class="scope-type"
                    style="
                      display: flex;
                      align-items: center;
                      position: absolute;
                      right: 5px;
                      top: 10px;
                    "
                  >
                    <div class="label">搜索模式：</div>
                    <a-radio-group
                      v-model:value="answerType"
                      @change="changeAnswerType"
                      name="radioGroup"
                    >
                      <a-radio value="0">简洁</a-radio>
                      <a-radio value="1">深入</a-radio>
                      <a-radio value="2">研究</a-radio>
                    </a-radio-group>
                    <div class="ds-box">
                      <div @click="onChange('1')" :class="{active: dsChecked === true}">
                        <i class="iconfont icon-deepsee"></i>
                      </div>
                      <div @click="onChange('0')" :class="{active: dsChecked === false}">
                        <i class="iconfont icon-tongyi"></i>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="result-view">
                  <div class="q-r">
                    <div class="ds-content-box" v-if="dsChecked">
                      <div class="icon">
                        <img src="/images/icon-ds.png" />
                      </div>
                      <div class="ds-panel">
                        <div class="ds-loading" v-if="dsHintTxt" @click="dsUp = !dsUp">
                          {{ dsHintTxt }}
                          <DownOutlined class="icon-arrow" :class="{ rotate: dsUp }" />
                        </div>
                        <div class="ds-con" v-if="!dsUp">
                          <vue-markdown-it
                            id="dsMarkdown"
                            :source="
                              currentResponse.streamMock
                                ? currentResponse.streamMsg.indexOf('###') > -1
                                  ? currentResponse.streamMsg.substring(
                                      0,
                                      currentResponse.streamMsg.indexOf('###')
                                    )
                                  : currentResponse.streamMsg
                                : currentResponse.msg.indexOf('###') > -1
                                ? currentResponse.msg.substring(
                                    0,
                                    currentResponse.msg.indexOf('###')
                                  )
                                : currentResponse.msg
                            "
                            :options="{
                              html: true,
                              linkify: true
                            }"
                          />
                        </div>
                        <a-spin :indicator="indicator" v-if="dsLoading" />
                      </div>
                    </div>
                    <vue-markdown-it
                      id="resMarkdown"
                      :source="
                        currentResponse.streamMock
                          ? currentResponse.streamMsg.indexOf('###') > -1
                            ? currentResponse.streamMsg.substring(
                                currentResponse.streamMsg.indexOf('###')
                              )
                            : ''
                          : dsChecked
                          ? currentResponse.msg.indexOf('###') > -1
                            ? currentResponse.msg.substring(currentResponse.msg.indexOf('###'))
                            : ''
                          : currentResponse.msg
                      "
                      :options="{
                        html: true,
                        linkify: true
                      }"
                    />
                  </div>
                  <a-skeleton
                    active
                    v-if="!dsLoading && (activeIndex < 2 || !currentResponse.msg)"
                  />
                  <div v-if="activeIndex >= 5" class="follow">
                    <div class="follow-btn" style="cursor: pointer">
                      <!--                     <a-button v-show="activeTab === 'knowledge'" style="margin-right: 10px;float: left" type="link" color="green" size="small" @click="reAnswer">-->
                      <a-button
                        style="
                          margin-right: 35px;
                          float: left;
                          font-family: Microsoft YaHei;
                          font-weight: 400;
                          font-size: 16px;
                          color: #465d7c;
                        "
                        type="link"
                        color="green"
                        size="small"
                        @click="changeTab(activeTab)"
                      >
                        重新生成
                      </a-button>
                      <div class="eval-card" style="float: left">
                        <div
                          :class="`eval-icon eval-icon-like${evaluate === 'like' ? '-s' : ''}`"
                          @click="evalResponse('like')"
                        ></div>
                        <a-divider type="vertical" />
                        <div
                          :class="`eval-icon eval-icon-dislike${
                            evaluate === 'dislike' ? '-s' : ''
                          }`"
                          @click="evalResponse('dislike')"
                        ></div>
                        <a-divider type="vertical" />
                        <a-dropdown :trigger="['click']">
                          <a class="ant-dropdown-link" @click.prevent>
                            <div :class="`eval-icon eval-icon-copy`"></div>
                          </a>
                          <template #overlay>
                            <a-menu>
                              <a-menu-item key="0" @click="copy()"> 复制到剪贴板</a-menu-item>
                              <a-menu-divider />
                              <a-menu-item key="1" @click="exportAnswer('doc')">
                                导出 Word
                              </a-menu-item>
                              <a-menu-divider />
                              <a-menu-item key="2" @click="exportAnswer('pdf')">
                                导出 PDF
                              </a-menu-item>
                            </a-menu>
                          </template>
                        </a-dropdown>
                      </div>
                    </div>
                    <div class="follow-input" v-show="followVisible">
                      <a-textarea
                        v-model:value="followQuestion"
                        class="input-text"
                        v-model="followQuestion"
                        placeholder="继续提问"
                      />
                      <div class="button" @click="followAsk">发送</div>
                    </div>
                  </div>
                  <!--                  <div class="more-questions" v-if="activeTab === 'knowledge' && activeIndex >= 4">-->
                  <div class="more-questions" v-if="activeIndex >= 4">
                    <div class="title" style="margin-bottom: 14px">
                      你可以继续问我：
                      <div class="change-title" @click="changeRecommendedQuestions">
                        <div class="change-icon"></div>
                        换一批
                      </div>
                    </div>
                    <div class="questions" style="cursor: pointer">
                      <div
                        class="question"
                        @click="openRecommendedQuestion(q)"
                        v-for="(q, i) in questions"
                        :key="i"
                        style="
                          line-height: 14px;
                          text-align: left;
                          font-style: normal;
                          text-transform: none;
                          width: fit-content;
                          margin-bottom: 12px;
                          background: #ffffff;
                          box-shadow: 0px 1px 8px 0px #e4e4e4;
                          border-radius: 10px;
                          border: 1px solid #e9e9e9;
                          padding: 16px;
                          font-family: PingFang SC;
                          font-weight: 500;
                          font-size: 14px;
                          color: #2185f2;
                        "
                      >
                        {{ q }}
                      </div>
                    </div>
                  </div>
                  <div class="source" v-if="activeTab !== 'original'" v-show="activeIndex === 5">
                    <div class="title">
                      <div class="icon"></div>
                      <div class="text">来源</div>
                      <div class="num">({{ currentResponse.docs.length }})</div>
                    </div>
                    <div class="items">
                      <div
                        class="item"
                        v-if="activeTab !== 'net'"
                        v-for="(doc, i) in currentResponse.docs"
                        :key="'doc-' + i"
                      >
                        <div class="doc">
                          <p>
                            <span
                              class="ma"
                              style="font-weight: bolder; color: #000000; margin-right: 10px"
                              >出处 [{{ i + 1 }}] </span
                            ><span class="doc-link" @click="openDoc(doc, i)">{{ doc.doc }}</span>
                          </p>
                          <div
                            :class="`doc-icon${
                              !doc.showContent ? ' doc-icon-show' : ' doc-icon-hide'
                            }`"
                            @click="doc.showContent = !doc.showContent"
                          ></div>
                        </div>

                        <div :class="`content${doc.showContent ? '' : ' content-hide'}`">
                          <p>{{ doc.content }}</p>
                        </div>
                      </div>
                      <div
                        class="item item-url"
                        v-if="activeTab === 'net'"
                        v-for="(doc, i) in currentResponse.docs"
                        :key="'doc-' + i"
                      >
                        <div class="doc">
                          <p>
                            <span class="doc-link" @click="openUrl(doc.link)">{{ doc.title }}</span>
                          </p>
                        </div>
                        <div class="bottom">
                          <div class="title-icon">
                            <div class="icon"></div>
                            <div class="title">{{ doc.doc }}</div>
                          </div>
                          <div class="index">{{ i + 1 }}</div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </template>
              <template v-else>
                <div v-if="activeIndex >= 1" class="map-answer">
                  <div class="left-panel">
                    <div class="content">
                      <div class="summary-card">
                        <div class="summary-title" id="tdscSummaryTitle">总结</div>
                        <div class="summary-content">
                          <a-skeleton active v-if="!currentResponse.msg" />
                          <vue-markdown-it
                            :source="
                              currentResponse.streamMock
                                ? currentResponse.streamMsg
                                : currentResponse.msg
                            "
                            :options="{
                              html: true,
                              linkify: true
                            }"
                          />
                          <!--                        {{currentResponse.msg}}-->
                        </div>
                      </div>
                      <div class="chart-card" v-if="currentResponse.hasChart" id="tdscChartCard">
                        <div class="chart-title">生成图表</div>
                        <a-skeleton
                          active
                          style="height: 100%"
                          v-if="!currentResponse.chartOption"
                        />
                        <div v-else class="chart" id="summaryChart"></div>
                      </div>
                    </div>
                  </div>
                  <!--                  <div class="map-panel" id="tdscMapPanel">-->
                  <!--                    <div class="map-title">空间位置</div>-->
                  <!--                    <div class="map">-->
                  <!--                      <a-i-map />-->
                  <!--                    </div>-->
                  <!--                  </div>-->
                </div>
              </template>
            </div>
          </div>
        </div>
        <!--   历史回答     -->
        <div
          v-show="askType === 'zcfg'"
          class="search-result result-history"
          style="overflow-y: hidden; height: auto"
          v-if="questHistories.length > 0"
          id="messageContainer"
        >
          <template v-for="(qh, i) in [...questHistories].reverse()" :key="`qh-${i}`">
            <div class="top">
              <div class="title">
                <div class="icon"></div>
                <div class="question" style="cursor: pointer">{{ qh.question }}</div>
              </div>
            </div>

            <div class="result-panel">
              <div class="result">
                <div class="tabs">
                  <div :class="`tab tab-active`">
                    <div class="title">回答</div>
                    <div class="bottom"></div>
                  </div>
                </div>
              </div>
              <div class="result-view">
                <div class="q-r">
                  <vue-markdown-it
                    :source="qh.msg"
                    :toc="true"
                    :options="{
                      html: true,
                      linkify: true
                    }"
                  />
                </div>
              </div>
            </div>
          </template>
        </div>
      </div>
      <a-affix v-if="showDoc" style="width: 52%; font-size: 16px" :offset-top="210">
        <div
          class="doc"
          style="width: 100%; background-color: white; height: calc(100vh - 190px); overflow: auto"
        >
          <p-d-f-viewer
            v-if="fileType === 'pdf'"
            :src="pdfSrc"
            @close="closeDoc"
            :content="pdfContent"
            :num="pdfNum"
          />
          <word-viewer
            v-if="fileType === 'docx'"
            :src="pdfSrc"
            @close="closeDoc"
            :content="pdfContent"
            :num="pdfNum"
          >
          </word-viewer>
          <txt-viewer v-if="fileType === 'txt'" :src="pdfSrc" @close="closeDoc" :txt="pdfContent" />
        </div>
      </a-affix>
    </div>

    <a-modal force-render class="input-modal" v-model:open="open" :closable="false" width="700px">
      <template #footer>
        <div class="footer" style="height: 26px; margin: 0 auto">
          <div class="left" style="float: left; cursor: pointer" @click="clearModalTextArea">
            清空
          </div>
          <a-button style="float: right" type="primary" size="small" @click="sendModalTextArea">
            发送
          </a-button>
        </div>
      </template>
      <div class="modal-que">
        <ai-textarea :q="question" ref="aiTextAreaRef" @enter="ask" />
      </div>
    </a-modal>
  </div>
</template>
<script setup>
import { fetchEventSource } from '@microsoft/fetch-event-source';
import PDFViewer from '@/components/pdf/PdfCanvas.vue';
import WordViewer from '@/components/pdf/WordViewer.vue';
import AiTextarea from '@/components/TextArea/AiTextarea.vue';
import { VueMarkdownIt } from '@f3ve/vue-markdown-it';
import TxtViewer from '@/components/pdf/TxtViewer.vue';
import { message } from 'ant-design-vue';
import { ref, defineProps, watch } from 'vue';
import CommonAPI from '@/api/common';
import ManagerAPI from '@/api/manager';
import AIMap from '@/components/Map/AIMap.vue';
import * as echarts from 'echarts';
import PubsubService from '@/utils/PubsubService';
import MarkdownToc from '@/components/markdown-toc/MarkdownToc.vue';
import HomeHeader from '@/views/home/components/HomeHeader.vue';
import { useUserStore } from '@/stores';
const { user: u = {}, updateUser } = useUserStore();
const { user = {}, token } = u || {};
import UserAPI from '@/api/user';
const aiLoading = ref(false);
const router = useRouter();
const markdownTocAffixRef = ref(null);
const tocHeight = ref(530);
import { LoadingOutlined, DownOutlined } from '@ant-design/icons-vue';
import { h } from 'vue';
const indicator = h(LoadingOutlined, {
  style: {
    fontSize: '24px'
  },
  spin: true
});
const props = defineProps({
  searchType: '',
  askType: {
    type: String,
    default: 'zcfg'
  }
});

const answerType = ref('0');
const dsChecked = ref(true);
const scope = ref('net');
watch(
  () => router.currentRoute.value,
  (value) => {
    const { query } = value;
    if (query.q) {
      ask(decodeURIComponent(query.q));
      answerType.value = query.type || '0';
      scope.value = query.scope || 'net';
      dsHintTxt.value = '';
    }
  }
);

watch(
  () => router.currentRoute.value,
  (value) => {
    const { query } = value;
    if (query.q) {
      var ds = query.ds;
      if (ds && ds == '1') {
        ds = true;
      } else {
        ds = false;
      }
      dsChecked.value = ds;
    }
  },
  {
    immediate: true
  }
);

watch(props.searchType, (val) => {
  activeTab.value = val;
});

const question = ref('国有土地的使用方式有哪些？');
const followQuestion = ref('');
const statusText = ref('检索中');
const activeIndex = ref(0);
const activeTab = ref(props.searchType);
let ctr = null;
const aiTextAreaRef = ref(null);
const searchRef = ref(null);

const evaluate = ref(null);

const scrollToBottom = () => {
  const messageContainer = document.getElementById('messageContainer');
  if (messageContainer && searchRef.value) {
  }
};

const clearModalTextArea = () => {
  aiTextAreaRef.value.clear();
};

const sendModalTextArea = () => {
  aiTextAreaRef.value.send();
};

const tocs = ref([]);
const open = ref(false);
const showDoc = ref(false);
const pdfSrc = ref('');
const pdfContent = ref('');
const pdfNum = ref(1);
const fileType = ref('pdf');
const dsLoading = ref(true);
const startTime = ref(0);
const endTime = ref(0);
const dsHintTxt = ref('');
const dsUp = ref(false);
const times = ref(0);
const timers = ref([]);
const currentResponse = ref({
  streamMsg: '',
  streamMock: false,
  msg: '',
  originAnswer: '',
  docs: []
});
let streamMockInterval = null;
const streamToAnswer = () => {
  console.log('streamToAnswer');
  currentResponse.value.index = 0;
  streamMockInterval = setInterval(() => {
    const { originAnswer = '', msg, streamMsg = '', id, index = 0 } = currentResponse.value;

    if (currentResponse.value.mockStart || index <= originAnswer.length) {
      currentResponse.value.streamMsg = originAnswer.substr(0, index + 2).replaceAll('\n', '  \n');
      if (originAnswer) {
        currentResponse.value.index += 2;
      }
      let num = getNum(currentResponse.value.streamMsg);

      while (num) {
        const docsNum = currentResponse.value.docs.length;
        if (docsNum && num > docsNum + 1) {
        }

        currentResponse.value.streamMsg = currentResponse.value.streamMsg.replace(
          `[[${num}]]`,
          `<span onclick="window.openDocByIndex(${num}, ${id})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 12px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 10px;background: #d0d5dd;    width: 20px;
    height: 20px;
    background: #FFFFFF;
    border-radius: 4px 4px 4px 4px;
    border: 1px solid #BACAE3;">${num}</span>`
        );

        num = getNum(currentResponse.value.streamMsg);
      }
    } else {
      if (streamMockInterval) {
        clearInterval(streamMockInterval);
        streamMockInterval = null;
      }

      activeIndex.value = 5;

      searchRef.value.scrollTop = 0;
      generateToc();
      console.log('mock 结束');
    }
  }, 50);
};

const tabs = [
  { key: 'knowledge', name: '知识库' },
  // { key: 'net', name: '全网' },
  { key: 'original', name: '原生' },
];

const steps = ref([
  {
    key: 0,
    name: '问题分析',
    tags: [],
    prog: 0
  },
  {
    key: 1,
    name: '知识搜索',
    tags: [],
    prog: 0
  },
  {
    key: 2,
    name: '整理答案',
    tags: [],
    prog: 0
  },
  {
    key: 3,
    name: '回答完成',
    tags: [],
    prog: 0
  }
]);

const doStep = () => {
  setInterval(() => {
    steps.value.forEach((v) => {
      if (v.key < activeIndex.value) {
        v.prog = 100;
      } else if (v.key === activeIndex.value) {
        if (v.prog + 1 === 100) {
        } else {
          v.prog += 1;
        }
      } else {
        v.prog = 0;
      }
    });
  }, 100);
};

// 相关案例关键词
const caseKeyWords = ref([]);

const setActiveIndexTags = (index, tags) => {
  steps.value[index].tags = [];
  // 把问题分析部分的关键词带出去
  if (index == 0 && tags.length > 0) {
    caseKeyWords.value = tags;
  }
  for (let i = 0; i < tags.length; i++) {
    setTimeout(function () {
      steps.value[index].tags = tags.slice(0, i + 1);
    }, 500 * (i + 1));
  }
};

const evalResponse = (evalType) => {
  // ManagerAPI.feedback(currentResponse.value.logId, evalType === 'like' ? 1 : 2).then((res) => {
  //   evaluate.value = evalType;
  //   message.info('感谢你的反馈！');
  // });
};

const changeStatusText = () => {
  let i = 0;
  setInterval(() => {
    statusText.value = '检索中' + '.'.repeat(i);

    if (i === 3) {
      i = 0;
    }
    i++;
  }, 500);
};
changeStatusText();
const askType = ref('zcfg');
const search = (q, type = 'zcfg') => {
  question.value = q;
  askType.value = type;
  if (ctr) {
    ctr.abort();
    ctr = null;
    if (streamMockInterval) {
      clearInterval(streamMockInterval);
      streamMockInterval = null;
    }
  }
  if (type === 'zcfg') {
    quest();
  } else {
    questLandMark();
  }
};

const graph = ref(false);

const questLandMark = async () => {
  activeIndex.value = 0;
  tocs.value = [];
  steps.value = [
    {
      key: 0,
      name: '问题分析',
      tags: [],
      prog: 0
    },
    {
      key: 1,
      name: '任务拆解',
      tags: [],
      prog: 0
    },
    {
      key: 2,
      name: 'Agent调用',
      tags: [],
      prog: 0
    },
    {
      key: 3,
      name: '回答完成',
      tags: [],
      prog: 0
    }
  ];

  currentResponse.value = {
    question: question.value,
    id: 1,
    msg: '',
    originAnswer: '',
    docs: [],
    msgFinished: false,
    hasChart: false
  };
  await getQuestionKeyWords();
  ctr = new AbortController();
  await fetchEventSource(window.AppGlobalConfig.landMarketUrl, {
    method: 'POST',
    openWhenHidden: true,
    timeout: 300000,
    // redirect: 'follow',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      data: question.value + (graph.value ? '，需要生成图表' : '，不需要生成图表')
    }),
    // mode: 'no-cors',
    signal: ctr.signal,
    async onmessage(msg) {
      const { data } = msg;

      if (!['', '[FINISH]', '[DONE]'].includes(data)) {
        try {
          currentResponse.value.originAnswer = data;
          const response = JSON.parse(data);

          if (response) {
            const { agent_responses = [] } = response;

            for (let agent of agent_responses) {
              // 问题分析
              if (agent.agent_name === 'plan_dispatcher' && activeIndex.value === 0) {
                if (
                  agent.choices.length > 0 &&
                  agent.choices.filter((v) => v.role === 'assistant').length > 0
                ) {
                  const chio = agent.choices.filter((v) => v.role === 'assistant')[0];
                  if (chio.finished) {
                    activeIndex.value = 1;
                    setActiveIndexTags(0, [chio.content]);
                  }
                }
              }

              if (agent.agent_name === 'land_supply_planner' && activeIndex.value === 1) {
                if (
                  agent.choices.length > 0 &&
                  agent.choices.filter((v) => v.role === 'assistant').length > 0
                ) {
                  const chio = agent.choices.filter((v) => v.role === 'assistant')[0];

                  if (chio.finished) {
                    activeIndex.value = 2;
                    setActiveIndexTags(1, [chio.content]);
                    if (chio.content.includes('generate_chart')) {
                      currentResponse.value.hasChart = true;
                    }
                  }
                }
              }

              if (
                ['generate_chart', 'LandSupplySqlAgent', 'summary'].includes(agent.agent_name) &&
                activeIndex.value === 2
              ) {
                if (
                  agent.choices.length > 0 &&
                  agent.choices.filter((v) => v.role === 'assistant').length > 0
                ) {
                  const chio = agent.choices.filter((v) => v.role === 'assistant')[0];

                  if (chio.finished && steps.value[2].agent !== agent.agent_name) {
                    steps.value[2].agent = agent.agent_name;
                    setActiveIndexTags(2, [chio.content]);
                  }
                }
              }

              if (agent.agent_name === 'summary') {
                steps.value[2].agent = 'summary';
                if (activeIndex.value === 2) {
                  activeIndex.value = 3;
                }
                if (agent.choices.length === 3) {
                  if (!currentResponse.value.msgFinished) {
                    currentResponse.value.msg = agent.choices[2].content;
                    currentResponse.value.msgFinished = agent.choices[2].finished;
                  }
                }
              }

              if (agent.agent_name === 'generate_chart') {
                currentResponse.value.hasChart = true;

                if (agent.executed) {
                  const option = JSON.parse(
                    agent.exec_res.replace('```json', '').replace('```', '').trim()
                  );

                  currentResponse.value.chartOption = option;
                  setTimeout(() => {
                    initChart(option);
                  }, 1000);
                }
              }
            }
          }
        } catch (e) {
          console.error(e, data);
        }
      }

      if (data === '[FINISH]') {
        activeIndex.value = 5;
      }
    },
    onclose() {
      activeIndex.value = 5;
      generateToc();
      collectQuestion();
    },
    onerror(err) {
      throw err;
    },
    onopen() {}
  });
};

const openAskModal = () => {
  open.value = true;
  nextTick(() => {
    if (aiTextAreaRef.value) {
      aiTextAreaRef.value.setText(question.value);
    }
  });
};

const ask = async (q, isFllow) => {
  if (ctr) {
    if (streamMockInterval) {
      clearInterval(streamMockInterval);
      streamMockInterval = null;
    }
    ctr.abort();
  }
  times.value = 0;
  if (timers.value) {
    timers.value.forEach((t) => {
      clearTimeout(t);
      t = null;
    });
  }
  timers.value = [];
  if (dsChecked.value) {
    dsHintTxt.value = '';
    dsLoading.value = true;
  }
  question.value = q;
  open.value = false;
  showDoc.value = false;
  askType.value = 'zcfg';
  // activeTab.value = 'knowledge';
  quest(isFllow);
};

const followAsk = () => {
  ask(followQuestion.value, true);
  followVisible.value = false;
  followQuestion.value = '';
  showDoc.value = false;
};

let questionUrl = '/chat/kb_chat';

const changeTab = (tab) => {
  dsLoading.value = dsChecked.value;
  dsHintTxt.value = '';
  times.value = 0;
  if (timers.value) {
    timers.value.forEach((t) => {
      clearTimeout(t);
      t = null;
    });
  }
  timers.value = [];
  if (tab === 'net') {
    questionUrl = '/chat/bing_chat';
  } else if(tab === 'knowledge'){
    questionUrl = '/chat/kb_chat';
  }else if(tab === 'original') {
    questionUrl = '/chat/chat';
  }

  activeTab.value = tab;
  if (ctr) {
    if (streamMockInterval) {
      clearInterval(streamMockInterval);
      streamMockInterval = null;
    }
    ctr.abort();
  }
  quest();
};
const onChange = (type) => {
  dsChange(type);
  changeAnswerType();
};
//ds绑定用户改变
const dsChange = (type) => {
  dsChecked.value = type === '0' ? false : true;
  localStorage.setItem("_isDeepSeek", type);
  if (timers.value) {
    timers.value.forEach((t) => {
      clearTimeout(t);
      t = null;
    });
    timers.value = [];
  }
  times.value = 0;
  dsHintTxt.value = '';
  //打字机效果 切换会打印
  aiLoading.value = true;
};
const changeAnswerType = () => {
  if (!dsChecked.value) {
    dsLoading.value = false;
    dsHintTxt.value = '';
  } else {
    dsLoading.value = true;
    dsHintTxt.value = '';
  }
  if (ctr) {
    if (streamMockInterval) {
      clearInterval(streamMockInterval);
      streamMockInterval = null;
    }
    ctr.abort();
  }
  quest();
};

const questHistories = ref([]);

const followVisible = ref(false);
let scb = null;
const quest = async (isFllow) => {
  startTime.value = Date.now();
  window.scroll({ top: 0, behavior: 'smooth' });
  tocs.value = [];
  question.value = (isFllow ? '追问: ' : '') + question.value;
  evaluate.value = null;
  activeIndex.value = 0;
  steps.value = [
    {
      key: 0,
      name: '问题分析',
      tags: [],
      prog: 0
    },
    {
      key: 1,
      name: '知识搜索',
      tags: [],
      prog: 0
    },
    {
      key: 2,
      name: '整理答案',
      tags: [],
      prog: 0
    },
    {
      key: 3,
      name: '正在生成答案...',
      tags: [],
      prog: 0
    }
  ];

  if (!isFllow) {
    showDoc.value = false;
  }
  searchRef.value.scrollTop = 0;
  if (isFllow) {
    const { id, question, msg, docs, originAnswer, keywords = [] } = currentResponse.value;
    questHistories.value.push({ id, question, msg, docs: docs, originAnswer, keywords });
  } else {
    questHistories.value = [];
  }
  aiLoading.value = true;
  if (scb !== null) {
    clearInterval(scb);
    scb = null;
  } else {
    scb = setInterval(() => {
      scrollToBottom();
    }, 500);
  }
  ctr = new AbortController();

  const id = questHistories.value.length;
  currentResponse.value = {
    question: question.value,
    id,
    msg: '',
    originAnswer: '',
    streamMock: false,
    streamMsg: '',
    docs: []
  };
  activeIndex.value = 0;
  getQuestionKeyWords();
  if (activeTab.value === 'net') {
    questionUrl = '/chat/bing_chat';
  } else if(activeTab.value === 'knowledge'){
    questionUrl = '/chat/kb_chat';
  }else if(activeTab.value === 'original') {
    questionUrl = '/chat/chat';
  }
  const topKs = window?.AppGlobalConfig?.topKs || {
    0: 5,
    1: 10,
    2: 15
  };
  let body = null
  if (activeTab.value === 'net') {
    body = {
      query: question.value,
      stream: true,
      model: dsChecked.value ? 'deepseek-r1' : '',
      search_type: answerType.value
    }
  } else if(activeTab.value === 'knowledge'){
    body = {
      query: question.value,
      mode: 'local_kb',
      kb_name: activeTab.value === 'paper' ? 'compose_paper_material_total' : dsChecked.value ? window?.AppGlobalConfig?.llm?.kb_name : 'policy',
      top_k: topKs[answerType.value],
      search_type: answerType.value,
      score_threshold: 0.5,
      model: dsChecked.value ? 'deepseek-r1' : '',
      history: isFllow ? getFlowHistory() : [],
      stream: true,
      prompt_name: 'rag_context_qa.md',
      return_direct: false
    }
  } else if (activeTab.value === 'original') {
    body = {
      query: question.value,
      stream: true
    }
  }
  if (activeTab.value === 'knowledge' && isFllow) {
    if (questHistories.value.length > 0) {
      body.history_keyword = questHistories.value[questHistories.value.length - 1].keywords;
    }
  }
  if (activeTab.value !== 'net' && answerType.value !== '0') {
    currentResponse.value.streamMock = true;
    currentResponse.value.mockStart = true;
    streamToAnswer();
  }
  const rootUrl = dsChecked.value ? window.AppGlobalConfig.knowledgeServer : window.AppGlobalConfig.aiServer
  await fetchEventSource(rootUrl + questionUrl, {
    method: 'POST',
    openWhenHidden: true,
    timeout: 300000,
    headers: {
      'Content-Type': 'application/json'
    },

    body: JSON.stringify(body),
    signal: ctr.signal,
    async onmessage(msg) {
      if (activeIndex.value !== 3) {
        activeIndex.value = 3;
        setActiveIndexTags(2, ['知识整理', '要点归纳', '总结摘要']);
      }

      activeTab.value === 'net' ? handleNetResponse(msg, id) : handleKnowledgeResponse(msg, id);
    },
    onclose() {
      if (scb !== null) {
        clearInterval(scb);
        scb = null;

        collectQuestion();
      }

      if (currentResponse.value.streamMock) {
        currentResponse.value.mockStart = false;
      } else {
        activeIndex.value = 5;

        searchRef.value.scrollTop = 0;
        generateToc();
      }
    },
    onerror(err) {
      throw err;
    },
    onopen() {
      setActiveIndexTags(1, ['国家法律法规', '地方性法规', '政府规章', '政策解读', '经典案例']);
    }
  });
};

const getFlowHistory = () => {
  const lastHistory = [...questHistories.value].splice(-1);
  const parm = [];
  lastHistory.forEach((item) => {
    parm.push({ role: 'user', content: item.question });
  });

  return parm;
};

const handleKnowledgeResponse = (msg, id) => {
  if (!msg || !msg.data) {
    return;
  }
  const rData = JSON.parse(msg.data);
  if (rData?.choices && rData.choices.length > 0) {
    if (activeTab.value === 'net' && rData.status !== 2) {
      return;
    }
    if (rData.status == 3) {
      if (timers.value) {
        timers.value.forEach((t) => {
          clearTimeout(t);
          t = null;
        });
        timers.value = [];
      }
      if (dsChecked.value) {
        endTime.value = Date.now();
        var time = ((endTime.value - startTime.value) / 1000).toFixed(0);
        dsHintTxt.value = `已深度思考（用时 ${time} 秒）`;
        dsLoading.value = false;
        aiLoading.value=true;
      }
        currentResponse.value.originAnswer = rData.choices[0]?.delta?.content.replaceAll(
          '\n',
          `  \n`
        );
        currentResponse.value.msg = rData.choices[0]?.delta?.content.replaceAll('\n', `  \n`);
        let num = getNum(currentResponse.value.msg);
        while (num) {
          const docsNum = currentResponse.value.docs.length;
          if (docsNum && num > docsNum + 1) {
          }

          currentResponse.value.msg = currentResponse.value.msg.replace(
            `[[${num}]]`,
            `<span onclick="window.openDocByIndex(${num}, ${id})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 12px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 10px;background: #d0d5dd;    width: 20px;
    height: 20px;
    background: #FFFFFF;
    border-radius: 4px 4px 4px 4px;
    border: 1px solid #BACAE3;">${num}</span>`
          );

          num = getNum(currentResponse.value.msg);
        }
    } else {
      aiLoading.value = false;
      if (dsChecked.value) {
        dsHintTxt.value = '思考中...';
        //ds模式打字机效果输出
        const timer = setTimeout(() => {
          if (!aiLoading.value) {
            currentResponse.value.originAnswer += rData.choices[0]?.delta?.content.replaceAll(
              '\n',
              `  \n`
            );
            currentResponse.value.msg += rData.choices[0]?.delta?.content.replaceAll('\n', `  \n`);
            let num = getNum(currentResponse.value.msg);
            while (num) {
              const docsNum = currentResponse.value.docs.length;
              if (docsNum && num > docsNum + 1) {
              }

              currentResponse.value.msg = currentResponse.value.msg.replace(
                `[[${num}]]`,
                `<span onclick="window.openDocByIndex(${num}, ${id})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 12px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 10px;background: #d0d5dd;    width: 20px;
    height: 20px;
    background: #FFFFFF;
    border-radius: 4px 4px 4px 4px;
    border: 1px solid #BACAE3;">${num}</span>`
              );

              num = getNum(currentResponse.value.msg);
            }
          }
          clearTimeout(timer);
          timers.value.push(timer);
        }, times.value * 15);
      } else {
        currentResponse.value.originAnswer += rData.choices[0]?.delta?.content.replaceAll(
          '\n',
          `  \n`
        );
        currentResponse.value.msg += rData.choices[0]?.delta?.content.replaceAll('\n', `  \n`);
        let num = getNum(currentResponse.value.msg);
        while (num) {
          const docsNum = currentResponse.value.docs.length;
          if (docsNum && num > docsNum + 1) {
          }

          currentResponse.value.msg = currentResponse.value.msg.replace(
            `[[${num}]]`,
            `<span onclick="window.openDocByIndex(${num}, ${id})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 12px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 10px;background: #d0d5dd;    width: 20px;
    height: 20px;
    background: #FFFFFF;
    border-radius: 4px 4px 4px 4px;
    border: 1px solid #BACAE3;">${num}</span>`
          );

          num = getNum(currentResponse.value.msg);
        }
      }

      // currentResponse.value.msg += rData.choices[0]?.delta?.content.replaceAll('\n', `  \n`);
    }
  }

  if (!currentResponse.value.docs.length) {
    if (rData.docs && rData.docs.length) {
      handleDocs(rData.docs);
    }
  }
  times.value++;
};

const handleNetResponse = (msg, id) => {
  const rData = msg.data;
  if (!!rData && rData !== '[DONE]') {
    try {
      const res = JSON.parse(rData);
      if (res.error) {
        activeIndex.value = 4;
        message.error(res.error);
        currentResponse.value.msg = res.error;

        return;
      }
      if (res.rag_finish) {
        if (activeIndex.value < 4) {
          activeIndex.value = 4;
        }
        if (dsChecked.value) {
          endTime.value = Date.now();
          var time = ((endTime.value - startTime.value) / 1000).toFixed(0);
          dsHintTxt.value = `已深度思考（用时 ${time} 秒）`;
          dsLoading.value = false;
        }
      } else {
        if (dsChecked.value && dsHintTxt.value != '思考中...') {
          dsHintTxt.value = '思考中...';
        }
      }
      if (res.result) {
        currentResponse.value.originAnswer = res.result;
        currentResponse.value.msg = res.result.replaceAll('\n', `  \n`);

        let num = getNum(currentResponse.value.msg);

        while (num) {
          const docsNum = currentResponse.value.docs.length;
          if (docsNum && num > docsNum + 1) {
            currentResponse.value.msg = currentResponse.value.msg.replace(`[[${num}]]`, ``);
          }
          currentResponse.value.msg = currentResponse.value.msg.replace(
            `[[${num}]]`,
            `<span onclick="window.openDocByIndex(${num}, ${id})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 12px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 10px;background: #d0d5dd">${num}</span>`
          );

          num = getNum(currentResponse.value.msg);
        }
      }
      if (res.source_list && res.source_list.length && !currentResponse.value.docs.length) {
        handleDocs(res.source_list);
      }
    } catch (e) {}
  }

  if (rData === '[DONE]') {
    console.log(currentResponse.value.msg);
  }
};

const handleDocs = (docs) => {
  if (
    docs.length === 1 &&
    "<span style='color:red'>未找到相关文档,该回答为大模型自身能力解答！</span>" === docs[0]
  ) {
    // message.warn("知识库中未收录相关内容，将为您自动切换全网模式，请稍候......");
    // changeTab('net');
    return;
  }

  currentResponse.value.docs = docs.map((v, i) => {
    if (activeTab.value === 'net') {
      return {
        index: v.num,
        doc: v.name,
        link: v.url,
        title: v.title,
        summary: v.summary,
        content: '',
        showContent: false,
        type: 'url'
      };
    }

    if (v.toLowerCase().indexOf('.pdf') > 0) {
      return {
        index: i++,
        doc: v.substring(v.toLowerCase().indexOf('] [') + 3, v.toLowerCase().indexOf('.pdf]') + 4),
        link: v.substring(v.toLowerCase().indexOf('.pdf]') + 6, v.toLowerCase().indexOf('.pdf)') + 4),
        content: v.substring(v.toLowerCase().indexOf('.pdf)') + 5),
        showContent: false,
        type: 'pdf'
      };
    } else if (v.toLowerCase().indexOf('.txt') > 0) {
      return {
        index: i++,
        doc: v.toLowerCase().substring(v.indexOf('] [') + 3, v.toLowerCase().indexOf('.txt]') + 4),
        link: v.toLowerCase().substring(v.indexOf('.txt]') + 6, v.toLowerCase().indexOf('.txt)') + 4),
        content: v.toLowerCase().substring(v.indexOf('.txt)') + 5),
        showContent: false,
        type: 'txt'
      };
    } else if (v.toLowerCase().indexOf('.docx') > 0) {
      return {
        index: i++,
        doc: v.substring(v.toLowerCase().indexOf('] [') + 3, v.toLowerCase().indexOf('.docx]') + 5),
        link: v.substring(v.toLowerCase().indexOf('.docx]') + 7, v.toLowerCase().indexOf('.docx)') + 5),
        content: v.substring(v.toLowerCase().indexOf('.docx)') + 6),
        showContent: false,
        type: 'docx'
      };
    }
  });
};

const openDoc = (doc, i) => {
  if (window.AppGlobalConfig.isDisabledSource) return;
  var link = doc.link;
  var type = doc.type;
  pdfSrc.value = link.replace(
    window.AppGlobalConfig.knowledgeDocUrl.replace(
      '=policy&',
      activeTab.value === 'paper' ? '=compose_paper_material_total&' : '=policy&'
    ),
    window.AppGlobalConfig.knowledgeDocUrlProxy.replace(
      '=policy&',
      activeTab.value === 'paper' ? '=compose_paper_material_total&' : '=policy&'
    )
  );
  showDoc.value = true;
  fileType.value = type;
  pdfContent.value = doc.content;
  pdfNum.value = i;
};

const closeDoc = () => {
  showDoc.value = false;
};

watch(
  () => showDoc.value,
  (newVal) => {
    // 发布打开关闭，在关闭文档的时候打开相关案例
    PubsubService.publish('switch-relevant-cases-box', newVal);
  }
);

const openUrl = (url) => {
  window.open(url, '_blank');
};

const openDocByIndex = (ind, id) => {
  showDoc.value = false;
  let link = null;
  if (id !== currentResponse.value.id) {
    if (questHistories.value[id].docs[ind - 1].type === 'url') {
      openUrl(questHistories.value[id].docs[ind - 1].link);
      return;
    }

    link = questHistories.value[id].docs[ind - 1].link;
    fileType.value = questHistories.value[id].docs[ind - 1].type;
  } else {
    if (currentResponse.value.docs[ind - 1].type === 'url') {
      openUrl(currentResponse.value.docs[ind - 1].link);
      return;
    }
    link = currentResponse.value.docs[ind - 1].link;
    fileType.value = currentResponse.value.docs[ind - 1].type;
    pdfContent.value = currentResponse.value.docs[ind - 1].content;
    pdfNum.value = currentResponse.value.docs[ind - 1].num;
  }
  pdfNum.value = ind;
  pdfSrc.value = link.replace(
    window.AppGlobalConfig.knowledgeDocUrl.replace(
      '=policy&',
      activeTab.value === 'paper' ? '=compose_paper_material_total&' : '=policy&'
    ),
    window.AppGlobalConfig.knowledgeDocUrlProxy.replace(
      '=policy&',
      activeTab.value === 'paper' ? '=compose_paper_material_total&' : '=policy&'
    )
  );
  showDoc.value = true;
};
window.openDocByIndex = openDocByIndex;
const getNum = (str) => {
  const matches = str.match(/\[\[(\d+)\]\]/);

  if (matches) {
    return matches[1]; // 输出: 2
  } else {
    return null;
  }
};

// 埋点采集数据
const collectQuestion = () => {
  const { question, originAnswer, keywords = [] } = currentResponse.value;
  const userStore = useUserStore();
  const param = {
    question,
    answer: originAnswer,
    questionType: askType.value === 'zcfg' ? '政策法规' : '土地市场',
    keywords: Array.isArray(keywords) ? keywords.join(',') : keywords,
    user: '游客',
    userId: '-1'
  };
  if (userStore.isLogin) {
    const { id = '-1', displayName = '游客' } = userStore?.user?.user || {};
    param.user = displayName;
    param.userId = id;
  }

  ManagerAPI.collect(param).then((res) => {
    if (res.data) {
      // 记录日志，用来反馈
      currentResponse.value.logId = res.data;
    }
  });
};

const questions = ref([]);
let recommendedQuestions = [];
let recommendedQuestionsIndex = 0;
const getRecommendedQuestion = async (b = false) => {
  const { question } = currentResponse.value;
  const myHeaders = new Headers();
  myHeaders.append('Content-Type', 'application/json');
  questions.value = [];
  if (!b) {
    recommendedQuestions = [];
  }
  recommendedQuestionsIndex = 0;
  const raw = JSON.stringify({
    query: `你会收到一个用户提问，请根据问题延伸出10个子问题。

在你回答问题的时候，还需要注意推荐给用户的问题必须以列表的形式返回。
for example：
[
    "1、南京市在推进产业用地高质量利用方面采取了哪些具体措施？这些措施的效果如何？",
    "2、杭州市创新型产业用地管理的具体实施细则是什么？这些细则如何促进传统产业转型升级？",
    "3、南京市和杭州市在土地供应方式上有哪些不同？这些不同如何影响各自的产业发展？",
    "4、南京市如何通过政策支持和激励措施吸引重大投资项目？这些措施的实际效果如何？",
    "5、杭州市“工业上楼”项目的实施情况如何？这一政策对提升土地利用效率有何影响？",
]

以下是用户提问：${question}`,
    // model: 'qwen1.5-chat',
    stream: false
  });

  const requestOptions = {
    method: 'POST',
    headers: myHeaders,
    body: raw,
    redirect: 'follow'
  };

  const rootUrl = dsChecked.value ? window.AppGlobalConfig.knowledgeServer : window.AppGlobalConfig.aiServer
  fetch(rootUrl + '/chat/chat', requestOptions)
    .then((response) => {
      return response.json()
    })
    .then((msgStr) => {
      const msg = JSON.parse(msgStr)
      const str = msg.choices[0]?.message?.content;
      if (str) {
        const str1 = str.slice(str.indexOf("</think>") + 7)
        recommendedQuestions = formatRecommendedQuestions(str1);
        questions.value = recommendedQuestions.slice(0, 5);
      }
    })
    .catch((error) => console.error(error));
};
const formatRecommendedQuestions = (str) => {
  return str
    .replace(/`|$$|$$|"|,/g, '')  // 清除引号、反引号、方括号和逗号
    .split('\n')                  // 按换行分割
    .map(line => line.trim())     // 去除首尾空格
    .filter(line => {             // 双条件过滤
      return (
        line.length > 0 &&         // 过滤空行
        /^\d+[、.]/.test(line)     // 匹配"1、"或"1."开头
      )
    })
    .map(line => {
      // 统一标点为中文顿号并保留末尾空格
      return line
        .replace(/^\d+\./, m => m.replace('.', '、')) // 英文标点转中文
        .replace(/\s*$/, '   ')                       // 强制保留末尾3空格
    });
}
const changeRecommendedQuestions = () => {
  recommendedQuestionsIndex++;
  if (recommendedQuestionsIndex % 2 === 0) {
    questions.value = recommendedQuestions.slice(0, 5);
  } else {
    questions.value = recommendedQuestions.slice(5);
    getRecommendedQuestion(true)
  }
};

const getQuestionKeyWords = async () => {
  const { question } = currentResponse.value;
  const myHeaders = new Headers();
  myHeaders.append('Content-Type', 'application/json');
  questions.value = [];
  const raw = JSON.stringify({
    query: `请从以下文本中提取核心关键词，确保关键词简洁明了且准确反映文本的主要内容。 请按照以下格式输出：关键词：关键词1，关键词2。文本如下：“${question}”`,
    stream: false
  });

  const requestOptions = {
    method: 'POST',
    headers: myHeaders,
    body: raw,
    redirect: 'follow'
  };

  const rootUrl = dsChecked.value ? window.AppGlobalConfig.knowledgeServer : window.AppGlobalConfig.aiServer
  return fetch(rootUrl + '/chat/chat', requestOptions)
    .then((response) => response.json())
    .then((msgStr) => {
      const msg = JSON.parse(msgStr)
      activeIndex.value = 1;
      const str = msg.choices[0]?.message?.content;
      if (str) {
        const str1 = str.slice(str.indexOf("</think>")+7)
        const keywords = splitWords(str1).slice(0, 3);
        setActiveIndexTags(0, keywords);
        currentResponse.value.keywords = keywords;
      }
    })
    .catch((error) => console.error(error));
};

const splitWords = (word) => {
  if (word) {
    word = word
      .replaceAll('核心词为：', '')
      .replaceAll('问题核心词：', '')
      .replaceAll('>', '')
      .replaceAll('。', '')
      .trim();

    if (word.indexOf('\n\n') !== -1) {
      return word.split('\n\n');
    }

    if (word.indexOf(',') !== -1) {
      return word.split(',');
    }

    if (word.indexOf('、') !== -1) {
      return word.split('、');
    }

    if (word.indexOf('，') !== -1) {
      return word.split('，');
    }

    return [word];
  }

  return [];
};

const exportAnswer = (type) => {
  const { question, originAnswer } = currentResponse.value;
  CommonAPI.answerExport(type, { question, answer: originAnswer });
};

const copy = async () => {
  try {
    const input = document.createElement('input');
    input.value = currentResponse.value.msg;
    document.body.appendChild(input);
    input.select();
    document.execCommand('copy');
    document.body.removeChild(input);

    message.info('内容已复制到剪贴板');
  } catch (err) {
    console.error(err);
    // console.error('复制到剪贴板失败', err);
  }
};

const changeActiveTab = (tab) => {
  activeTab.value = tab;
};

const stopAI = () => {
  if (ctr) {
    ctr.abort();
  }
};

const openRecommendedQuestion = (q) => {
  if (q) {
    if (q.charAt(1) === '、') {
      q = q.substring(2);
    }
    window.open(
      `/aisearch/#/ai-search?q=${encodeURI(q.trim())}&scope=${activeTab.value}&type=${answerType.value}`,
      '_blank'
    );
  }
};

function initChart(option = {}) {
  let chart = echarts.init(document.getElementById('summaryChart'));
  if (option.option) {
    chart.setOption(option.option);
  } else {
    chart.setOption(option);
  }
}

const generateToc = () => {
  if (askType.value === 'tdsc') {
    const summaryTitle = document.getElementById('tdscSummaryTitle');
    const chartCard = document.getElementById('tdscChartCard');
    const mapPanel = document.getElementById('tdscMapPanel');

    tocs.value = [];
    const offset = 550 + 210;
    tocs.value.push({
      id: 'tdscSummaryTitle',
      children: [],
      text: '总结',
      top: summaryTitle.offsetTop + offset
    });

    if (chartCard.style.display !== 'none') {
      tocs.value.push({
        id: 'tdscChartCard',
        children: [],
        text: '生成图表',
        top: chartCard.offsetTop + offset
      });
    }

    // tocs.value.push({
    //   id: 'tdscMapPanel',
    //   children: [],
    //   text: '空间位置',
    //   top: mapPanel.offsetTop + offset
    // });
    return;
  }
  const resMarkdownDom = document.getElementById("resMarkdown");
  let thinkDoms = resMarkdownDom.getElementsByTagName("think");
  let markdowns = null;
  if (!thinkDoms || thinkDoms.length === 0) {
    markdowns = resMarkdownDom.children;
  } else {
    markdowns = thinkDoms[0].children
  }
  let index = 1;
  let children = [];
  let toc = [];
  for (const markdown of markdowns) {
    if (markdown.tagName.length === 2 && markdown.tagName.toLocaleUpperCase().startsWith('H')) {
      const id = 'title' + index++ + new Date().getTime();
      markdown.setAttribute('id', id);
      const tocItem = {
        id,
        text: markdown.innerText.trim(),
        children: [],
        top: markdown.offsetTop
      };
      children = tocItem.children;
      toc.push(tocItem);
    }
    if (markdown.tagName.toLocaleUpperCase().trim() === 'P') {
      const pChildren = markdown.children;
      for (const pChild of pChildren) {
        if (pChild.tagName.toLocaleUpperCase().trim() === 'STRONG') {
          const id = 'strong' + index++ + new Date().getTime();
          pChild.setAttribute('id', id);
          const strongItem = {
            id,
            text: pChild?.innerText?.trim(),
            children: [],
            top: pChild.offsetTop
          };
          children.push(strongItem);
          // children = strongItem.children
        }
      }
    }
  }

  tocs.value = toc;

  console.log('toc', toc);
};

onMounted(() => {
  tocHeight.value = window.document.body.offsetHeight - 210 - 51;
  doStep();
  const { query } = router.currentRoute.value;
  if (query.q) {
    answerType.value = query.type || '0';
    scope.value = query.scope || 'net';
    var ds = '0';
    if (!useUserStore().isLogin) {
      ds = query.ds;
    } else {
      ds = useUserStore().user.user.enableDeepseek
        ? useUserStore().user.user.enableDeepseek + ''
        : query.ds;
    }
    dsHintTxt.value = '';
    if (ds && ds == '1') {
      ds = true;
      dsLoading.value = true;
    } else {
      ds = false;
      dsLoading.value = false;
    }
    dsChecked.value = ds;
    activeTab.value = scope.value;
    ask(decodeURIComponent(query.q));
  }

  window.addEventListener(
    'scroll',
    () => {
      if (markdownTocAffixRef.value && markdownTocAffixRef.value.updatePosition) {
        markdownTocAffixRef.value.updatePosition();
      }
    },
    true
  );
});

defineExpose({ search, changeActiveTab, stopAI });
</script>
<style scoped lang="scss">
@import 'src/assets/scss/variables';
.ai-search-detail {
  width: 100%;
  background: $background_color;
  height: 100%;
  .header {
    width: 100%;
    height: 60px;
    background: #F4F6F9;
  }


  .search-panel {
    width: 100%;
    height: calc(100% - 60px - 50px);
    display: flex;
    margin-top: 50px;
    padding-bottom: 50px;
    .markdown-toc-tdsc {
      :deep(.toc-list) {
        margin: 30px 0;
      }
    }

    .search-detail {
      width: calc(52%);
      background: #ffffff;
      margin-left: 52px;

      &-tdsc {
        width: calc(52%);
      }

      .search-result {
        height: calc(100% - 40px);

        .top {
          width: 100%;
          //height: 105px;
          background: #fff;
          //margin-bottom: 5px;
          border-radius: 4px 4px 4px 4px;

          .title {
            width: calc(100% - 7px - 2px);
            display: flex;
            //margin-bottom: 24PX;
            align-items: center;
            min-height: 33px;

            .icon {
              width: 33px;
              height: 29px;
              background: url('@/assets/images/ai-search/question-prefixicon.png') no-repeat;
              background-size: 100% 100%;
              margin-right: 16px;
            }

            .question {
              width: calc(100% - 32px - 150px);
              //line-height: 20px;
              font-family: PingFang SC, PingFang SC;
              font-weight: 600;
              font-size: 24px;
              color: #212121;
              text-align: left;
              font-style: normal;
              text-transform: none;
            }

            .graph-switch {
              display: flex;
              align-items: center;
              margin-left: 10px;
              width: 110px;

              button {
                margin-right: 2px;
              }
            }
          }

          .status {
            display: flex;
            align-items: center;
            margin-top: 15px;
            justify-content: center;

            @keyframes shake {
              0% {
                transform: translateX(0);
              }
              25% {
                transform: translateX(0px);
              }
              50% {
                transform: translateX(2px);
              }
              75% {
                transform: translateX(0px);
              }
              100% {
                transform: translateX(2px);
              }
            }

            .text {
              width: 55px;
              font-family: Alibaba PuHuiTi 3, Alibaba PuHuiTi 30;
              font-weight: normal;
              font-size: 14px;
              color: #9da6b5;
              line-height: 20px;
              text-stroke: 1px rgba(0, 0, 0, 0);
              text-align: left;
              font-style: normal;
              text-transform: none;
              -webkit-text-stroke: 1px rgba(0, 0, 0, 0);
            }
          }
        }

        .result-panel {
          width: 100%;
          background: #fff;
          padding: 29px 0;

          .search-steps {
            width: 100%;
            padding: 4px 0;
            display: flex;
            align-items: center;
            margin-bottom: 30px;
            flex-direction: column;

            .step {
              width: 100%;

              .info {
                width: 100%;
                padding: 0;
                display: flex;
                align-items: center;

                .icon {
                  width: 18px;
                  height: 18px;
                  background: url('@/assets/images/ai-search/step-wait-icon.png') no-repeat;
                  background-size: 100% 100%;
                  margin-right: 7px;
                }

                .title {
                  width: 120px;

                  font-family: PingFang SC, PingFang SC;
                  font-weight: 600;
                  font-size: 16px;
                  color: #212121;
                  text-align: left;
                  font-style: normal;
                  text-transform: none;
                }

                .tags {
                  width: calc(100% - 10px - 27px - 100px);
                  display: flex;
                  justify-content: end;
                  overflow: hidden;
                  height: 30px;
                  align-items: center;

                  .tag {
                    padding: 4px 14px;

                    margin-left: 8px;
                    line-height: 14px;
                    text-align: left;
                    font-style: normal;
                    text-transform: none;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    max-width: 200px;
                    cursor: pointer;
                    font-weight: 400;
                    font-size: 14px;
                    color: #2185f2;
                    height: 24px;
                    background: #f5f9fc;
                    border: 1px solid #e9eef5;
                    font-family: PingFang SC, PingFang SC;
                    font-weight: 400;
                    font-size: 14px;
                    color: #525b74;
                    /* line-height: 0px; */
                    text-align: left;
                    font-style: normal;
                    text-transform: none;

                    &-first {
                      background: none;

                      font-family: Microsoft YaHei;
                      font-weight: 400;
                      font-size: 16px;
                      color: #666666;
                    }
                  }

                  .tag-rol {
                    display: inline-block;
                    white-space: nowrap;
                    box-sizing: border-box;
                    //animation: scroll-text 25s linear infinite;
                    //width: 100%;
                    background: none;
                    height: 22px;
                    max-width: none;
                    overflow: unset;
                  }

                  @keyframes scroll-text {
                    0% {
                      transform: translateX(100%);
                    }
                    100% {
                      transform: translateX(-100%);
                    }
                  }
                }
              }

              &-done {
                .info {
                  .icon {
                    width: 18px;
                    height: 18px;
                    background: url('@/assets/images/ai-search/step-done-icon.png') no-repeat;
                    background-size: 100% 100%;
                    margin-right: 7px;
                  }

                  .title {
                    font-family: Microsoft YaHei;
                    font-weight: 400;
                    font-size: 16px;
                    color: #333333;
                    line-height: 30px;
                  }
                }
              }
            }
          }

          .result {
            width: 100%;

            .tabs {
              display: flex;
              border-bottom: 1px solid #ccc;
              .ds-box {
                display: flex;
                height: 36px;
                align-items: center;
                border: 1px solid #E3E4E4;
                background: #f0f0f0;
                border-radius: 5px;
                overflow: hidden;
                >div {
                  height: 100%;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  width: 108px;
                  cursor: pointer;
                  &.active {
                    background: #fff;
                    &:nth-child(1) {
                      .iconfont {
                        color: #4f6bfe;
                      }
                    }
                    &:nth-child(2) {
                      .iconfont {
                        color: #605BEC;
                      }
                    }
                  }
                  .iconfont {
                    color: #898D93;
                    margin-top: 2px;
                  }
                  &:nth-child(1) {
                    .iconfont {
                      font-size: 16px;
                    }
                  }
                  &:nth-child(2) {
                    .iconfont {
                      font-size: 22px;
                    }
                  }
                }
                .sw {
                  :deep(.ant-switch) {
                    background-color: #eaeaea;
                  }
                  :deep(.ant-switch-handle::before) {
                    background-color: #fff;
                  }
                }
                .sw-checked {
                  :deep(.ant-switch-checked) {
                    background-color: #fff;
                  }
                  :deep(.ant-switch-handle::before) {
                    background-color: #1890ff;
                  }
                }
              }
              .tab {
                font-family: PingFang SC, PingFang SC;
                font-weight: 400;
                font-size: 24px;
                color: #212121;
                text-align: left;
                font-style: normal;
                text-transform: none;
                margin-right: 28px;
                display: flex;
                justify-content: center;
                flex-direction: column;
                align-items: center;
                cursor: pointer;

                .title {
                  margin-bottom: 9px;
                }

                .bottom {
                  height: 0;
                  margin-top: 10px;
                }

                &-active,
                &:hover {
                  font-family: PingFang SC, PingFang SC;
                  font-weight: 400;
                  font-size: 24px;
                  color: #1586fa;
                  text-align: left;
                  font-style: normal;
                  text-transform: none;

                  .bottom {
                    width: 100%;
                    height: 4px;
                    background: #3987F4;
                    border-radius: 2px;
                  }
                }
              }
            }

            .result-view {
              width: 100%;
              height: 50%;
              overflow-y: auto;

              .q-r {
                padding: 20px;
                line-height: 30px;
                background: #f5f8fa;
                border-radius: 4px 4px 4px 4px;
                margin: 20px 0;
                .ds-content-box {
                  display: flex;
                  .icon {
                    width: 26px;
                    height: 26px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    border-radius: 50%;
                    background: white;
                    border: 1px solid #117ff9;
                    img {
                      width: 18px;
                      height: 18px;
                    }
                  }
                  .ds-panel {
                    margin-top: -5px;
                    margin-left: 10px;
                    width: calc(100% - 40px);
                    .ds-loading {
                      display: flex;
                      align-items: center;
                      .icon-arrow {
                        padding-left: 5px;
                        cursor: pointer;
                      }
                    }
                    .rotate {
                      transform: rotate(180deg);
                    }
                  }
                  .ds-con {
                    border-left: 1px solid #ccc;
                    padding-left: 10px;
                  }
                }
              }

              // 追问
              .follow {
                padding: 0 20px 20px 0;
                width: 100%;
                text-align: right;
                height: auto;
                min-height: 40px;

                .eval-card {
                  width: auto;
                  display: flex;
                  /* float: left; */
                  justify-content: center;
                  align-items: center;

                  .eval-icon {
                    width: 22px;
                    height: 22px;

                    &-like {
                      background: url('@/assets/images/ai-search/eval-like-icon.png') no-repeat;
                      background-size: 100% 100%;

                      &-s,
                      &:hover {
                        background: url('@/assets/images/ai-search/eval-like-icon.png') no-repeat;
                        background-size: 100% 100%;
                      }
                    }

                    &-dislike {
                      background: url('@/assets/images/ai-search/eval-dislike-icon.png') no-repeat;
                      background-size: 100% 100%;

                      &-s,
                      &:hover {
                        background: url('@/assets/images/ai-search/eval-dislike-icon.png') no-repeat;
                        background-size: 100% 100%;
                      }
                    }

                    &-copy {
                      background: url('@/assets/images/ai-search/eval-copy-icon.png') no-repeat;
                      background-size: 100% 100%;

                      &-s,
                      &:hover {
                        background: url('@/assets/images/ai-search/eval-copy-icon.png') no-repeat;
                        background-size: 100% 100%;
                      }
                    }
                  }
                }

                .follow-input {
                  margin-top: 10px;
                  position: relative;

                  textarea {
                    width: 100%;
                    height: 120px;
                    border-color: white;
                    border-radius: 10px;
                    resize: none;
                    padding: 10px;
                    background: transparent;
                    font-size: 19px;
                    border-color: #4096ff;
                    box-shadow: 0 0 0 2px rgba(5, 145, 255, 0.1);

                    textarea:focus-visible,
                    textarea:focus {
                      border: none !important;
                      outline: none;
                    }

                    textarea:focus {
                      border: none !important;
                      outline: none;
                    }
                  }

                  .button {
                    width: 110px;
                    height: 40px;
                    background: linear-gradient(90deg, #5c62ea, #517de2);
                    border-radius: 20px;
                    position: absolute;
                    right: 10px;
                    bottom: 12px;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    font-family: Alibaba PuHuiTi 2;
                    font-weight: normal;
                    font-size: 16px;
                    color: #ffffff;
                    cursor: pointer;
                  }
                }
              }

              .more-questions {
                .title {
                  display: flex;
                  margin-bottom: 14px;

                  .change-title {
                    margin-left: 20px;
                    display: flex;
                    cursor: pointer;
                    font-size: 13px;
                    color: #3c3c3c;

                    .change-icon {
                      width: 16px;
                      height: 16px;
                      margin-right: 4px;
                      background: url('@/assets/images/ai-search/icon-chang-question.png') no-repeat;
                      background-size: 100% 100%;
                    }
                  }
                }
              }

              .source {
                width: 100%;

                .title {
                  display: flex;
                  align-items: center;
                  font-family: PingFang SC;
                  font-weight: bold;
                  font-size: 20px;
                  color: #333333;
                  line-height: 30px;

                  .icon {
                    width: 20px;
                    height: 20px;
                    margin-right: 8px;
                    background: url('@/assets/images/ai-search/source-icon.png') no-repeat;
                    background-size: 100% 100%;
                  }

                  .text {
                    font-family: Alibaba PuHuiTi 3, Alibaba PuHuiTi 30;
                    font-weight: normal;
                    //font-size: 16px;
                    color: #404557;
                    line-height: 30px;
                    text-align: left;
                    font-style: normal;
                    text-transform: none;
                    margin-right: 5px;
                  }
                }

                .items {
                  .item {
                    width: calc(100% - 10px);
                    min-height: 82px;
                    background: rgba(255, 255, 255, 0.5);
                    border-radius: 10px;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    padding: 20px;
                    color: #888;
                    display: flex;
                    line-height: 25px;
                    margin-bottom: 20px;
                    margin: 12px 0;
                    background: #f1f9ff;
                    border-radius: 8px 8px 8px 8px;

                    .doc {
                      display: flex;
                      width: 100%;

                      p {
                        width: calc(100% - 25px);

                        .doc-link {
                          cursor: pointer;
                          color: #3987F4;

                          &:hover {
                            font-weight: bold;
                          }
                        }
                      }

                      .doc-icon {
                        width: 20px;
                        height: 20px;
                        margin-left: 5px;
                        cursor: pointer;

                        &-show {
                          background: url('/images/zcbd/ai-search/icon-doc-show.png') no-repeat;
                          background-size: 100% 100%;
                        }

                        &-hide {
                          background: url('/images/zcbd/ai-search/icon-doc-hide.png') no-repeat;
                          background-size: 100% 100%;
                        }
                      }
                    }

                    .content {
                      //white-space: pre-line;
                      width: 100%;
                      font-family: Alibaba PuHuiTi 3, Alibaba PuHuiTi 30;
                      font-weight: normal;
                      font-size: 14px;
                      color: #757575;
                      line-height: 28px;
                      text-align: left;
                      font-style: normal;
                      text-transform: none;

                      &-hide {
                        display: none;
                      }
                    }
                  }

                  .item-url {
                    margin: 12px 0;
                    background: #f1f9ff;
                    border-radius: 8px 8px 8px 8px;

                    .bottom {
                      width: 100%;

                      .title-icon {
                        display: flex;
                        justify-content: left;
                        align-items: center;
                        width: 90%;
                        float: left;

                        .icon {
                          width: 23px;
                          height: 23px;
                          background: url('/images/zcbd/ai-search/icon-net-url.png') no-repeat;
                          background-size: 100% 100%;
                        }

                        .title {
                          color: #a9a3a3cc;
                          font-size: 16px;
                          margin-left: 10px;
                        }
                      }

                      .index {
                        float: right;
                        width: 20px;
                        height: 20px;
                        font-size: 12px;
                        line-height: 20px;
                        text-align: center;
                        margin: 0 5px;
                        border-radius: 10px;
                        background: #d0d5dd;
                        color: #000;
                      }
                    }
                  }
                }
              }
            }

            // 土地市场
            .map-answer {
              position: relative;
              width: 100%;
              min-height: 600px;

              .left-panel {
                width: 100%;
                background: #ffffff;
                z-index: 1000;
                //position: relative;
                left: 12px;
                top: 15px;
                border-radius: 10px;

                .title {
                  width: 100%;
                  height: 30px;
                  text-align: left;
                  line-height: 30px;
                  font-size: 18px;
                  font-weight: bolder;
                }

                .content {
                  width: 100%;
                  height: auto;

                  .chart-card {
                    width: 100%;
                    height: 330px;

                    .chart-title {
                      width: 100%;
                      height: 30px;
                      font-size: 18px;
                      font-weight: bolder;
                      padding: 0 5px;
                      line-height: 30px;
                      margin: 10px 0;
                    }

                    .chart {
                      width: 100%;
                      height: 300px;
                    }

                    //background: #0a84ff;
                  }

                  .summary-card {
                    width: 100%;
                    height: 50%;

                    .summary-title {
                      width: 100%;
                      height: 30px;
                      font-size: 18px;
                      font-weight: bolder;
                      padding: 0 5px;
                      line-height: 30px;
                      margin: 10px 0;
                    }

                    .summary-content {
                      width: calc(100% - 20px);
                      height: calc(100% - 30px);
                      padding: 0;
                      white-space: pre-wrap;
                      overflow-y: auto;
                      border-radius: 10px;
                      margin: 10px;
                      font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Noto Sans, Helvetica,
                        Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
                      font-size: 16px;
                      line-height: 1.5;
                    }
                  }
                }
              }

              .map-panel {
                width: 100%;
                height: 630px;

                .map-title {
                  width: 100%;
                  height: 30px;
                  font-size: 18px;
                  font-weight: bolder;
                  padding: 0 5px;
                  line-height: 30px;
                  margin: 10px 0;
                }

                .map {
                  width: 100%;
                  height: 600px;
                }
              }
            }
          }
        }
      }
    }
  }

  ::-webkit-scrollbar {
    width: 8px;
  }

  ::-webkit-scrollbar-thumb {
    background-color: rgb(0 0 0 / 10%);
    border-radius: 10px;
  }
}

::v-deep .input-modal {
  .modal-que {
    background: #0e91fd;

    textarea {
      width: 100%;
      height: 257px !important;
      border: none;
      border-radius: 10px;
      resize: none;
      padding: 10px;
      background: transparent;
      font-size: 19px;

      &:focus-visible {
        border: none !important;
        outline: none;
      }
    }
  }
}
</style>

