Эх сурвалжийг харах

Merge branch 'main' of http://gitlab.smartai.com/qi/xiaoshu

zhupei 1 жил өмнө
parent
commit
29cf3549dd

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 838 - 858
src/components/DialogWrap.vue


+ 78 - 73
src/components/dialog-wrap/DocRefItem.vue

@@ -1,41 +1,42 @@
 <template>
-  <div>
-    <a-popover :title="knowledge.doc_name" position="left">
-        <div @click="openDocuementPage(knowledge)" class="doc-ref-container">
-            <span class="doc-ref-index">{{ knowledgeIndex + 1 }}</span>
-            <span class="doc-ref-label">{{ knowledge.doc_name }}</span>
-        </div>
-        <template #content>
-            <div class="knowledge-detail">
-                <div class="knowledge-content">
-                {{ knowledge.content_ltks }}
-                </div>
-                <div class="knowledge-footer">
-                <p>检索片段</p>
-                <p>
-                    <span v-for="(content, contentIndex) in knowledge.content_ltks" :key="contentIndex"
-                    :class="{ active: knowledge.page === contentIndex }" @click="() => {
-                        knowledge.page = contentIndex;
-                    }
-                        ">{{ contentIndex + 1 }}</span>
-                </p>
-                <!-- TODO详情暂时注释 -->
-                <!-- <p @click="goKnowledge(knowledge.id)">查看详情></p> -->
-                </div>
+    <div>
+        <a-popover :title="knowledge.doc_name" position="left">
+            <div @click="openDocuementPage(knowledge)" class="doc-ref-container">
+                <span class="doc-ref-index">{{ knowledgeIndex + 1 }}</span>
+                <span class="doc-ref-label">{{ knowledge.doc_name }}</span>
             </div>
-        </template>
-    </a-popover>
-</div>
+            <template #content>
+                <div class="knowledge-detail">
+                    <div class="knowledge-content">
+                        {{ knowledge.content_ltks }}
+                    </div>
+                    <div class="knowledge-footer">
+                        <p>检索片段</p>
+                        <p>
+                            <span v-for="(content, contentIndex) in knowledge.content_ltks" :key="contentIndex"
+                                :class="{ active: knowledge.page === contentIndex }" @click="() => {
+                                    knowledge.page = contentIndex;
+                                }
+                                    ">{{ contentIndex + 1 }}</span>
+                        </p>
+                        <!-- TODO详情暂时注释 -->
+                        <p @click="goKnowledge(knowledge)">查看详情></p>
+                    </div>
+                </div>
+            </template>
+        </a-popover>
+    </div>
 </template>
 <script setup>
 import { defineComponent, ref, onBeforeUnmount, onMounted, reactive, nextTick, inject } from "vue";
-
+import { defineEmits } from 'vue'
 import { getDocumentUrl } from '../../ajax/document';
 
 const props = defineProps({
     knowledge: Object,
     knowledgeIndex: Number
 });
