Entry.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. <template>
  2. <div class="kgrt-entry" v-cloak v-loading="loading">
  3. <header class="entry-topbar">
  4. <button class="back" @click="handleBack">返回</button>
  5. <span class="title">知识溯源检索</span>
  6. <input type="text" v-model.trim="keyword" @keydown.enter="handleRetrieval(keyword)" />
  7. <button class="retrieval" @click="handleRetrieval(keyword)">检索</button>
  8. </header>
  9. <div class="entry-content">
  10. <div class="left" ref="leftRef">
  11. <div class="result-num" v-show="pagination.total">
  12. 搜索结果:{{ pagination.total }}条
  13. </div>
  14. <ul class="main-content-list">
  15. <li v-for="(record, index) in records" :key="record.id">
  16. <div class="record-title" @click="changeRecordIsShow(index)">
  17. <h3 target="_blank" class="title-name">
  18. <i @click.stop="handleClick(record.name, record.category)" style="cursor: pointer;">
  19. {{ record.name }}
  20. </i>
  21. <!-- <i class="distance">{{ record.distance }}</i> -->
  22. <i :class="record.isShow ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
  23. style="margin-left: auto; color: #2780ff"></i>
  24. </h3>
  25. <div class="category">{{ record.category }}</div>
  26. </div>
  27. <div :style="record.isShow ? { maxHeight: '10000px' } : { maxHeight: '0px' }" class="record-content-box">
  28. <div class="record-content-box-item1">
  29. <div class="menu">
  30. <div style="font-weight: bold;margin-bottom: 20px;" v-show="record.props.length > 0">目录</div>
  31. <div class="anchor" v-for="prop in record.props" :key="prop.id">
  32. <a :href="'#anchor' + prop.id"
  33. @click.prevent="handleAnchor('.entry-content', '#anchor' + prop.id)">{{ prop.prop_title
  34. }}</a>
  35. <!-- <el-button type="text" :targetId="'anchor' + prop.id">{{ prop.prop_title }}</el-button> -->
  36. </div>
  37. </div>
  38. <div class="menu-content">
  39. <div class="record-omit-content" v-for="prop in record.props" :key="prop.id">
  40. <div class="prop-title" :id="'anchor' + prop.id"> {{ prop.prop_title }}</div>
  41. <div class="prop-content">
  42. <div v-if="prop.answer">
  43. <i v-for="(answer, index) in prop.answer" :key="index">
  44. <i v-html="answer.sentence"></i>
  45. <i v-if="answer.flag" class="pdf-icon" @click="handlePdf(answer.flag, prop.references)">
  46. {{ answer.flag }}&nbsp;PDF
  47. </i>
  48. </i>
  49. </div>
  50. <div v-else>
  51. <i>{{ prop.prop_value }}</i>
  52. <!-- <span class="pdf-icon" @click="handlePdf">PDF</span> -->
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. <div class="literature" v-if="Array.isArray(record.files) && record.files.length > 0">
  59. <div>来源</div>
  60. <ul>
  61. <li v-for="file in record.files" :key="file.file_name">
  62. {{ file.index }}.<i class="file-type-icon" v-if="file.file_type">{{ file.file_type }}</i>{{
  63. decodeURIComponent(file.file_name) }}
  64. </li>
  65. </ul>
  66. </div>
  67. </div>
  68. <!-- <div class="record-edge">{{ record.edges.length }}</div> -->
  69. </li>
  70. </ul>
  71. <div class="pagination" v-if="pagination.total > 10">
  72. <el-pagination prev-text="上一页" next-text="下一页" background layout="prev, pager, next" :total="pagination.total"
  73. @current-change="handlePaginationChange">
  74. </el-pagination>
  75. </div>
  76. </div>
  77. <div class="right">
  78. <div class="aside">
  79. <div class="aside-title">
  80. <el-radio-group v-model="radio">
  81. <el-radio label="检索推荐">检索推荐</el-radio>
  82. <el-radio label="知识图谱">知识图谱</el-radio>
  83. </el-radio-group>
  84. </div>
  85. <!-- <ul class="aside-content">
  86. <li
  87. v-for="item in vectorSearch"
  88. :key="item.id"
  89. v-html="markdownToHtml(item.content)"
  90. ></li>
  91. </ul> -->
  92. <el-collapse v-model="activeName" accordion v-show="radio === '检索推荐'">
  93. <el-collapse-item v-for="item in vectorSearch" :key="item.id">
  94. <template slot="title">
  95. <div class="title" style="
  96. /* font-weight: 600; */
  97. font-size: 20px;
  98. vertical-align: bottom;
  99. color: #2f19ab;
  100. white-space: nowrap;
  101. ">
  102. {{ item.title }}
  103. <i class="distance" style="
  104. font-size: 12px;
  105. zoom: 0.8;
  106. margin-left: 3px;
  107. display: inline-block;
  108. color: #2f9634;
  109. ">{{ item.distance }}</i>
  110. </div>
  111. </template>
  112. <div style="padding: 0px 10px" class="markdown-body" v-html="markdownToHtml(item.content)"></div>
  113. </el-collapse-item>
  114. </el-collapse>
  115. <div class="knowledge-graph-window" v-show="radio === '知识图谱'">
  116. <iframe :src="knowledgeGraphLink" frameborder="0"></iframe>
  117. </div>
  118. <div class="pdf" v-show="pdfShow">
  119. <!-- <PdfViewer :pdfUrl="pdfUrl" :pdfPage="pdfPage" @closePdf="closePdf"></PdfViewer> -->
  120. <i class="el-icon-circle-close pdf2js-close-icon" @click="pdfShow = false"></i>
  121. <iframe style="width: 100%;height: 100%;" id="pdf2js"
  122. :src="pdf2jsUrl + '?file=' + encodeURIComponent(pdfProxy + decodeURIComponent(pdfUrl))">
  123. </iframe>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. <el-dialog title="文献引用" width="600px" custom-class="pdf-dialog" :modal="false"
  129. :visible.sync="pdfDialogData.visible">
  130. <pre style="white-space: pre-line;">{{ pdfDialogData.content }}</pre>
  131. <span class="view-pdf"
  132. @click="viewPdf(pdfDialogData.pdfUrl, pdfDialogData.page, pdfDialogData.reference)">查看PDF</span>
  133. <span class="reference-source">来源:{{ pdfDialogData.reference &&
  134. decodeURIComponent(pdfDialogData.reference.file_name)
  135. }}</span>
  136. </el-dialog>
  137. </div>
  138. </template>
  139. <script>
  140. import $ from 'jquery'
  141. import PdfViewer from "./PdfViewer.vue"
  142. const markdown = require("markdown").markdown;
  143. import config from "@api/config.js"
  144. const knowledgeGraphAddr = config.knowledgeGraphAddr
  145. // console.log(config.pdfProxy, knowledgeGraphAddr)
  146. let timer1
  147. let timer2
  148. export default {
  149. data() {
  150. return {
  151. pdfProxy: config.pdfProxy,
  152. radio: "检索推荐",
  153. loading: false,
  154. keyword: "",
  155. distance: 1,
  156. records: [],
  157. pagination: {},
  158. activeName: "1",
  159. vectorSearch: [], // 检索推荐的数据
  160. knowledgeGraphLink: "",
  161. pdfUrl: "",
  162. pdfPage: 1,
  163. pdfShow: false,
  164. pdf2jsUrl: location.origin + '/pdf2js/web/viewer.html',
  165. pdfDialogData: {
  166. visible: false,
  167. content: "",
  168. pdfUrl: "",
  169. page: 1,
  170. oldPage: 1,
  171. reference: null,
  172. }
  173. };
  174. },
  175. components: {
  176. PdfViewer
  177. },
  178. methods: {
  179. handlePdf(flag, references) {
  180. // console.log(flag, references)
  181. if (Array.isArray(references)) {
  182. for (let i = 0; i < references.length; i++) {
  183. if (references[i].index === flag) {
  184. const pdfUrl = references[i].referrence
  185. // alert(pdfUrl)
  186. this.pdfDialogData.content = references[i].content
  187. this.pdfDialogData.pdfUrl = pdfUrl
  188. this.pdfDialogData.visible = true
  189. this.pdfDialogData.page = references[i].page_no
  190. this.pdfDialogData.reference = references[i]
  191. // alert(references.page_no)
  192. break
  193. }
  194. }
  195. }
  196. },
  197. viewPdf(pdfUrl, page, reference) {
  198. clearInterval(timer1)
  199. clearInterval(timer2)
  200. this.pdfPage = page || 1
  201. this.pdfDialogData.visible = false
  202. this.pdfShow = true;
  203. const iframeLoadEvent = async () => {
  204. const iframe = document.getElementById('pdf2js');
  205. const viewerApp = iframe.contentWindow.PDFViewerApplication;
  206. // console.log("PDFViewerApplication", viewerApp, viewerApp.eventBus)
  207. await viewerApp.initializedPromise //等待pdf查看器初始化完成
  208. // 监听 PDF 加载完成事件
  209. // viewerApp.page = this.pdfPage // 传入需要让跳转页码的值
  210. // 监听目标页面渲染完成
  211. const onTargetPageRendered = (event) => {
  212. if (event.pageNumber === this.pdfPage) { // 目标页码
  213. let cycleIndex = 1
  214. viewerApp.page = this.pdfPage;
  215. // console.log(`第${this.pdfPage}页渲染完成!`);
  216. timer2 = setInterval(() => {
  217. viewerApp.page = this.pdfPage;
  218. const iframeDocument = document.getElementById('pdf2js').contentWindow.document;
  219. const pdfData = {
  220. htmlElements: [],
  221. textList: [],
  222. page: this.pdfPage,
  223. trunkId: this.pdfDialogData.reference.id
  224. }
  225. $(iframeDocument).find(`.pdfViewer .page[data-page-number="${this.pdfPage}"] .textLayer span[role="presentation"]`).each((index, element) => {
  226. // console.log(index, $(element).text())
  227. pdfData.htmlElements.push(element)
  228. pdfData.textList.push($(element).text())
  229. // $(element).addClass("highlight")
  230. })
  231. if (pdfData.htmlElements.length === 0 && cycleIndex <= 500) {
  232. // console.log("1没有获取到文本!")
  233. } else {
  234. clearInterval(timer2)
  235. this.matchHighlight(pdfData)
  236. }
  237. }, 200)
  238. viewerApp.eventBus.off('pagerendered', onTargetPageRendered); // 移除监听
  239. viewerApp.eventBus.off('documentloaded', onTargetDocumentLoaded); // 移除监听
  240. }
  241. };
  242. const onTargetDocumentLoaded = () => {
  243. viewerApp.page = this.pdfPage // 传入需要让跳转页码的值
  244. const iframeDocument = document.getElementById('pdf2js').contentWindow.document;
  245. let cycleIndex = 1
  246. timer1 = setInterval(() => {
  247. if (+$(iframeDocument).find("#pageNumber.toolbarField").val() !== this.pdfPage && cycleIndex <= 500) {
  248. viewerApp.page = this.pdfPage;
  249. cycleIndex++
  250. // console.log("viewerApp.page", viewerApp.page !== this.pdfPage)
  251. } else {
  252. // console.log("viewerApp.page", viewerApp.page === this.pdfPage, viewerApp.page, this.pdfPage)
  253. clearInterval(timer1)
  254. }
  255. }, 500)
  256. }
  257. viewerApp.eventBus.on('pagerendered', onTargetPageRendered);
  258. viewerApp.eventBus.on('documentloaded', onTargetDocumentLoaded);
  259. }
  260. if (!this.pdfUrl) {
  261. document.getElementById('pdf2js').addEventListener('load', iframeLoadEvent);
  262. }
  263. const isPdfUrlChange = this.pdfUrl !== pdfUrl;
  264. this.pdfUrl = pdfUrl
  265. this.$nextTick(() => {
  266. // 获取 iframe 元素
  267. // console.log("我是nextTick")
  268. const iframe = document.getElementById('pdf2js');
  269. if (isPdfUrlChange) { //pdf文件链接有改变,需要等待文件加载完毕
  270. // iframe.removeEventListener('load', iframeLoadEvent);
  271. // iframe.addEventListener('load', iframeLoadEvent);
  272. } else {
  273. const viewerApp = iframe.contentWindow.PDFViewerApplication;
  274. viewerApp.page = this.pdfPage // 传入需要让跳转页码的值
  275. let cycleIndex = 1
  276. timer2 = setInterval(() => {
  277. viewerApp.page = this.pdfPage // 传入需要让跳转页码的值
  278. const iframeDocument = document.getElementById('pdf2js').contentWindow.document;
  279. const pdfData = {
  280. htmlElements: [],
  281. textList: [],
  282. page: this.pdfPage,
  283. trunkId: this.pdfDialogData.reference.id
  284. }
  285. $(iframeDocument).find(`.pdfViewer .page[data-page-number="${page}"] .textLayer span[role="presentation"]`).each((index, element) => {
  286. // console.log(index, $(element).text())
  287. pdfData.htmlElements.push(element)
  288. pdfData.textList.push($(element).text())
  289. // 移除之前的高亮
  290. $(element).removeClass("highlight")
  291. })
  292. if (pdfData.htmlElements.length === 0 && cycleIndex <= 500) {
  293. // console.log("2没有获取到文本!")
  294. cycleIndex++
  295. } else {
  296. clearInterval(timer2)
  297. this.matchHighlight(pdfData)
  298. }
  299. }, 200)
  300. }
  301. })
  302. },
  303. closePdf(data) {
  304. this.pdfShow = false
  305. },
  306. handleAnchor(parentClass, anchor) {
  307. // console.log(parentClass, anchor, $(anchor).offset().top)
  308. // $(parentClass).animate({
  309. // scrollTop: $(anchor).offset().top - $(parentClass).offset().top
  310. // }); // 1000 表示滚动的动画持续时间(毫秒)
  311. const container = $(parentClass);
  312. const target = $(anchor);
  313. // 获取父容器当前滚动量
  314. const currentScroll = container.scrollTop();
  315. // 计算目标元素的原始偏移(需父容器有 position: relative)
  316. const targetOffset = target.position().top;
  317. // 最终滚动位置 = 原始偏移 + 当前已滚动量
  318. container.animate({ scrollTop: currentScroll + targetOffset });
  319. },
  320. matchHighlight: async function (pdfData) {
  321. try {
  322. // clearInterval(timer)
  323. const { data, success } = await this.$http.post(`/knowledge/saas/trunks/${pdfData.trunkId}/highlight`, pdfData.textList)
  324. // console.log(data)
  325. if (success) {
  326. // const iframeDocument = document.getElementById('pdf2js').contentWindow.document;
  327. // const divArray = $(iframeDocument).find(`.pdfViewer .page[data-page-number="${pdfData.page}"] .textLayer span[role="presentation"]`).map(function () { return this; }).get()
  328. // console.log(pdfData, data, divArray)
  329. for (let i = 0; i < data.length; i++) {
  330. // console.log(data[i], pdfData.htmlElements[data[i]])
  331. // $(pdfData.htmlElements[data[i]]).css('backgroundColor', 'red');
  332. $(pdfData.htmlElements[data[i]]).addClass("highlight");
  333. }
  334. }
  335. } catch (e) {
  336. console.log(e)
  337. }
  338. },
  339. handleClick(name, category) {
  340. // this.getVectorSearch(name);
  341. // this.keyword = name;
  342. // this.getPaginatedSearch(this.keyword);
  343. // this.$router.replace({ query: { keyword: this.keyword } });
  344. this.getVectorSearch(name);
  345. this.knowledgeGraphLink = `${knowledgeGraphAddr}/knowledgeGraph.html?input=${name}&label=${category}&no-tree=true`;
  346. },
  347. markdownToHtml(text) {
  348. //将markdown文本转成html文本
  349. return markdown.toHTML(text);
  350. },
  351. handleBack() {
  352. this.$router.push({ name: "kgrt-retrieve" });
  353. },
  354. handleRetrieval(keyword) {
  355. this.getPaginatedSearch(keyword);
  356. // this.$route.query.keyword = keyword;
  357. this.$router.replace({ query: { keyword: keyword } });
  358. },
  359. changeRecordIsShow(index) {
  360. let copyData = JSON.parse(JSON.stringify(this.records[index]))
  361. copyData.isShow = !(copyData.isShow ? true : false)
  362. // this.records.splice(index, 1, copyData)
  363. this.$set(this.records, index, copyData)
  364. if (!copyData.isShow) return;
  365. if (copyData.isShow && !copyData.oneExpand) { //第一次展开才发送请求
  366. this.records[index].oneExpand = true
  367. this.getEbSearch(index)
  368. }
  369. // this.records[index].isShow = !this.records[index].isShow;
  370. // alert('我点击了!')
  371. },
  372. getEbSearch: async function (index) {
  373. try {
  374. const params = {
  375. "node_id": this.records[index].id,
  376. "props_ids": this.records[index].props.map(it => it.id),
  377. symptoms: this.$route.query.mw ? this.$route.query.mw.split(';') : []
  378. // "conversation_id": "string"
  379. }
  380. let res = await this.axios.post("/knowledge/text/eb_search", params)
  381. const { data, code, msg, success } = res.data
  382. if (success) {
  383. // Object.assign(this.records[index], data)
  384. // const copyData = JSON.parse(JSON.stringify(this.records[index]))
  385. this.records[index].files = data.files
  386. this.records[index].props = data.props
  387. // this.records.splice(index, 1, copyData)
  388. // console.log("record", this.records[index])
  389. }
  390. } catch (e) {
  391. console.log(e)
  392. }
  393. },
  394. getPaginatedSearch: async function (keyword, category = "", pageNo = 1, limit = 10) {
  395. try {
  396. if (!keyword) {
  397. this.pagination = {};
  398. this.records = [];
  399. return;
  400. }
  401. this.loading = true;
  402. let resData = await this.axios.post(
  403. "/knowledge/saas/nodes/paginated_search",
  404. {
  405. keyword: keyword,
  406. category: category,
  407. pageNo: pageNo,
  408. limit: limit,
  409. distance: this.distance,
  410. // knowledge_ids: ["ER"],
  411. }
  412. );
  413. this.records = resData.data.data.records;
  414. // console.log("records", this.records);
  415. this.pagination = resData.data.data.pagination;
  416. if (this.records.length > 0) {
  417. const name = this.records[0].name;
  418. const category = this.records[0].category;
  419. this.getVectorSearch(name);
  420. this.knowledgeGraphLink = `${knowledgeGraphAddr}/knowledgeGraph.html?input=${name}&label=${category}&no-tree=true`;
  421. }
  422. this.$nextTick(() => {
  423. // 回到顶部
  424. document.querySelector(".kgrt-entry").scrollTop = 0;
  425. if (this.distance === 0) {
  426. // this.records.forEach((it) => {
  427. // it.isShow = true
  428. // })
  429. $(".main-content-list .record-title").trigger('click')
  430. }
  431. });
  432. } catch (e) {
  433. console.log(e);
  434. } finally {
  435. this.loading = false;
  436. }
  437. },
  438. handlePaginationChange(page) {
  439. // console.log(page);
  440. this.getPaginatedSearch(this.$route.params.keyword || this.keyword, this.$route.query.category || "", page);
  441. },
  442. getVectorSearch: async function (text) {
  443. try {
  444. let resData = await this.axios.post(
  445. "/knowledge/saas/trunks/vector_search",
  446. {
  447. text: text,
  448. limit: 10,
  449. type: "community_report",
  450. }
  451. );
  452. this.vectorSearch = resData.data.data;
  453. } catch (e) {
  454. console.log(e);
  455. }
  456. },
  457. },
  458. created() {
  459. this.keyword = this.$route.query.keyword;
  460. const category = this.$route.query.category
  461. if (this.$route.query.hasOwnProperty('exact')) {
  462. if (this.$route.query.exact === null) {
  463. this.distance = 0
  464. } else {
  465. this.distance = Number(this.$route.query.exact) || 0
  466. }
  467. } else {
  468. this.distance = 1
  469. }
  470. // console.log('exact', this.$route.query.exact, this.distance)
  471. this.getPaginatedSearch(this.keyword, category);
  472. },
  473. mounted() { },
  474. };
  475. </script>
  476. <style scoped lang="less">
  477. div {
  478. box-sizing: border-box;
  479. }
  480. .pdf-icon {
  481. display: inline;
  482. height: 12px;
  483. font-size: 12px;
  484. // min-width: 40px;
  485. cursor: pointer;
  486. color: white;
  487. // font-weight: bolder;
  488. border-radius: 10px;
  489. padding: 0px;
  490. text-align: right;
  491. // line-height: 20px;
  492. background-color: #FECFCB;
  493. white-space: nowrap;
  494. }
  495. .file-type-icon {
  496. display: inline-block;
  497. // height: 20px;
  498. // min-width: 40px;
  499. // cursor: pointer;
  500. // color: white;
  501. // font-weight: bolder;
  502. border-radius: 10px;
  503. border: 1px solid #000;
  504. padding: 0px 5px;
  505. text-align: right;
  506. // line-height: 20px;
  507. box-sizing: border-box;
  508. // background-color: #FECFCB;
  509. margin-right: 10px;
  510. margin-left: 3px;
  511. }
  512. .kgrt-entry {
  513. width: 100vw;
  514. height: 100vh;
  515. box-sizing: border-box;
  516. padding: 0px;
  517. overflow: auto;
  518. // overflow-x: hidden;
  519. display: flex;
  520. flex-direction: column;
  521. .entry-topbar {
  522. height: 60px;
  523. flex: 0 0 auto;
  524. display: flex;
  525. align-items: center;
  526. padding: 0px 5px 20px;
  527. border-bottom: 1px solid #e0e0e0;
  528. margin: 0px 15px;
  529. // min-width: 500px;
  530. .back {
  531. padding: 2px 5px;
  532. white-space: nowrap;
  533. }
  534. .title {
  535. font-size: 24px;
  536. font-weight: 600;
  537. margin: 0px 10px;
  538. white-space: nowrap;
  539. }
  540. input[type="text"] {
  541. width: 300px;
  542. height: 20px;
  543. padding: 1px 10px;
  544. border-color: 1px solid #bfbfbf;
  545. }
  546. .retrieval {
  547. cursor: pointer;
  548. background-color: #ffbf6b;
  549. font-weight: 600;
  550. // border: 0px;
  551. height: 29px;
  552. width: 70px;
  553. border: 1px solid #c7c7c7;
  554. margin-left: 20px;
  555. border-radius: 5px;
  556. white-space: nowrap;
  557. }
  558. }
  559. .entry-content {
  560. // margin-top: 20px;
  561. // margin: 20px 15px 0px 15px;
  562. display: flex;
  563. flex-wrap: nowrap;
  564. flex: 1 1 auto;
  565. overflow-y: auto;
  566. // overflow-x: hidden;
  567. box-sizing: border-box;
  568. padding: 0px 15px;
  569. position: relative;
  570. &::-webkit-scrollbar {
  571. // display: none;
  572. width: 10px;
  573. height: 10px;
  574. }
  575. &::-webkit-scrollbar-thumb {
  576. background-color: rgb(226, 218, 218);
  577. border-radius: 10px;
  578. }
  579. &::-webkit-scrollbar-track {
  580. border-radius: 2px;
  581. }
  582. .left {
  583. // flex: 1 1 1;
  584. // background: skyblue;
  585. // overflow-y: auto;
  586. // overflow-x: hidden;
  587. width: 50%;
  588. // height: 100%;
  589. min-width: 500px;
  590. padding-top: 10px;
  591. .result-num {
  592. padding-left: 5px;
  593. font-size: 16px;
  594. font-weight: bold;
  595. }
  596. .main-content-list {
  597. li {
  598. margin: 15px 5px 0px 5px;
  599. cursor: default;
  600. }
  601. .record-title {
  602. // color: #1d7dd7;
  603. // text-decoration: underline;
  604. // cursor: pointer;
  605. border-bottom: 1px solid #e5eaf9;
  606. .title-name {
  607. display: flex;
  608. align-items: end;
  609. font-size: 20px;
  610. font-weight: 600;
  611. color: #2f19ab;
  612. .distance {
  613. font-size: 12px;
  614. zoom: 0.8;
  615. color: #2f9634;
  616. transform: translateX(5px);
  617. display: inline-block;
  618. }
  619. }
  620. .category {
  621. font-size: 12px;
  622. color: #2f9634;
  623. }
  624. }
  625. .record-content-box {
  626. // display: flex;
  627. flex-wrap: wrap;
  628. overflow: hidden;
  629. transition: max-height 1s linear;
  630. .record-content-box-item1 {
  631. display: flex;
  632. }
  633. .literature {
  634. // flex: 1 1 100%;
  635. width: 100%;
  636. }
  637. .menu {
  638. flex: 0 0 auto;
  639. width: 180px;
  640. .anchor {
  641. a {
  642. color: #C4C6C8;
  643. padding: 3px 0px 3px 10px;
  644. display: inline-block;
  645. font-size: 16px;
  646. &:hover {
  647. color: skyblue;
  648. }
  649. }
  650. }
  651. }
  652. .menu-content {
  653. flex: 1 1 auto;
  654. }
  655. }
  656. .record-omit-content {
  657. border-bottom: 1px solid #e5eaf9;
  658. margin-top: 20px;
  659. font-size: 16px;
  660. // font-weight: 500;
  661. .prop-title {
  662. font-weight: bold;
  663. }
  664. .prop-content {
  665. padding: 10px 0px 20px 15px;
  666. color: #767F8E;
  667. line-height: 2;
  668. white-space: pre-line;
  669. }
  670. // font-family: "宋体", "楷体", sans-serif;
  671. &:first-child {
  672. margin: 0px;
  673. }
  674. }
  675. .record-edges {
  676. color: #a1a1a1;
  677. font-size: 10px;
  678. }
  679. }
  680. .pagination {
  681. text-align: center;
  682. /deep/ .el-pagination {
  683. text-align: left;
  684. padding-left: 0px;
  685. .btn-next,
  686. .btn-prev {
  687. background: white;
  688. padding-left: 8px;
  689. padding-right: 8px;
  690. &:hover {
  691. color: skyblue;
  692. }
  693. }
  694. .el-pager {
  695. li {
  696. background: white;
  697. }
  698. }
  699. }
  700. }
  701. }
  702. .right {
  703. width: 50%;
  704. min-width: 300px;
  705. // flex: 0 0 1;
  706. // background: orange;
  707. padding: 10px 5px 5px 30px;
  708. position: sticky;
  709. /* 使右边盒子固定 */
  710. top: 0;
  711. /* 顶部固定 */
  712. .aside {
  713. position: relative;
  714. height: 100%;
  715. width: 100%;
  716. display: flex;
  717. flex-direction: column;
  718. .pdf {
  719. position: absolute;
  720. top: -18px;
  721. width: calc(100% + 20px);
  722. min-height: 500px;
  723. height: calc(100vh - 80px);
  724. // overflow: auto;
  725. overflow: hidden;
  726. background: white;
  727. // opacity: 0.8;
  728. box-shadow: 0 0 10px white;
  729. padding: 10px;
  730. .pdf2js-close-icon {
  731. position: absolute;
  732. left: 50px;
  733. top: 18px;
  734. z-index: 10;
  735. cursor: pointer;
  736. font-size: 20px;
  737. }
  738. }
  739. /deep/.markdown {
  740. ul {}
  741. }
  742. .aside-title {
  743. font-size: 16px;
  744. font-weight: 600;
  745. margin-bottom: 10px;
  746. flex: 0 0 auto;
  747. }
  748. .el-collapse {
  749. flex: 1 1 auto;
  750. overflow: auto;
  751. &::-webkit-scrollbar {
  752. display: none;
  753. }
  754. }
  755. .aside-content {
  756. li {
  757. // color: #a0a0a0;
  758. }
  759. }
  760. }
  761. .knowledge-graph-window {
  762. width: 100%;
  763. height: 600px;
  764. iframe {
  765. width: 100%;
  766. height: 100%;
  767. }
  768. }
  769. }
  770. }
  771. }
  772. </style>
  773. <style lang="less">
  774. .pdf-dialog {
  775. margin-top: 50vh !important;
  776. background-color: #F9F9F8;
  777. border-radius: 10px;
  778. margin-left: 10vw;
  779. .el-dialog__header {
  780. display: none;
  781. }
  782. .view-pdf {
  783. margin-top: 20px;
  784. color: red;
  785. cursor: pointer;
  786. display: inline-block;
  787. }
  788. .reference-source {
  789. color: red;
  790. font-size: 20px;
  791. margin-left: 20px;
  792. }
  793. .el-dialog__body {
  794. // background-color: #F9F9F8;
  795. // border-radius: 10px;
  796. }
  797. }
  798. </style>