mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: chat export pdf (#3931)
Co-authored-by: wangdan-fit2cloud <dan.wang@fit2cloud.com>
This commit is contained in:
parent
deb7333750
commit
23c9bc545c
|
|
@ -32,6 +32,8 @@
|
|||
"element-plus": "^2.10.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"highlight.js": "^11.11.1",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^3.0.1",
|
||||
"katex": "^0.16.10",
|
||||
"marked": "^12.0.2",
|
||||
"md-editor-v3": "^5.8.2",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
|
|
@ -1 +1,35 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 232.4409 232.4409"><defs><style>.cls-1{fill:url(#未命名的渐变_7);}.cls-2{fill:url(#未命名的渐变_7-2);}.cls-3{fill:url(#未命名的渐变_7-3);}.cls-4{fill:url(#未命名的渐变_7-4);}.cls-5{fill:url(#未命名的渐变_7-5);}.cls-6{fill:url(#未命名的渐变_7-6);}</style><linearGradient id="未命名的渐变_7" x1="113.6159" y1="176.9998" x2="113.6159" y2="195.8629" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3370FF"/><stop offset="1" stop-color="#7f3bf5"/></linearGradient><linearGradient id="未命名的渐变_7-2" x1="209.3027" y1="90.7042" x2="209.3027" y2="131.8553" xlink:href="#未命名的渐变_7"/><linearGradient id="未命名的渐变_7-3" x1="23.1384" y1="90.7042" x2="23.1384" y2="131.8553" xlink:href="#未命名的渐变_7"/><linearGradient id="未命名的渐变_7-4" x1="138.8087" y1="96.1512" x2="138.8087" y2="118.7847" xlink:href="#未命名的渐变_7"/><linearGradient id="未命名的渐变_7-5" x1="95.3622" y1="96.1512" x2="95.3622" y2="118.7847" xlink:href="#未命名的渐变_7"/><linearGradient id="未命名的渐变_7-6" x1="116.2206" y1="48.8968" x2="116.2206" y2="173.4002" xlink:href="#未命名的渐变_7"/></defs><title>MaxKB</title><path class="cls-1" d="M128.4532,177H98.7785L87.78,187.9985a4.6069,4.6069,0,0,0,3.2576,7.8644h45.1569a4.6069,4.6069,0,0,0,3.2575-7.8644Z"/><path class="cls-2" d="M210.0008,90.7042h-5.85v41.1511h5.85a4.4537,4.4537,0,0,0,4.4537-4.4537V95.1579A4.4537,4.4537,0,0,0,210.0008,90.7042Z"/><path class="cls-3" d="M28.29,90.7042H22.44a4.4538,4.4538,0,0,0-4.4538,4.4537v32.2437a4.4538,4.4538,0,0,0,4.4538,4.4537h5.85Z"/><path class="cls-4" d="M138.8087,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,138.8087,96.1512Z"/><path class="cls-5" d="M95.3622,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,95.3622,96.1512Z"/><path class="cls-6" d="M166.8344,48.8968H65.6064A33.7544,33.7544,0,0,0,31.89,82.6131v57.07A33.7548,33.7548,0,0,0,65.6064,173.4h101.228a33.7549,33.7549,0,0,0,33.7168-33.7168v-57.07A33.7545,33.7545,0,0,0,166.8344,48.8968Zm2.831,90.4457a6.0733,6.0733,0,0,1-6.0732,6.0733H114.2168a43.5922,43.5922,0,0,0-21.3313,5.5757l-16.5647,9.2946v-14.87h-7.472a6.0733,6.0733,0,0,1-6.0733-6.0733v-60.5a6.0733,6.0733,0,0,1,6.0733-6.0733h94.7434a6.0733,6.0733,0,0,1,6.0732,6.0733Z"/></svg>
|
||||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 232.4409 232.4409">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1{fill:url(#未命名的渐变_7);}.cls-2{fill:url(#未命名的渐变_7-2);}.cls-3{fill:url(#未命名的渐变_7-3);}.cls-4{fill:url(#未命名的渐变_7-4);}.cls-5{fill:url(#未命名的渐变_7-5);}.cls-6{fill:url(#未命名的渐变_7-6);}</style>
|
||||
<linearGradient id="未命名的渐变_7" x1="113.6159" y1="176.9998" x2="113.6159" y2="195.8629"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#3370FF" />
|
||||
<stop offset="1" stop-color="#7f3bf5" />
|
||||
</linearGradient>
|
||||
<linearGradient id="未命名的渐变_7-2" x1="209.3027" y1="90.7042" x2="209.3027" y2="131.8553"
|
||||
xlink:href="#未命名的渐变_7" />
|
||||
<linearGradient id="未命名的渐变_7-3" x1="23.1384" y1="90.7042" x2="23.1384" y2="131.8553"
|
||||
xlink:href="#未命名的渐变_7" />
|
||||
<linearGradient id="未命名的渐变_7-4" x1="138.8087" y1="96.1512" x2="138.8087" y2="118.7847"
|
||||
xlink:href="#未命名的渐变_7" />
|
||||
<linearGradient id="未命名的渐变_7-5" x1="95.3622" y1="96.1512" x2="95.3622" y2="118.7847"
|
||||
xlink:href="#未命名的渐变_7" />
|
||||
<linearGradient id="未命名的渐变_7-6" x1="116.2206" y1="48.8968" x2="116.2206" y2="173.4002"
|
||||
xlink:href="#未命名的渐变_7" />
|
||||
</defs>
|
||||
<title>MaxKB</title>
|
||||
<path class="cls-1"
|
||||
d="M128.4532,177H98.7785L87.78,187.9985a4.6069,4.6069,0,0,0,3.2576,7.8644h45.1569a4.6069,4.6069,0,0,0,3.2575-7.8644Z" />
|
||||
<path class="cls-2"
|
||||
d="M210.0008,90.7042h-5.85v41.1511h5.85a4.4537,4.4537,0,0,0,4.4537-4.4537V95.1579A4.4537,4.4537,0,0,0,210.0008,90.7042Z" />
|
||||
<path class="cls-3"
|
||||
d="M28.29,90.7042H22.44a4.4538,4.4538,0,0,0-4.4538,4.4537v32.2437a4.4538,4.4538,0,0,0,4.4538,4.4537h5.85Z" />
|
||||
<path class="cls-4"
|
||||
d="M138.8087,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,138.8087,96.1512Z" />
|
||||
<path class="cls-5"
|
||||
d="M95.3622,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,95.3622,96.1512Z" />
|
||||
<path class="cls-6"
|
||||
d="M166.8344,48.8968H65.6064A33.7544,33.7544,0,0,0,31.89,82.6131v57.07A33.7548,33.7548,0,0,0,65.6064,173.4h101.228a33.7549,33.7549,0,0,0,33.7168-33.7168v-57.07A33.7545,33.7545,0,0,0,166.8344,48.8968Zm2.831,90.4457a6.0733,6.0733,0,0,1-6.0732,6.0733H114.2168a43.5922,43.5922,0,0,0-21.3313,5.5757l-16.5647,9.2946v-14.87h-7.472a6.0733,6.0733,0,0,1-6.0733-6.0733v-60.5a6.0733,6.0733,0,0,1,6.0733-6.0733h94.7434a6.0733,6.0733,0,0,1,6.0732,6.0733Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
|
@ -26,7 +26,7 @@
|
|||
</div>
|
||||
<template v-if="!(isUserInput || isAPIInput) || !firsUserInput || type === 'log'">
|
||||
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
|
||||
<div ref="dialogScrollbar" class="ai-chat__content p-16">
|
||||
<div ref="dialogScrollbar" class="ai-chat__content p-16" id="chatListId">
|
||||
<PrologueContent
|
||||
:type="type"
|
||||
:application="applicationDetails"
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
d="M166.8344,48.8968H65.6064A33.7544,33.7544,0,0,0,31.89,82.6131v57.07A33.7548,33.7548,0,0,0,65.6064,173.4h101.228a33.7549,33.7549,0,0,0,33.7168-33.7168v-57.07A33.7545,33.7545,0,0,0,166.8344,48.8968Zm2.831,90.4457a6.0733,6.0733,0,0,1-6.0732,6.0733H114.2168a43.5922,43.5922,0,0,0-21.3313,5.5757l-16.5647,9.2946v-14.87h-7.472a6.0733,6.0733,0,0,1-6.0733-6.0733v-60.5a6.0733,6.0733,0,0,1,6.0733-6.0733h94.7434a6.0733,6.0733,0,0,1,6.0732,6.0733Z"
|
||||
/>
|
||||
</svg>
|
||||
<img v-else src="@/assets/logo/logo.svg" :height="height" />
|
||||
<img v-else src="@/assets/logo/logo.png" :height="height" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
import html2Canvas from 'html2canvas'
|
||||
import jsPDF from 'jspdf'
|
||||
|
||||
export const exportToPDF = async (elementId: string, filename = 'document.pdf') => {
|
||||
const element = document.getElementById(elementId)
|
||||
if (!element) return
|
||||
await html2Canvas(element, {
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
logging: false,
|
||||
scale: 2,
|
||||
backgroundColor: '#fff',
|
||||
}).then((canvas: any) => {
|
||||
const pdf = new jsPDF('p', 'mm', 'a4')
|
||||
const pageWidth = 190 // 保留边距后的有效宽度
|
||||
const pageHeight = 277 // 保留边距后的有效高度 //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
|
||||
const imgHeight = (pageHeight * canvas.width) / pageWidth
|
||||
|
||||
let renderedHeight = 0
|
||||
while (renderedHeight < canvas.height) {
|
||||
const pageCanvas = document.createElement('canvas')
|
||||
pageCanvas.width = canvas.width
|
||||
pageCanvas.height = Math.min(imgHeight, canvas.height - renderedHeight)
|
||||
|
||||
pageCanvas
|
||||
.getContext('2d')!
|
||||
.putImageData(
|
||||
canvas
|
||||
.getContext('2d')!
|
||||
.getImageData(
|
||||
0,
|
||||
renderedHeight,
|
||||
canvas.width,
|
||||
Math.min(imgHeight, canvas.height - renderedHeight),
|
||||
),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
pdf.addImage(
|
||||
pageCanvas.toDataURL('image/jpeg', 1.0),
|
||||
'JPEG',
|
||||
10,
|
||||
10, // 左边距和上边距
|
||||
pageWidth,
|
||||
Math.min(pageHeight, (pageWidth * pageCanvas.height) / pageCanvas.width),
|
||||
)
|
||||
|
||||
renderedHeight += imgHeight
|
||||
if (renderedHeight < canvas.height) {
|
||||
pdf.addPage()
|
||||
}
|
||||
}
|
||||
pdf.save(filename)
|
||||
})
|
||||
}
|
||||
|
|
@ -139,6 +139,9 @@
|
|||
<el-dropdown-item @click="exportHTML"
|
||||
>{{ $t('common.export') }} HTML</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item @click="exportToPDF('chatListId', currentChatName + '.pdf')"
|
||||
>{{ $t('common.export') }} PDF</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
|
@ -222,7 +225,6 @@ import { ref, onMounted, nextTick, computed, watch } from 'vue'
|
|||
import { marked } from 'marked'
|
||||
import { saveAs } from 'file-saver'
|
||||
import chatAPI from '@/api/chat/chat'
|
||||
|
||||
import useStore from '@/stores'
|
||||
import useResize from '@/layout/hooks/useResize'
|
||||
import { hexToRgba } from '@/utils/theme'
|
||||
|
|
@ -236,6 +238,7 @@ import ParagraphDocumentContent from '@/components/ai-chat/component/knowledge-s
|
|||
import HistoryPanel from '@/views/chat/component/HistoryPanel.vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { getFileUrl } from '@/utils/common'
|
||||
import { exportToPDF } from '@/utils/htmlToPdf'
|
||||
useResize()
|
||||
|
||||
const { common, chatUser } = useStore()
|
||||
|
|
|
|||
Loading…
Reference in New Issue