+const emit = defineEmits(['go-document']);
 
 const openDocuementPage = (knowledge) => {
     const doc_name = knowledge.doc_name;
@@ -46,67 +47,70 @@ const openDocuementPage = (knowledge) => {
 
     window.open(pdf_url);
 }
+const goKnowledge = (knowledge) => {
+    emit('go-document', knowledge)
+}
 </script>
 <style scoped>
 .knowledge-detail {
-  width: 320px;
-  padding-top: 20px;
-
-  .knowledge-content {
-    height: 300px;
-    overflow-y: auto;
-    line-height: 30px;
-  }
-
-  .knowledge-footer {
-    border-top: 1px solid rgba(229, 229, 229, 1);
-    margin-top: 20px;
+    width: 320px;
     padding-top: 20px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
 
-    p {
-      &:nth-child(1) {
-        opacity: 0.8;
-      }
+    .knowledge-content {
+        height: 300px;
+        overflow-y: auto;
+        line-height: 30px;
+    }
 
-      &:nth-child(2) {
-        flex: 1;
+    .knowledge-footer {
+        border-top: 1px solid rgba(229, 229, 229, 1);
+        margin-top: 20px;
+        padding-top: 20px;
         display: flex;
-        justify-content: left;
-        margin: 0 30px;
-
-        >span {
-          margin: 0 5px;
-          cursor: pointer;
-
-          &:hover,
-          &.active {
-            color: #00aea3;
-          }
-        }
-      }
+        justify-content: space-between;
+        align-items: center;
+
+        p {
+            &:nth-child(1) {
+                opacity: 0.8;
+            }
+
+            &:nth-child(2) {
+                flex: 1;
+                display: flex;
+                justify-content: left;
+                margin: 0 30px;
+
+                >span {
+                    margin: 0 5px;
+                    cursor: pointer;
+
+                    &:hover,
+                    &.active {
+                        color: #00aea3;
+                    }
+                }
+            }
 
-      &:nth-child(3) {
-        font-weight: bold;
-        cursor: pointer;
+            &:nth-child(3) {
+                font-weight: bold;
+                cursor: pointer;
 
-        &:hover {
-          color: #00aea3;
+                &:hover {
+                    color: #00aea3;
+                }
+            }
         }
-      }
     }
-  }
 }
 
-.doc-ref-container{
+.doc-ref-container {
     height: 40px;
     display: inline-flex;
     align-items: center;
 }
 
-.doc-ref-index{
+.doc-ref-index {
     display: inline-block;
     background-color: #00aea333;
     color: #00aea3;
@@ -119,11 +123,12 @@ const openDocuementPage = (knowledge) => {
     cursor: pointer;
 }
 
-.doc-ref-label{
+.doc-ref-label {
     /* margin: 0 5px; */
     cursor: pointer;
 }
-.doc-ref-label:hover{
+
+.doc-ref-label:hover {
     color: #00aea3;
 }
-</style>
+</style>

+ 68 - 32
src/components/pdf-viewer/PDFViewer.vue

@@ -1,23 +1,23 @@
 <template>
-    <div class="pdf-container" ref="box">
-        
+    <div class="pdf-container" id="pdfContainer" ref="box">
+
     </div>
     <div class="loading-pdf-box" v-if="load_status === 2">
         <div class="loading-spin">
-            <a-spin :size="36"/>
+            <a-spin :size="36" />
         </div>
     </div>
 
     <div class="loading-pdf-box" v-if="load_status === 4">
         <a-result status="error" title="文档加载出错">
             <template #subtitle>
-                {{load_msg}}
+                {{ load_msg }}
             </template>
         </a-result>
     </div>
 </template>
 <script setup>
-import { defineComponent, inject, ref, useTemplateRef, watchEffect, onMounted} from "vue";
+import { defineComponent, inject, ref, useTemplateRef, watch, onMounted } from "vue";
 
 import PDFJS from './pdfjs';
 
@@ -55,6 +55,16 @@ const props = defineProps({
 });
 
 const box = useTemplateRef('box');
+/**
+ * 提取pdf中的全局变量
+ *
+ */
+let pdfDocument = null;
+const height_list = []
+let pdfCtxs = [];
+let scale_value = 0
+let drawPages = [] //已经绘制的页码
+
 
 /**
  * 记录PDF文档加载过程中的状态
@@ -71,7 +81,6 @@ const load_msg = ref(''); // 加载消息
  */
 const highlight_pos = (() => {
     const mp = {};
-
     props.positions.forEach((item, index) => {
         const page_index = item[0];
 
@@ -80,14 +89,14 @@ const highlight_pos = (() => {
         const y1 = item[3];
         const y2 = item[4];
 
-        if(page_index in mp){
+        if (page_index in mp) {
             mp[page_index].push({
                 x1,
                 x2,
                 y1,
                 y2
             });
-        }else{
+        } else {
             mp[page_index] = [{
                 x1,
                 x2,
@@ -95,7 +104,7 @@ const highlight_pos = (() => {
                 y2
             }];
         }
- 
+
     });
 
     return mp;
@@ -104,12 +113,12 @@ const highlight_pos = (() => {
 /**
  * 绘制高亮区域
  */
-function drawHighLight(ctx, x1, x2, y1, y2){
+function drawHighLight(ctx, x1, x2, y1, y2) {
     // 设置矩形的样式
     ctx.fillStyle = 'rgba(255, 255, 0, 0.5)';  // 填充颜色
     // ctx.strokeStyle = 'red'; // 边框颜色
     // ctx.lineWidth = 5;       // 边框宽度
-    
+
     const width = x2 - x1;
     const height = y2 - y1;
 
@@ -117,8 +126,8 @@ function drawHighLight(ctx, x1, x2, y1, y2){
     ctx.fillRect(x1, y1, width, height); // 参数依次为:x坐标, y坐标, 宽度, 高度
 }
 
-function getPageHeight(viewWidth, viewHeight){
-    const height = props.doc_width/ (viewWidth/viewHeight);
+function getPageHeight(viewWidth, viewHeight) {
+    const height = props.doc_width / (viewWidth / viewHeight);
 
     return height;
 }
@@ -128,37 +137,36 @@ onMounted(() => {
     load_msg.value = 'loading';
 
     PDFJS.getDocument(props.url).promise.then(async pdfDoc => {
+        pdfDocument = pdfDoc;
         const page_total = pdfDoc.numPages;
 
         let min_page = -1;
         let height_total = 0;
+        height_list.length = 0;
+        pdfCtxs.length = 0;
 
-        const height_list = [];
-
-        for(let i = 1; i <= page_total; i++){
+        for (let i = 1; i <= page_total; i++) {
             const canvas = document.createElement('canvas');
             // 设置事件监听器来阻止默认的右键菜单
-            canvas.addEventListener('contextmenu', function(e) {
+            canvas.addEventListener('contextmenu', function (e) {
                 e.preventDefault();
             });
-
-            const pdfCtx = canvas.getContext('2d')
+            pdfCtxs[i] = canvas.getContext('2d')
 
             const page = await pdfDoc.getPage(i);
 
             // 获取原始页面的大小
             const viewport1 = page.getViewport({ scale: 1 })
-
             // 原始宽度和高度
             const cur_width = viewport1.width;
             const cur_height = viewport1.height;
 
             // 目标宽度和高度
             const target_width = props.doc_width;
-            const target_height = target_width/(cur_width/cur_height);
+            const target_height = target_width / (cur_width / cur_height);
 
             // 获取到缩放比例
-            const scale_value = target_width/cur_width;
+            scale_value = target_width / cur_width;
 
             // 根据缩放比例,重新获取viewport值
             const viewport2 = page.getViewport({ scale: scale_value });
@@ -170,23 +178,22 @@ onMounted(() => {
             canvas.height = target_height; // viewport.height
 
             height_total = height_total + canvas.height;
-                        
             await page.render({
                 viewport: viewport2,
-                canvasContext: pdfCtx,
+                canvasContext: pdfCtxs[i],
             })
-            .promise;
+                .promise;
 
-            if(i in highlight_pos){
+            if (i in highlight_pos) {
                 const pos_info = highlight_pos[i];
 
                 // 记录第一个要跳转的页码
-                if(min_page === -1){
+                if (min_page === -1) {
                     min_page = i;
                 }
 
                 pos_info.forEach((psinfo) => {
-                    drawHighLight(pdfCtx, psinfo.x1 * scale_value, psinfo.x2 * scale_value, psinfo.y1 * scale_value, psinfo.y2 * scale_value);
+                    drawHighLight(pdfCtxs[i], psinfo.x1 * scale_value, psinfo.x2 * scale_value, psinfo.y1 * scale_value, psinfo.y2 * scale_value);
                 });
             }
 
@@ -199,7 +206,7 @@ onMounted(() => {
 
 
         // TODO: 优化跳转效果:平滑跳转
-        if(min_page !== -1){
+        if (min_page !== -1) {
             setTimeout(() => {
                 box.value.scrollTop = height_list[min_page - 1]
             });
@@ -212,16 +219,45 @@ onMounted(() => {
         load_msg.value = `PDF文档 ${props.url} 加载出错。 ERROR: :${err.message}`;
     });
 })
+const toPageIndex = async (pageNumber, positions) => {
+    if (!pdfDocument) {
+        return
+    }
+    setTimeout(() => {
+        box.value.scrollTop = height_list[pageNumber - 1]
+    });
+    if (!drawPages.includes(pageNumber)) {
+        positions.forEach(position => {
+            const [_, x1, x2, y1, y2] = position;
+            drawHighLightArea(pdfCtxs[pageNumber], x1 * scale_value, x2 * scale_value, y1 * scale_value, y2 * scale_value)
+            drawPages.push(pageNumber)
+        });
+    }
+
 
+}
+
+const drawHighLightArea = (pdfCtx, x1, x2, y1, y2) => {
+    // 设置高亮的样式,比如颜色、透明度、线宽等
+    pdfCtx.fillStyle = "rgba(255, 255, 0, 0.5)"; // 黄色半透明
+    // 绘制高亮矩形
+    pdfCtx.beginPath();
+    pdfCtx.rect(x1, y1, x2 - x1, y2 - y1);
+    pdfCtx.fill(); // 填充矩形
+};
+
+defineExpose({
+    toPageIndex
+})
 </script>
 <style scoped>
-.pdf-container{
+.pdf-container {
     text-align: center;
     height: 100vh;
     overflow-y: auto;
 }
 
-.loading-pdf-box{
+.loading-pdf-box {
     width: 100%;
     height: 100vh;
     display: flex;
@@ -234,7 +270,7 @@ onMounted(() => {
     background-color: #fff;
 }
 
-.loading-spin{
+.loading-spin {
     width: 40px;
     height: 40px;
 }

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 14 - 14
src/views/DocumentDetail.vue


+ 628 - 627
src/views/Home.vue

@@ -1,6 +1,6 @@
 <template>
-  <div id="app">
-    <Slider @select-nav="selectNav" :navId="navId" v-show="!closeOthers"></Slider>
+    <div id="app">
+        <Slider @select-nav="selectNav" :navId="navId" v-show="!closeOthers"></Slider>
 
     <div class="main">
       <div :class="{ 'history-wrap': true, 'history-wrap-open': !closeOthers && navId > -1 }">
@@ -12,135 +12,143 @@
         />
       </div>
 
-      <div class="wrap">
-        <Index v-if="navId === -1" :number="swiperNumber" @select-nav="selectNav" />
-
-        <div :class="{ 'border-wrap': true, 'border-no-wrap': navId === -2 }" v-else>
-          <div>
-            <!-- 项目与功能特色介绍 -->
-            <ProjectIntro v-if="!showDialog" :navId="navId" />
-
-            <section :class="{ 'section-padding': showDialog }">
-              <!-- 报告生成 -->
-              <DocumentCombine v-if="navId == 0 && !showDialog" />
-              <!-- 报表合并 -->
-              <Document v-if="navId === 1 && !showDialog" />
-              <!-- 知识问答 -->
-              <DocumentInterlocution v-if="navId === 2 && !showDialog" />
-              <!-- 文档智能 -->
-              <DocumentAnswer v-if="navId === 3 && !showDialog" :agentId="selectId" />
-              <!-- 智能问答 -->
-              <Answer v-if="navId === 4 && !showDialog" />
-              <!-- 智能数据 -->
-              <DocumentsmartData v-if="navId === 5 && !showDialog" :agentId="selectId" />
-              <!-- 小数绘图 -->
-              <PicArticle v-if="navId === 6 && !showDialog" :agentId="selectId" />
-              <!-- 文档出卷 -->
-              <DocumentQuestion v-if="navId === 7 && !showDialog" :agentId="selectId" />
+            <div class="wrap">
+                <Index v-if="navId === -1" :number="swiperNumber" @select-nav="selectNav" />
+
+                <div :class="{ 'border-wrap': true, 'border-no-wrap': navId === -2 }" v-else>
+                    <div>
+                        <!-- 项目与功能特色介绍 -->
+                        <ProjectIntro v-if="!showDialog" :navId="navId" />
+
+                        <section :class="{ 'section-padding': showDialog }">
+                            <!-- 报告生成 -->
+                            <DocumentCombine v-if="navId == 0 && !showDialog" />
+                            <!-- 报表合并 -->
+                            <Document v-if="navId === 1 && !showDialog" />
+                            <!-- 知识问答 -->
+                            <DocumentInterlocution v-if="navId === 2 && !showDialog" />
+                            <!-- 文档智能 -->
+                            <DocumentAnswer v-if="navId === 3 && !showDialog" :agentId="selectId" />
+                            <!-- 智能问答 -->
+                            <Answer v-if="navId === 4 && !showDialog" />
+                            <!-- 智能数据 -->
+                            <DocumentsmartData v-if="navId === 5 && !showDialog" :agentId="selectId" />
+                            <!-- 小数绘图 -->
+                            <PicArticle v-if="navId === 6 && !showDialog" :agentId="selectId" />
+                            <!-- 文档出卷 -->
+                            <DocumentQuestion v-if="navId === 7 && !showDialog" :agentId="selectId" />
 
               <!-- 出题组卷 -->
               <DocumentQuestion2 v-if="navId === 8 && !showDialog" :agentId="selectId" />
 
-              <!-- 文库详情 -->
-              <DocumentDetail v-if="navId === -2" @go-back="goBack" />
-
-              <dialog-wrap
-                v-if="showDialog && initDialog"
-                v-show="!hideDialog"
-                :type="dialogType[navId]"
-                :isSetting="false"
-                :readonly="readonly"
-                :agentId="selectId"
-                :dialogId="dialogId"
-                :list="dialogList"
-                @setReadonly="setReadonly"
-                @changeParse="changeParse"
-                @goDocument="goDocument"
-              />
-            </section>
-
-            <footer v-if="navId !== -2 && navId !== 0 && navId !== 3 && navId !== 6 && navId !== 1 && !historyMode">
-              <BtnIframeChujuan v-if="navId==7"/>
-              <message-input :readonly="readonly" eventName="open-dialog" />
-            </footer>
-
-            <footer v-if="navId === 0 && !showDialog" class="upload-footer">
-              <section v-for="(item, key) in variables" :key="key">
-                <div>
-                  <p>
-                    <span>{{ item.variable_name }}</span>
-                  </p>
+                            <!-- 文库详情 -->
+                            <DocumentDetail v-if="navId === -2" :targetDocument="targetDocument" :dialogList="dialogList"
+                                @go-back="goBack" />
+
+                            <dialog-wrap v-if="showDialog && initDialog" v-show="!hideDialog" :type="dialogType[navId]"
+                                :isSetting="false" :readonly="readonly" :agentId="selectId" :dialogId="dialogId"
+                                :list="dialogList" @setReadonly="setReadonly" @changeParse="changeParse"
+                                @goDocument="goDocument" />
+                        </section>
+
+                        <footer
+                            v-if="navId !== -2 && navId !== 0 && navId !== 3 && navId !== 6 && navId !== 1 && !historyMode">
+                            <BtnIframeChujuan v-if="navId == 7" />
+                            <message-input :readonly="readonly" eventName="open-dialog" />
+                        </footer>
+
+                        <footer v-if="navId === 0 && !showDialog" class="upload-footer">
+                            <section v-for="(item, key) in variables" :key="key">
+                                <div>
+                                    <p>
+                                        <span>{{ item.variable_name }}</span>
+                                    </p>
+                                </div>
+
+                                <div>
+                                    <a-input :style="{ flex: '1' }" :placeholder="`请输入${item.variable_name}`" allow-clear
+                                        @change="(event) => {
+                                            customChange(event, item.node_id, item.variable_name);
+                                        }
+                                            " v-if="item.value_type === 1" />
+                                    <a-upload v-else :style="{ width: '300px' }" :multiple="false" :limit="1"
+                                        :custom-request="(option) => {
+                                            customRequest(option, item.node_id, item.variable_name);
+                                        }
+                                            " :show-upload-button="{ showOnExceedLimit: true }"
+                                        accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx" />
+                                </div>
+                            </section>
+
+                            <a-textarea :max-length="maxLength" v-model="textValue"
+                                :show-word-limit="textValue.length > maxLength / 2" :auto-size="{ maxRows: 6 }"
+                                placeholder="输入您想了解的内容,Shift+Enter换行" :style="{
+                                    flex: 1,
+                                    borderRadius: '12px',
+                                    marginTop: '20px',
+                                    padding: '0px 30px 0 16px',
+                                    background: 'transparent',
+                                    border: '1px solid #e3e3e3',
+                                    minHeight: '120px',
+                                    paddingBottom: `${textValue.length > maxLength / 2 ? '20px' : ''}`
+                                }">
+                            </a-textarea>
+
+                            <a-button :style="{ width: '500px' }" type="primary" @click="beginCombine">开始</a-button>
+                        </footer>
+
+                        <footer v-if="navId === 3 && !showDialog" class="upload-footer">
+                            <section v-for="(item, key) in variables" :key="key">
+                                <div>
+                                    <p>
+                                        <span>{{ item.variable_name }}</span>
+                                    </p>
+                                </div>
+                                <div>
+                                    <a-input :style="{ flex: '1' }" :placeholder="`请输入${item.variable_name}`" allow-clear
+                                        @change="(event) => {
+                                            customChange(event, item.node_id, item.variable_name);
+                                        }
+                                            " v-if="item.value_type === 1" />
+                                    <a-upload v-else :style="{ width: '300px' }" :multiple="false" :limit="1"
+                                        :custom-request="(option) => {
+                                            customRequest(option, item.node_id, item.variable_name);
+                                        }
+                                            " :show-upload-button="{ showOnExceedLimit: true }"
+                                        accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx" />
+                                </div>
+                            </section>
+                            <a-button :style="{ width: '500px' }" type="primary" @click="beginCombine">开始</a-button>
+                        </footer>
+
+                        <footer v-if="navId === 3 && showDialog && !historyMode" class="upload-footer">
+                            <a-textarea :max-length="maxLength" v-model="textValue" :disabled="parseStatus"
+                                :show-word-limit="textValue.length > maxLength / 2" :auto-size="{ maxRows: 6 }"
+                                placeholder="输入您想了解的内容,Shift+Enter换行" :style="{
+                                    flex: 1,
+                                    borderRadius: '12px',
+                                    marginTop: '20px',
+                                    padding: '0px 30px 0 16px',
+                                    background: 'transparent',
+                                    border: '1px solid #e3e3e3',
+                                    minHeight: '120px',
+                                    paddingBottom: `${textValue.length > maxLength / 2 ? '20px' : ''}`
+                                }">
+                            </a-textarea>
+                            <a-button :style="{ width: '500px' }" type="primary" @click="continueCombine">开始</a-button>
+                        </footer>
+
+                        <!-- 小数绘图底部输入栏 -->
+                        <PictureFooter v-if="navId === 6 && !historyMode" :agentId="selectId" />
+
+                        <!-- 侧边栏切换按钮 -->
+                        <ToggleBtn v-if="navId !== -2" :closeOthers="closeOthers" @toggle="openAll" />
+                    </div>
                 </div>
-
-                <div>
-                  <a-input :style="{ flex: '1' }" :placeholder="`请输入${item.variable_name}`" allow-clear @change="(event) => {
-                    customChange(event, item.node_id, item.variable_name);
-                  }
-                    " v-if="item.value_type === 1" />
-                  <a-upload v-else :style="{ width: '300px' }" :multiple="false" :limit="1" :custom-request="(option) => {
-                    customRequest(option, item.node_id, item.variable_name);
-                  }
-                    " :show-upload-button="{ showOnExceedLimit: true }" accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx" />
-                </div>
-              </section>
-
-              <a-textarea :max-length="maxLength" v-model="textValue"
-                :show-word-limit="textValue.length > maxLength / 2" :auto-size="{ maxRows: 6 }"
-                placeholder="输入您想了解的内容,Shift+Enter换行" :style="text_area_style">
-              </a-textarea>
-
-              <a-button :style="{ width: '500px' }" type="primary" @click="beginCombine">开始</a-button>
-            </footer>
-
-            <footer v-if="navId === 3 && !showDialog" class="upload-footer">
-              <section v-for="(item, key) in variables" :key="key">
-                <div>
-                  <p>
-                    <span>{{ item.variable_name }}</span>
-                  </p>
-                </div>
-                <div>
-                  <a-input :style="{ flex: '1' }" :placeholder="`请输入${item.variable_name}`" allow-clear @change="(event) => {
-                    customChange(event, item.node_id, item.variable_name);
-                  }
-                    " v-if="item.value_type === 1" />
-                  <a-upload v-else :style="{ width: '300px' }" :multiple="false" :limit="1" :custom-request="(option) => {
-                    customRequest(option, item.node_id, item.variable_name);
-                  }
-                    " :show-upload-button="{ showOnExceedLimit: true }" accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx" />
-                </div>
-              </section>
-              <a-button :style="{ width: '500px' }" type="primary" @click="beginCombine">开始</a-button>
-            </footer>
-
-            <footer v-if="navId === 3 && showDialog && !historyMode" class="upload-footer">
-              <a-textarea :max-length="maxLength" v-model="textValue" :disabled="parseStatus"
-                :show-word-limit="textValue.length > maxLength / 2" :auto-size="{ maxRows: 6 }"
-                placeholder="输入您想了解的内容,Shift+Enter换行" :style="{
-                  flex: 1,
-                  borderRadius: '12px',
-                  marginTop: '20px',
-                  padding: '0px 30px 0 16px',
-                  background: 'transparent',
-                  border: '1px solid #e3e3e3',
-                  minHeight: '120px',
-                  paddingBottom: `${textValue.length > maxLength / 2 ? '20px' : ''}`
-                }">
-              </a-textarea>
-              <a-button :style="{ width: '500px' }" type="primary" @click="continueCombine">开始</a-button>
-            </footer>
-
-            <!-- 小数绘图底部输入栏 -->
-            <PictureFooter v-if="navId === 6 && !historyMode" :agentId="selectId"/>
-
-            <!-- 侧边栏切换按钮 -->
-            <ToggleBtn v-if="navId !== -2" :closeOthers="closeOthers" @toggle="openAll"/>
-          </div>
+            </div>
+            <!-- <right v-if="navId === 0 || navId === 2" /> -->
         </div>
-      </div>
-      <!-- <right v-if="navId === 0 || navId === 2" /> -->
     </div>
-  </div>
 </template>
 <script>
 import Right from "../components/Right.vue";
@@ -170,547 +178,540 @@ import BtnIframeChujuan from '../components/btn-iframe-chujuan/BtnIframeChujuan.
 import { defineComponent, ref, onMounted, inject, onBeforeUnmount } from "vue";
 
 export default defineComponent({
-  components: {
-    Right,
-    Slider,
-    ProjectIntro,
-    History,
-    Index,
-    Answer,
-    MessageInput,
-
-    PictureFooter,
-
-    DialogWrap,
-    Document,
-    PicArticle,
-    DocumentAnswer,
-    DocumentsmartData,
-    DocumentInterlocution,
-    DocumentQuestion,
-    DocumentQuestion2,
-    Analysis,
-    DocumentDetail,
-    DocumentCombine,
-
-    ToggleBtn,
-    BtnIframeChujuan // 文档出卷按钮
-  },
-  setup() {
-    // NOTE: 先把4文库问答的类型改成report类型,后续再改回来
-    const dialogType = [
-      "report",
-      "excel",
-      "knowledgeQuiz",
-      "report",
-      "normal",
-      "smartData",
-      "huitu",  // 小数绘图
-      "question",
-      "question"
-    ];
-
-    const { config, helper, ajax } = inject("$global");
-
-    const SYSTEM_NAME = config.defaultTitle
-
-    const closeOthers = ref(false);
-    const swiperNumber = ref(5);
-    const navId = ref(-1);
-
-    const readonly = ref(false);
-
-    const showDialog = ref(false); // 是否显示对话内容 v-if
-    const initDialog = ref(false); // 对话是否初始化
-    const hideDialog = ref(false); // 是否隐藏对话 v-show
-
-    const historyMode = ref(false);
-    const dialogList = ref([]);
-
-    const selectId = ref(""); // 当前选择的 agent_id 或者 历史记录的 ID
-    const real_agent_id = ref(""); // 实际的agent_id,此值仅在 点击侧边栏具体功能时更改,例如点击 知识问答、文档智能按钮时更改
-    const agentIds = ref([]); // agent ID的列表
-
-    const dialogId = ref("");
-    const historyList = ref([]);
-    const variables = ref([]);
-    const textValue = ref("");
-    const parseStatus = ref(false);
-    const maxLength = ref(6000); // 允许输入的最大长度
-
-    let reportData = {};
-    let agents = {}
-
-    const openAll = () => {
-      closeOthers.value = !closeOthers.value;
-    };
-
-    const setReadonly = (status) => {
-      readonly.value = status;
-    };
-    const changeParse = (status) => {
-      parseStatus.value = status;
-    }
-    const goDocument = () => {
-      navId.value = -2;
-      hideDialog.value = true;
-    };
-    const goBack = () => {
-      navId.value = 0;
-      hideDialog.value = false;
-    };
-
-    /**
-     * 当点击某个导航时触发的方法
-     * 例如:点击 知识问答 文档智能 智能问答 智能数据 等
-     * @params {object} node
-     * @params {number} node.id - 例如 3 4 5
-     * @params {string} node.title - 例如:文档智能 小数绘图
-     */
-    const selectNav = async (node) => {
-      navId.value = node.id;
-      textValue.value = [];
-      // 关闭历史模式
-      historyMode.value = false;
-      readonly.value = false;
-
-      if (node.index === -1) {
-        swiperNumber.value = 5;
-      } else {
-        swiperNumber.value = 4;
-      }
-
-      helper.$bus.emit("stop-writing");
-      showDialog.value = false;
-
-      // 获取当前选定的agent对应的ID
-      selectId.value = (agents.find(agent => agent.name === node.title) || {}).id || null;
-      real_agent_id.value = selectId.value; // 记录agent_id值
-
-      // 获取历史记录
-      const data = await ajax.message.getDialogs(selectId.value);
-
-      if (navId.value === 0 || navId.value === 3) {
-        const result = await ajax.agent.getVariables(selectId.value);
-        variables.value = result;
-        reportData = {};
-      }
-
-      if (data && Array.isArray(data)) {
-        historyList.value = data.map((value) => {
-          return {
-            content: value.name,
-            id: value.id,
-            time: value.update_date
-          };
-        });
-      }
-
-      // 每次切换功能板块时,清空sendData数据
-      // helper.write('sendData', {});
-      clearLocalStorageSendData();
-    };
-
-    /**
-     * 选择某个历史记录
-     * @params {string} id - 历史记录对应的ID
-     */
-    const selectHistory = async (id) => {
-      showDialog.value = true;
-      // 历史记录对话模式,不调用对话ID接口
-      historyMode.value = true;
-      readonly.value = true;
-
-      selectId.value = id;
-      helper.$bus.emit("set-loading", true);
-      helper.$bus.emit("stop-writing");
-      initDialog.value = false;
-
-      // 历史记录 通过当前name取id
-      const name = config.slider.find(item => item.id === navId.value).title
-      const agentsId = agents.find(agent => agent.name === name).id;
-      const data = await ajax.message.getHistoryLogs(agentsId, id);
-
-      if (data && Array.isArray(data) && data.length > 0) {
-        dialogList.value = data
-      } else {
-        dialogList.value = []
-      }
-
-      initDialog.value = true;
-      helper.$bus.emit("set-loading", false);
-    };
-
-    const beginCombine = async () => {
-      let report_name = "";
-      let inputData = [];
-      for (let key in reportData) {
+    components: {
+        Right,
+        Slider,
+        ProjectIntro,
+        History,
+        Index,
+        Answer,
+        MessageInput,
+
+        PictureFooter,
+
+        DialogWrap,
+        Document,
+        PicArticle,
+        DocumentAnswer,
+        DocumentsmartData,
+        DocumentInterlocution,
+        DocumentQuestion,
+        DocumentQuestion2,
+        Analysis,
+        DocumentDetail,
+        DocumentCombine,
+
+        ToggleBtn,
+        BtnIframeChujuan, // 文档出卷按钮
+    },
+    setup() {
+        // NOTE: 先把4文库问答的类型改成report类型,后续再改回来
+        const dialogType = [
+            "report",
+            "excel",
+            "knowledgeQuiz",
+            "report",
+            "normal",
+            "smartData",
+            "huitu",  // 小数绘图
+            "question",
+            "question"
+        ];
+
+        const { config, helper, ajax } = inject("$global");
+
+        const SYSTEM_NAME = config.defaultTitle
+
+        const closeOthers = ref(false);
+        const swiperNumber = ref(5);
+        const navId = ref(-1);
+
+        const readonly = ref(false);
+
+        const showDialog = ref(false); // 是否显示对话内容 v-if
+        const initDialog = ref(false); // 对话是否初始化
+        const hideDialog = ref(false); // 是否隐藏对话 v-show
+
+        const historyMode = ref(false);
+        const dialogList = ref([]);
+
+        const selectId = ref(""); // 当前选择的 agent_id 或者 历史记录的 ID
+        const real_agent_id = ref(""); // 实际的agent_id,此值仅在 点击侧边栏具体功能时更改,例如点击 知识问答、文档智能按钮时更改
+        const agentIds = ref([]); // agent ID的列表
+
+        const dialogId = ref("");
+        const historyList = ref([]);
+        const variables = ref([]);
+        const textValue = ref("");
+        const parseStatus = ref(false);
+        const maxLength = ref(6000); // 允许输入的最大长度
+        const targetDocument = ref(null); // 当前查看详情的文档
+        const transNavId = ref() //查看详情时记录之前的navId
+
+        let reportData = {};
+        let agents = {}
+
+        const openAll = () => {
+            closeOthers.value = !closeOthers.value;
+        };
+
+        const setReadonly = (status) => {
+            readonly.value = status;
+        };
+        const changeParse = (status) => {
+            parseStatus.value = status;
+        }
+        const goDocument = (knowledge) => {
+            transNavId.value = navId.value
+            navId.value = -2;
+            hideDialog.value = true;
+            const filterList = dialogList.value.filter(item => (item.reference && item.reference.doc_aggs))
+            const targetDocumentItem = filterList.find(item => item.reference.doc_aggs.some(doc => doc.doc_id === knowledge.id))
+            if (targetDocumentItem) {
+                targetDocument.value = { ...knowledge, ...targetDocumentItem }
+
+            } else {
+                targetDocument.value = { ...knowledge }
+            }
+        };
+        const goBack = () => {
+            navId.value = transNavId.value;
+            hideDialog.value = false;
+        };
+
         /**
-         * 此部分代码于 2024/11/25日上午做了简单优化
-         * 优化时,仅调整了循环体内的代码
-         * 由于此功能暂时禁用,无法测试优化后的效果是否正常
-         * 如果后续测试时发现代码异常,可copy此时间之前的原代码
+         * 当点击某个导航时触发的方法
+         * 例如:点击 知识问答 文档智能 智能问答 智能数据 等
+         * @params {object} node
+         * @params {number} node.id - 例如 3 4 5
+         * @params {string} node.title - 例如:文档智能 小数绘图
          */
-        const cur_report = reportData[key];
-        const report_key = cur_report.key;
-        const report_value = cur_report.value;
+        const selectNav = async (node) => {
+            navId.value = node.id;
+            textValue.value = [];
+            // 关闭历史模式
+            historyMode.value = false;
+            readonly.value = false;
+
+            if (node.index === -1) {
+                swiperNumber.value = 5;
+            } else {
+                swiperNumber.value = 4;
+            }
+
+            helper.$bus.emit("stop-writing");
+            showDialog.value = false;
+
+            // 获取当前选定的agent对应的ID
+            selectId.value = (agents.find(agent => agent.name === node.title) || {}).id || null;
+            real_agent_id.value = selectId.value; // 记录agent_id值
+
+            // 获取历史记录
+            const data = await ajax.message.getDialogs(selectId.value);
+
+            if (navId.value === 0 || navId.value === 3) {
+                const result = await ajax.agent.getVariables(selectId.value);
+                variables.value = result;
+                reportData = {};
+            }
+
+            if (data && Array.isArray(data)) {
+                historyList.value = data.map((value) => {
+                    return {
+                        content: value.name,
+                        id: value.id,
+                        time: value.update_date
+                    };
+                });
+            }
+
+            // 每次切换功能板块时,清空sendData数据
+            // helper.write('sendData', {});
+            clearLocalStorageSendData();
+        };
 
-        const item = {
-          id: key,
-          name: report_key,
+        /**
+         * 选择某个历史记录
+         * @params {string} id - 历史记录对应的ID
+         */
+        const selectHistory = async (id) => {
+            showDialog.value = true;
+            // 历史记录对话模式,不调用对话ID接口
+            historyMode.value = true;
+            readonly.value = true;
+
+            selectId.value = id;
+            helper.$bus.emit("set-loading", true);
+            helper.$bus.emit("stop-writing");
+            initDialog.value = false;
+
+            // 历史记录 通过当前name取id
+            const name = config.slider.find(item => item.id === navId.value).title
+            const agentsId = agents.find(agent => agent.name === name).id;
+            const data = await ajax.message.getHistoryLogs(agentsId, id);
+
+            if (data && Array.isArray(data) && data.length > 0) {
+                dialogList.value = data
+            } else {
+                dialogList.value = []
+            }
+
+            initDialog.value = true;
+            helper.$bus.emit("set-loading", false);
         };
 
-        if (typeof report_value === "string") {
-          report_name += `${report_key}:${report_value}\n`;
+        const beginCombine = async () => {
+            let report_name = "";
+            let inputData = [];
+            for (let key in reportData) {
+                /**
+                 * 此部分代码于 2024/11/25日上午做了简单优化
+                 * 优化时,仅调整了循环体内的代码
+                 * 由于此功能暂时禁用,无法测试优化后的效果是否正常
+                 * 如果后续测试时发现代码异常,可copy此时间之前的原代码
+                 */
+                const cur_report = reportData[key];
+                const report_key = cur_report.key;
+                const report_value = cur_report.value;
+
+                const item = {
+                    id: key,
+                    name: report_key,
+                };
+
+                if (typeof report_value === "string") {
+                    report_name += `${report_key}:${report_value}\n`;
+
+                    item.file_path = '';
+                    item.value = report_value;
+                } else {
+                    report_name += `${report_key}:${report_value.name}\n`;
+
+                    item.file_path = report_value.url;
+                    item.value = '';
+                }
+
+                inputData.push(item);
+            }
+
+            // 如果不是历史记录对话模式,则创建对话
+            if (!historyMode.value) {
+                const data = await ajax.message.createDialog(selectId.value);
+
+                if (data) {
+                    dialogId.value = data.chat_id;
+                }
+            }
+
+            dialogList.value = [];
+            showDialog.value = true;
+            initDialog.value = true;
+
+            const sendData = {
+                chatHistory: [],
+                message: textValue.value,
+                name: "报告生成",
+                description: "报告生成",
+                inputs: {
+                    report_name,
+                    id: "Report-PRcYL",
+                    data: inputData
+                }
+            };
+
+            setTimeout(() => {
+                helper.$bus.emit("send-message", sendData);
+            }, 500);
+        };
 
-          item.file_path = '';
-          item.value = report_value;
-        } else {
-          report_name += `${report_key}:${report_value.name}\n`;
+        const continueCombine = async () => {
+            const sendData = {
+                chatHistory: [],
+                name: "报告生成",
+                description: "报告生成",
+                inputs: {
+                    report_name: textValue.value,
+                    id: "Report-PRcYL",
+                    query: textValue.value,
+                }
+            };
+
+            setTimeout(() => {
+                helper.$bus.emit("send-message", sendData);
+                textValue.value = "";
+            }, 500);
+        };
 
-          item.file_path = report_value.url;
-          item.value = '';
-        }
+        const customChange = (event, key, value) => {
+            reportData[key] = {
+                key: value,
+                value: event
+            };
+        };
 
-        inputData.push(item);
-      }
+        const customRequest = async (option, key, value) => {
+            const { onSuccess, fileItem } = option;
+            const { file, uid, name } = fileItem;
+            const fileList = [];
 
-      // 如果不是历史记录对话模式,则创建对话
-      if (!historyMode.value) {
-        const data = await ajax.message.createDialog(selectId.value);
+            fileList.push({
+                id: uid,
+                file
+            });
 
-        if (data) {
-          dialogId.value = data.chat_id;
-        }
-      }
-
-      dialogList.value = [];
-      showDialog.value = true;
-      initDialog.value = true;
-
-      const sendData = {
-        chatHistory: [],
-        message: textValue.value,
-        name: "报告生成",
-        description: "报告生成",
-        inputs: {
-          report_name,
-          id: "Report-PRcYL",
-          data: inputData
-        }
-      };
-
-      setTimeout(() => {
-        helper.$bus.emit("send-message", sendData);
-      }, 500);
-    };
-
-    const continueCombine = async () => {
-      const sendData = {
-        chatHistory: [],
-        name: "报告生成",
-        description: "报告生成",
-        inputs: {
-          report_name: textValue.value,
-          id: "Report-PRcYL",
-          query: textValue.value,
-        }
-      };
-
-      setTimeout(() => {
-        helper.$bus.emit("send-message", sendData);
-        textValue.value = "";
-      }, 500);
-    };
-
-    const customChange = (event, key, value) => {
-      reportData[key] = {
-        key: value,
-        value: event
-      };
-    };
-
-    const customRequest = async (option, key, value) => {
-      const { onSuccess, fileItem } = option;
-      const { file, uid, name } = fileItem;
-      const fileList = [];
-
-      fileList.push({
-        id: uid,
-        file
-      });
-
-      onSuccess();
-      const formData = new FormData();
-
-      fileList.forEach((item) => {
-        formData.append("file", item.file);
-      });
-
-      const data = await ajax.file.uploadFiles(selectId.value, formData);
-
-      reportData[key] = {
-        key: value,
-        value: {
-          name,
-          url: data.file_path
-        }
-      };
-    };
-
-    onMounted(async () => {
-      agents = await ajax.agent.getAgents();
-      agentIds.value = agents && Array.isArray(agents) && agents.map((data) => data.id) || [];
-
-      helper.$bus.on("open-dialog", async (value) => {
-        // 如果不是历史记录对话模式,则创建对话
-        if (!historyMode.value) {
-          const data = await ajax.message.createDialog(selectId.value);
-          dialogId.value = data.chat_id;
-        }
+            onSuccess();
+            const formData = new FormData();
 
-        dialogList.value = [];
-        showDialog.value = true;
-        initDialog.value = true;
+            fileList.forEach((item) => {
+                formData.append("file", item.file);
+            });
 
-        // TODO
-        setTimeout(() => {
-          helper.$bus.emit("send-message", value);
-        }, 200);
-      });
-    });
+            const data = await ajax.file.uploadFiles(selectId.value, formData);
 
-    onBeforeUnmount(() => {
-      helper.$bus.off("open-dialog");
-    });
+            reportData[key] = {
+                key: value,
+                value: {
+                    name,
+                    url: data.file_path
+                }
+            };
+        };
 
-    /**
-     * 点击新建对话按钮
-     */
-    const handelSetNewChat = () => {
-      selectId.value = real_agent_id.value;
+        onMounted(async () => {
+            agents = await ajax.agent.getAgents();
+            agentIds.value = agents && Array.isArray(agents) && agents.map((data) => data.id) || [];
+
+            helper.$bus.on("open-dialog", async (value) => {
+                // 如果不是历史记录对话模式,则创建对话
+                if (!historyMode.value) {
+                    const data = await ajax.message.createDialog(selectId.value);
+                    dialogId.value = data.chat_id;
+                }
+
+                dialogList.value = [];
+                showDialog.value = true;
+                initDialog.value = true;
+
+                // TODO
+                setTimeout(() => {
+                    helper.$bus.emit("send-message", value);
+                }, 200);
+            });
+        });
 
-      showDialog.value = false;
+        onBeforeUnmount(() => {
+            helper.$bus.off("open-dialog");
+        });
 
-      historyMode.value = false;
-      setReadonly(false);
+        /**
+         * 点击新建对话按钮
+         */
+        const handelSetNewChat = () => {
+            selectId.value = real_agent_id.value;
 
-      // 每次新建对话时,清空sendData数据
-      clearLocalStorageSendData();
-    };
+            showDialog.value = false;
 
-    function clearLocalStorageSendData(){
-      // helper.write('sendData', {});
-    }
+            historyMode.value = false;
+            setReadonly(false);
 
-    const text_area_style = {
-        flex: 1,
-        borderRadius: '12px',
-        marginTop: '20px',
-        padding: '0px 30px 0 16px',
-        background: 'transparent',
-        border: '1px solid #e3e3e3',
-        minHeight: '120px',
-        paddingBottom: `${textValue.value.length > maxLength.value / 2 ? '20px' : ''}`
-    }
+            // 每次新建对话时,清空sendData数据
+            clearLocalStorageSendData();
+        };
+
+        function clearLocalStorageSendData() {
+            // helper.write('sendData', {});
+        }
 
-    // const handleInputChange = (item) => {
-    //     const fn = (event) => {
-    //         customChange(event, item.node_id, item.variable_name);
-    //     }
-    // }
-
-    return {
-      SYSTEM_NAME,
-      customChange,
-      customRequest,
-      historyList,
-      beginCombine,
-      continueCombine,
-      selectId,
-      dialogId,
-      navId,
-      variables,
-      selectNav,
-      swiperNumber,
-      slider: config.slider,
-      readonly,
-      setReadonly,
-      showDialog,
-      selectHistory,
-      historyMode,
-      closeOthers,
-      openAll,
-      dialogType,
-      dialogList,
-      initDialog,
-      goDocument,
-      goBack,
-      changeParse,
-      hideDialog,
-      agentIds,
-      textValue,
-      parseStatus,
-      maxLength,
-
-        handelSetNewChat,
-
-        text_area_style
-    };
-  }
+        return {
+            SYSTEM_NAME,
+            customChange,
+            customRequest,
+            historyList,
+            beginCombine,
+            continueCombine,
+            selectId,
+            dialogId,
+            navId,
+            variables,
+            selectNav,
+            swiperNumber,
+            slider: config.slider,
+            readonly,
+            setReadonly,
+            showDialog,
+            selectHistory,
+            historyMode,
+            closeOthers,
+            openAll,
+            dialogType,
+            dialogList,
+            initDialog,
+            goDocument,
+            goBack,
+            changeParse,
+            hideDialog,
+            agentIds,
+            textValue,
+            parseStatus,
+            maxLength,
+
+            handelSetNewChat,
+            targetDocument
+        };
+    }
 });
 </script>
 <style lang="scss" scoped>
 .main {
-  .upload-footer {
-    margin-bottom: 50px;
-    padding: 20px;
-    width: 540px;
-    border: 1px solid #eee;
-
-    >section {
-      >div {
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        width: 500px;
-
-        >p {
-          width: 150px;
-          margin-right: 10px;
-        }
-      }
-
-      p {
-        span {
-          position: relative;
-
-          &:after {
-            content: "*";
-            display: block;
-            color: red;
-            position: absolute;
-            right: -10px;
-            top: -5px;
-          }
+    .upload-footer {
+        margin-bottom: 50px;
+        padding: 20px;
+        width: 540px;
+        border: 1px solid #eee;
+
+        >section {
+            >div {
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                width: 500px;
+
+                >p {
+                    width: 150px;
+                    margin-right: 10px;
+                }
+            }
+
+            p {
+                span {
+                    position: relative;
+
+                    &:after {
+                        content: "*";
+                        display: block;
+                        color: red;
+                        position: absolute;
+                        right: -10px;
+                        top: -5px;
+                    }
+                }
+            }
+
+            >p,
+            >div {
+                margin: 10px 0;
+            }
         }
-      }
-
-      >p,
-      >div {
-        margin: 10px 0;
-      }
-    }
-  }
-
-  flex: 1;
-  position: relative;
-  display: flex;
-
-  .history-wrap {
-    width: 0px;
-    opacity: 0;
-    overflow: hidden;
-    transition-duration: 0.3s;
-    transition-property: width;
-
-    &-open {
-      opacity: 1;
-      width: 260px;
     }
-  }
 
-  .wrap {
     flex: 1;
-  }
-
-  .border-wrap {
     position: relative;
-    padding: 30px 16px 30px 40px;
-    flex: 1;
-    height: 100%;
+    display: flex;
 
-    &.border-no-wrap {
-      padding: 0;
-
-      >div {
-        padding: 0;
+    .history-wrap {
+        width: 0px;
+        opacity: 0;
+        overflow: hidden;
+        transition-duration: 0.3s;
+        transition-property: width;
 
-        >section.section-padding {
-          padding: 0;
+        &-open {
+            opacity: 1;
+            width: 260px;
         }
-      }
     }
 
-    >div {
-      width: 100%;
-      height: 100%;
-      background: #fff;
-      box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.03);
-      border-radius: 14px;
-      display: flex;
-      flex-direction: column;
-      padding-left: 32px;
-      position: relative;
-
-      >div {
-        position: absolute;
-        bottom: -10px;
-        left: -10px;
-        z-index: 10;
-        width: 38px;
-        height: 38px;
-        border-radius: 20px;
-        background: #fff;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        cursor: pointer;
-      }
-
-      // >header {
-      //   >div {
-      //     display: inline-block;
-      //     margin-top: 20px;
-
-      //     >img {
-      //       transform: translateX(-12px);
-      //     }
-
-      //     >p {
-      //       font-size: 36px;
-      //       font-weight: bold;
-      //       color: #000;
-
-      //       >span {
-      //         font-weight: bold;
-      //         background: linear-gradient(180deg, #41d98c, #31c4c9);
-      //         -webkit-background-clip: text;
-      //         -webkit-text-fill-color: transparent;
-      //       }
-      //     }
-
-      //     >span {
-      //       display: block;
-      //       color: #000;
-      //       font-size: 15px;
-      //       margin: 5px 0 32px;
-      //     }
-      //   }
-      // }
-
-      >section {
+    .wrap {
         flex: 1;
-        overflow: hidden;
+    }
+
+    .border-wrap {
+        position: relative;
+        padding: 30px 16px 30px 40px;
+        flex: 1;
+        height: 100%;
 
-        &.section-padding {
-          padding-right: 32px;
-          padding-bottom: 50px;
+        &.border-no-wrap {
+            padding: 0;
+
+            >div {
+                padding: 0;
+
+                >section.section-padding {
+                    padding: 0;
+                }
+            }
         }
-      }
 
-      >footer {}
+        >div {
+            width: 100%;
+            height: 100%;
+            background: #fff;
+            box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.03);
+            border-radius: 14px;
+            display: flex;
+            flex-direction: column;
+            padding-left: 32px;
+            position: relative;
+
+            >div {
+                position: absolute;
+                bottom: -10px;
+                left: -10px;
+                z-index: 10;
+                width: 38px;
+                height: 38px;
+                border-radius: 20px;
+                background: #fff;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                cursor: pointer;
+            }
+
+            // >header {
+            //   >div {
+            //     display: inline-block;
+            //     margin-top: 20px;
+
+            //     >img {
+            //       transform: translateX(-12px);
+            //     }
+
+            //     >p {
+            //       font-size: 36px;
+            //       font-weight: bold;
+            //       color: #000;
+
+            //       >span {
+            //         font-weight: bold;
+            //         background: linear-gradient(180deg, #41d98c, #31c4c9);
+            //         -webkit-background-clip: text;
+            //         -webkit-text-fill-color: transparent;
+            //       }
+            //     }
+
+            //     >span {
+            //       display: block;
+            //       color: #000;
+            //       font-size: 15px;
+            //       margin: 5px 0 32px;
+            //     }
+            //   }
+            // }
+
+            >section {
+                flex: 1;
+                overflow: hidden;
+
+                &.section-padding {
+                    padding-right: 32px;
+                    padding-bottom: 50px;
+                }
+            }
+
+            >footer {}
+        }
     }
-  }
 }
 </style>

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно