Commit f3887f44 authored by 罗超's avatar 罗超

修改PDF下载,替换为服务器生成

parent 65571f29
......@@ -20,13 +20,11 @@ declare module 'vue' {
Divider: typeof import('./src/components/Divider.vue')['default']
Drawer: typeof import('./src/components/Drawer.vue')['default']
EditableInput: typeof import('./src/components/ColorPicker/EditableInput.vue')['default']
ElAside: typeof import('element-plus/es')['ElAside']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckTag: typeof import('element-plus/es')['ElCheckTag']
ElCol: typeof import('element-plus/es')['ElCol']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
......@@ -36,7 +34,6 @@ declare module 'vue' {
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
......@@ -73,6 +70,8 @@ declare module 'vue' {
QRCode: typeof import('./src/components/QRCode/QRCode.vue')['default']
RadioButton: typeof import('./src/components/RadioButton.vue')['default']
RadioGroup: typeof import('./src/components/RadioGroup.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Saturation: typeof import('./src/components/ColorPicker/Saturation.vue')['default']
Select: typeof import('./src/components/Select.vue')['default']
SelectGroup: typeof import('./src/components/SelectGroup.vue')['default']
......
<template>
<div v-if="isFinish" style="height: 100vh;background: rgb(243, 246, 251);">
<!-- <Screen v-if="screening" /> -->
<Market v-if="(market&&model!=2)||(market&&SalesEditor>0)"></Market>
<PreviewCustomSlider v-if="model==448963"></PreviewCustomSlider>
<Market v-else-if="(market&&model!=2)||(market&&SalesEditor>0)"></Market>
<SellTemplate v-else-if="model==2&&SalesEditor==0"/>
<Editor v-else-if="_isPC" />
<Mobile v-else />
......@@ -30,21 +31,17 @@ import Editor from './views/Editor/index.vue'
import Screen from './views/Screen/index.vue'
import Mobile from './views/Mobile/index.vue'
import Market from './views/Market/Index.vue'
import NewFile from './views/Market/newFile.vue'
import PreviewCustomSlider from './views/Preview/PreviewCustomSlider.vue'
import SellTemplate from './views/SellTemplate/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
const searchData = ref({} as any)
provide(injectKeyTemplate,searchData)
const autoSave = ref(0)
provide("SellTravelSave",autoSave)
const isFinish = ref(false)
const loading = ref(false)
const ShareTips = ref('')
const _isPC = isPC()
const mainStore = useMainStore()
const snapshotStore = useSnapshotStore()
const modelStore = useScreenStore()
......
......@@ -55,6 +55,9 @@ page {
.no-bg .el-divider__text{
background-color: transparent !important;
}
.el-loading-mask{
z-index: 99999 !important;
}
.light-shadow {
box-shadow: 0px 0px 20px 0px rgba(76,87,125,0.2)!important;
}
......
......@@ -488,6 +488,7 @@ export default (MapDOM:Ref<HTMLElement|undefined>,loadingStatus:Ref<boolean>)=>{
lineSeries.value!.mapLines.template.nonScalingStroke = true;
lineSeries.value!.mapLines.template.line.controlPointDistance = 0;
lineSeries.value!.mapLines.template.line.controlPointPosition = 0.5;
lineSeries.value!.mapLines.template.line.resizable = true
lineSeries.value!.mapLines.template.line.cursorOverStyle = am4core.MouseCursorStyle.pointer
lineSeries.value!.mapLines.template.strokeLinecap = 'round'
}
......
import {compressionThumbnail} from '@/utils/psdParser/compressor'
import { compressionThumbnail } from '@/utils/psdParser/compressor'
class FileService{
static getImageSizeWithoutDownloading = async (url: string): Promise<{ width: number; height: number }> => {
const response = await fetch(url, { method: 'HEAD' }); // Use HEAD request to get metadata
const contentLength = response.headers.get('Content-Length');
if (!contentLength) {
throw new Error('Unable to determine Content-Length');
}
const rangeEnd = Math.min(parseInt(contentLength, 10), 1024); // Read the first 1KB of data
const partialResponse = await fetch(url, {
headers: {
Range: `bytes=0-${rangeEnd}`,
},
});
const blob = await partialResponse.blob();
const objectURL = URL.createObjectURL(blob);
const image = new Image();
return new Promise((resolve, reject) => {
image.onload = () => {
resolve({ width: image.width, height: image.height });
URL.revokeObjectURL(objectURL);
};
image.onerror = reject;
image.src = objectURL;
});
}
const fetchWithTimeout = (url:string, timeout:number)=>{
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
static convertNetworkToBase64Async = async (url:string): Promise<{ width: number; height: number,url:string }> =>{
let result:{ width: number; height: number,url:string }={
width:0,
height:0,
url:''
return fetch(url, { signal: controller.signal })
.then(response => {
clearTimeout(timeoutId);
return response;
})
.catch(error => {
if (error.name === 'AbortError') {
console.error('Request timed out');
} else {
console.error('Fetch error:', error.message);
}
throw error;
});
}
class FileService {
static downloadLinePdfAsync = async (id: any) => {
let url = `http://localhost:5164/api/pdf/${id}`
try {
const response = await fetchWithTimeout(url, 60*1000);
// 处理响应
if (response.ok) {
return true
} else {
return false
}
const response = await fetch(url)
const blob = await response.blob()
const objectURL = URL.createObjectURL(blob);
const image = new Image();
return new Promise(async (resolve, reject) => {
} catch (error) {
console.log(error)
return false
}
}
static getImageSizeWithoutDownloading = async (url: string): Promise<{ width: number; height: number }> => {
const response = await fetch(url, { method: 'HEAD' }); // Use HEAD request to get metadata
const contentLength = response.headers.get('Content-Length');
image.onload = () => {
result.width=image.width
result.height=image.height
const reader = new FileReader();
reader.onload = async (e) => {
result.url = reader.result as string
result.url = await compressionThumbnail(result.url,"image/jpeg", 0, 0.9)
resolve(result)
}
reader.readAsDataURL(blob);
};
image.onerror = reject;
image.src = objectURL;
})
if (!contentLength) {
throw new Error('Unable to determine Content-Length');
}
const rangeEnd = Math.min(parseInt(contentLength, 10), 1024); // Read the first 1KB of data
const partialResponse = await fetch(url, {
headers: {
Range: `bytes=0-${rangeEnd}`,
},
});
const blob = await partialResponse.blob();
const objectURL = URL.createObjectURL(blob);
const image = new Image();
return new Promise((resolve, reject) => {
image.onload = () => {
resolve({ width: image.width, height: image.height });
URL.revokeObjectURL(objectURL);
};
image.onerror = reject;
image.src = objectURL;
});
}
static convertNetworkToBase64Async = async (url: string): Promise<{ width: number; height: number, url: string }> => {
let result: { width: number; height: number, url: string } = {
width: 0,
height: 0,
url: ''
}
const response = await fetch(url)
const blob = await response.blob()
const objectURL = URL.createObjectURL(blob);
const image = new Image();
return new Promise(async (resolve, reject) => {
image.onload = () => {
result.width = image.width
result.height = image.height
const reader = new FileReader();
reader.onload = async (e) => {
result.url = reader.result as string
result.url = await compressionThumbnail(result.url, "image/jpeg", 0, 0.9)
resolve(result)
}
reader.readAsDataURL(blob);
};
image.onerror = reject;
image.src = objectURL;
})
}
}
export default FileService
\ No newline at end of file
......@@ -135,7 +135,7 @@
<script lang="ts" setup>
import { ArrowDown } from '@element-plus/icons-vue'
import { nextTick, ref, reactive, inject, computed, watch } from 'vue'
import { nextTick, ref, reactive, inject, computed, watch, provide } from 'vue'
import { storeToRefs } from 'pinia'
import { toPng, toJpeg } from 'html-to-image'
import message from '@/utils/message'
......@@ -188,7 +188,7 @@ const editingTitle = ref(false)
const titleInputRef = ref<InstanceType<typeof Input>>()
const titleValue = ref('')
const { setNewDatasList } = useEditor()
const autoSave = inject("SellTravelSave") as any
const { userInfo } = storeToRefs(userStore())
......@@ -311,13 +311,17 @@ const SetSellTemplate = async (type) => {
if(type==1) setTimeout(()=>{
SalesEditorStore.setSalesEditor(0)
},100)
if(type == 0 && Id==0){
searchData.value.sellId=TemplateRes.data.data.Id
}
if(autoSave.value==1)autoSave.value=2
}else{
ElMessage({
showClose: true,
message: '操作失败',
type: 'warning',
})
if(autoSave.value==1)autoSave.value=0
}
} catch (error) {}
datas.loading = false
......@@ -552,6 +556,12 @@ const setDialogForExport = (type: DialogForExportTypes) => {
mainStore.setDialogForExport(type)
mainMenuVisible.value = false
}
watch(()=>autoSave.value,(newVal)=>{
if(newVal==1){
setTemplate(0)
}
})
</script>
<style lang="scss" scoped>
......
......@@ -20,7 +20,7 @@
</template>
</div>
</div>
<div class="configs">
<div class="configs" v-if="param.model!='2'">
<div class="row">
<div class="title">导出范围:</div>
<RadioGroup
......@@ -53,20 +53,25 @@
提示:若打印预览与实际样式不一致,请在弹出的打印窗口中勾选【背景图形】选项。
</div>
</div>
<a ref="downloadLink" target="_blank" :href="fileUrl" @load="downLoadEndHandler" style="display:none" v-else></a>
<!-- <a ref="downloadLink" :href="fileUrl" @click.prevent="downloadFile" style="display:none" v-else></a> -->
<div class="q-mt-lg configs" style="font-size: 12px;color:red" v-if="searchData.sellId==0">当前设计文档没有保存,无法下载PDF,请先保存文档。</div>
<div class="btns">
<Button class="btn export" type="primary" @click="expPDF()">打印 / 导出 PDF</Button>
<Button class="btn export" type="primary" @click="expPDF()" v-if="param.model!='2'">导出PDF</Button>
<Button class="btn export" type="primary" @click="exportOnlinePdf()" v-if="param.model=='2' && searchData.sellId!=0">导出PDF</Button>
<Button class="btn close" @click="emit('close')">关闭</Button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Ref, ref,inject } from 'vue'
import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store'
import { print } from '@/utils/print'
import { VIEWPORT_SIZE, VIEWPORT_VER_SIZE } from '@/configs/canvas'
import { query } from '@/utils/common'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
import Switch from '@/components/Switch.vue'
......@@ -74,6 +79,11 @@ import Button from '@/components/Button.vue'
import RadioButton from '@/components/RadioButton.vue'
import RadioGroup from '@/components/RadioGroup.vue'
import Select from '@/components/Select.vue'
import { ElLoading } from 'element-plus'
import { injectKeyTemplate } from '@/types/injectKey'
import { watch } from 'vue'
import { nextTick } from 'vue'
const emit = defineEmits<{
(event: 'close'): void
......@@ -81,11 +91,18 @@ const emit = defineEmits<{
const { slides, currentSlide, viewportRatio } = storeToRefs(useSlidesStore())
const newSlides = ref<Array<any>>([])
const searchData = ref({} as any)
searchData.value = inject(injectKeyTemplate)
console.log(searchData.value)
const pdfThumbnailsRef = ref<HTMLElement>()
const rangeType = ref<'all' | 'current'>('all')
const count = ref(1)
const padding = ref(false)
let param = query()
const autoSave = inject('SellTravelSave') as Ref<number>
const loadingObj = ref<any>()
const downloadLink= ref()
const fileUrl = ref("")
const expPDF = () => {
if (!pdfThumbnailsRef.value) return
......@@ -106,6 +123,35 @@ const formatSliders =()=>{
newSlides.value.push(item)
})
}
const exportOnlinePdf=()=>{
autoSave.value=1
}
const beginDownload = async ()=>{
// loadingObj.value = ElLoading.service({
// text:'正在下载中,请耐心等待',
// lock:true,
// body:true
// })
fileUrl.value = `http://fileservice.oytour.com/api/pdf/${searchData.value.sellId}`
nextTick(()=>{
downloadLink.value.click()
})
//downloadLink.value.click()
}
const downLoadEndHandler = ()=>{
if(loadingObj.value) loadingObj.value.close()
loadingObj.value=null
}
watch(()=>autoSave.value,(newVal)=>{
if(newVal==2){
beginDownload()
}else if(newVal==0){
if(loadingObj.value) loadingObj.value.close()
loadingObj.value=null
}
})
formatSliders()
</script>
......
<template>
<div style="
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: auto;
">
<div class="export-img-dialog">
<div class="thumbnails-view" ref="refThumbnails">
<div class="thumbnails" v-for="slide in slides">
<ThumbnailSlide class="thumbnail" :key="slide.id" :slide="slide" :size="param.w
? param.w
: viewportRatio < 1
? VIEWPORT_SIZE.Value
: VIEWPORT_VER_SIZE.Value
" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import ThumbnailSlide from '../components/ThumbnailSlide/index.vue'
import ConfigService from '@/services/ConfigService'
import { storeToRefs } from 'pinia'
import { useSlidesStore } from '../../store'
import { VIEWPORT_SIZE, VIEWPORT_VER_SIZE } from '../../configs/canvas'
import { ref } from 'vue';
import { query } from '../../utils/common'
const param = ref("")
param.value = query()
const slidesStore = useSlidesStore()
const { slides, viewportRatio } = storeToRefs(slidesStore)
const loadSliders = async ()=>{
let response = await ConfigService.sellGetTemplateDetails({Id:param.value.tid})
console.log(response)
if (response.data.resultCode == 1) {
let dataObj = response.data.data
viewportRatio.value = dataObj.TempType==1? 0.7069:1.414
let SlidesData = JSON.parse(dataObj.TempData)
let newSlides = []
await SlidesData.forEach((x,i)=>{
newSlides.push(x)
})
slidesStore.setSlides(newSlides)
}
}
if(param.value.tid){
loadSliders()
}
</script>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment