فهرست منبع

iframe嵌入使用

Veronique 1 سال پیش
والد
کامیت
ba01680755

+ 17 - 0
src/api/template/index.ts

@@ -34,6 +34,14 @@ export function getDesignTemplateEdit(data: any): any {
   });
 }
 
+export function getPreViewTemplate(data: any): any {
+  return request({
+    url: "apis10/design/getPreViewTemplate",
+    method: "post",
+    params: data,
+  });
+}
+
 export function updateDesignTemplate(data: any): any {
   return request({
     url: "apis10/design/updateDesignTemplate",
@@ -41,3 +49,12 @@ export function updateDesignTemplate(data: any): any {
     data: data,
   });
 }
+
+export function newDesignOrder(data: any, sessionId: string): any {
+  return request({
+    url: "apis10/design/newDesignOrder?outerSessionId=" + sessionId,
+    method: "post",
+    data: data,
+  });
+}
+

+ 4 - 3
src/components/FileExport/ExportImage.vue

@@ -29,9 +29,10 @@
       <div class="row">
         <div class="title">{{ t('message.imageResolution') }}:</div>
         <el-radio-group class="config-item" v-model="dpiType">
-          <el-radio-button style="width: 33.33%;" :value="72" :label="72">72DPI</el-radio-button>
-          <el-radio-button style="width: 33.33%;" :value="150" :label="150">150DPI</el-radio-button>
-          <el-radio-button style="width: 33.33%;" :value="300" :label="300">300DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="72" :label="72">72DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="150" :label="150">150DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="300" :label="300">300DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="1200" :label="1200">1200DPI</el-radio-button>
         </el-radio-group>
       </div>
 

+ 29 - 27
src/components/SwipeInput.vue

@@ -1,40 +1,41 @@
 <template>
   <el-input-number
-    class="swipe-input"
-    v-model="numberValue" 
-    :step="step" 
-    :max="max" 
-    :min="min"
-    :controls="false"
-    :label="label"
-    @change="change"
+      class="swipe-input"
+      v-model="numberValue"
+      :step="step"
+      :max="max"
+      :min="min"
+      :controls="false"
+      :label="label"
+      @change="change"
   >
   </el-input-number>
 </template>
 <script setup lang="ts">
-import { usePointerSwipe, useVModel, isDefined, useMagicKeys } from '@vueuse/core'
-import { useSlots, watch, ref, computed } from 'vue'
-import { toFixed } from '@/utils/common'
+import {usePointerSwipe, useVModel, isDefined, useMagicKeys} from '@vueuse/core'
+import {useSlots, watch, ref, computed} from 'vue'
+import {toFixed} from '@/utils/common'
 // import { useMainStore } from '@/store';
 // import { storeToRefs } from 'pinia';
 // import { mm2px, px2mm } from '@/utils/image';
 import useHandleActive from '@/hooks/useHandleActive'
 
-const { handleInput } = useHandleActive()
+const {handleInput} = useHandleActive()
 
 const props = withDefaults(
-  defineProps<{
-    label?: string
-    modelValue?: number
-    modelEvent?: 'change' | 'input'
-    step?: number
-    max?: number
-    min?: number
-  }>(),
-  {
-    modelEvent: 'change',
-    step: 0.01,
-  },
+    defineProps<{
+      label?: string
+      modelValue?: number
+      modelEvent?: 'change' | 'input'
+      step?: number
+      max?: number
+      min?: number
+    }>(),
+    {
+      modelEvent: 'change',
+      step: 0.01,
+      min: 0
+    },
 )
 
 const emit = defineEmits<{
@@ -50,10 +51,10 @@ const numberValue = useVModel(props, 'modelValue', emit)
 watch(numberValue, (value) => {
   if (!value) return
   numberValue.value = toFixed(value)
-}, { immediate: true})
+}, {immediate: true})
 
 const change = (value: number | undefined, ev: Event) => {
-  if (!value) return
+  if (value == undefined) return
   value = handleInput(value)
   emit('change', value, ev)
 }
@@ -96,16 +97,17 @@ const change = (value: number | undefined, ev: Event) => {
 </script>
 
 
-
 <style scoped lang="scss">
 .swipe-input {
   :deep(.el-input__wrapper) {
     padding: 1px;
   }
+
   :deep(.el-input__prefix-inner) {
     margin: 0;
     width: 25px;
   }
+
   :deep(.label-ref) {
     margin: 0;
   }

+ 227 - 162
src/hooks/useCanvasExport.ts

@@ -1,173 +1,238 @@
-
-import { ref } from 'vue'
-import { saveAs } from 'file-saver'
-import { storeToRefs } from 'pinia'
-import { useFabricStore, useTemplatesStore } from '@/store'
-import { WorkSpaceThumbType, WorkSpaceClipType, WorkSpaceCommonType, WorkSpaceSafeType, propertiesToInclude } from '@/configs/canvas'
-import { ImageFormat, StaticCanvas } from 'fabric'
-import { downloadSVGFile, downloadLinkFile } from '@/utils/download'
-import { changeDpiDataUrl } from 'changedpi'
+import {ref} from 'vue'
+import {saveAs} from 'file-saver'
+import {storeToRefs} from 'pinia'
+import {useFabricStore, useTemplatesStore} from '@/store'
+import {
+    WorkSpaceThumbType,
+    WorkSpaceClipType,
+    WorkSpaceCommonType,
+    WorkSpaceSafeType,
+    propertiesToInclude
+} from '@/configs/canvas'
+import {ImageFormat, StaticCanvas} from 'fabric'
+import {downloadSVGFile, downloadLinkFile} from '@/utils/download'
+import {changeDpiDataUrl} from 'changedpi'
 import useCanvas from '@/views/Canvas/useCanvas'
 import useCenter from '@/views/Canvas/useCenter'
-import { exportFile } from '@/api/file'
-import { ElementNames } from '@/types/elements'
+import {exportFile} from '@/api/file'
+import {ElementNames} from '@/types/elements'
+import {px2mm} from "@/utils/image";
 
 export default () => {
-  
-  const Exporting = ref(false)
-  const { showClip, showSafe } = storeToRefs(useFabricStore())
-  const { currentTemplate, templateCanvas, templates } = storeToRefs(useTemplatesStore())
-  // 导出图片
-  const exportImage = (format: ImageFormat, quality: number, dpi: number, ignoreClip = true) => {
-    Exporting.value = true
-    const [ canvas ] = useCanvas()
-    const { left, top, width, height } = useCenter()
-    const zoom = canvas.getZoom()
-    const viewportTransform = canvas.viewportTransform
-    const activeObject = canvas.getActiveObject()
-    let ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceCommonType.includes(obj.id))
-    if (format === 'jpeg') {
-      ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceThumbType.includes(obj.id))
+
+    const Exporting = ref(false)
+    const {showClip, showSafe} = storeToRefs(useFabricStore())
+    const {currentTemplate, templateCanvas, templates} = storeToRefs(useTemplatesStore())
+    // 导出图片
+    const exportImage = (format: ImageFormat, quality: number, dpi: number, ignoreClip = true) => {
+        Exporting.value = true
+        const [canvas] = useCanvas()
+        const {left, top, width, height} = useCenter()
+        const zoom = canvas.getZoom()
+        const viewportTransform = canvas.viewportTransform
+        const activeObject = canvas.getActiveObject()
+        let ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceCommonType.includes(obj.id))
+        if (format === 'jpeg') {
+            ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceThumbType.includes(obj.id))
+        }
+        if (ignoreClip) {
+            ignoreObjects.map(item => item.set({visible: false}))
+            canvas.renderAll()
+        }
+        if (activeObject) canvas.discardActiveObject()
+        canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
+        canvas.set({background: 'rgba(255,255,255,0)'})
+        canvas.renderAll()
+        let result = canvas.toDataURL({
+            multiplier: 1 / zoom,
+            // multiplier: 2,
+            quality: quality,
+            format: format,
+            width: width * zoom,
+            height: height * zoom,
+            left: left * zoom + viewportTransform[4],
+            top: top * zoom + viewportTransform[5]
+        })
+        result = changeDpiDataUrl(result, dpi)
+        saveAs(result, `sd-designer-${Date.now()}.${format}`)
+        Exporting.value = false
+        ignoreObjects.map(item => item.set({visible: true}))
+        canvas.getObjects().filter(obj => obj.id === WorkSpaceClipType).map(item => item.set({visible: showClip.value}))
+        canvas.getObjects().filter(obj => obj.id === WorkSpaceSafeType).map(item => item.set({visible: showSafe.value}))
+        if (activeObject) canvas.setActiveObject(activeObject)
+        canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
+        canvas.renderAll()
     }
-    if (ignoreClip) {
-      ignoreObjects.map(item => item.set({visible: false}))
-      canvas.renderAll()
+
+    const getSVGDataEx = () => {
+        return convertSvgUnitsToMillimeters(getSVGData())
     }
-    if (activeObject) canvas.discardActiveObject()
-    canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
-    canvas.set({background: 'rgba(255,255,255,0)'})
-    canvas.renderAll()
-    let result = canvas.toDataURL({
-      multiplier: 1 / zoom,
-      // multiplier: 2,
-      quality: quality,
-      format: format,
-      width: width * zoom,
-      height: height * zoom,
-      left: left * zoom + viewportTransform[4],
-      top: top * zoom + viewportTransform[5]
-    })
-    result = changeDpiDataUrl(result, dpi)
-    saveAs(result, `sd-designer-${Date.now()}.${format}`)
-    Exporting.value = false
-    ignoreObjects.map(item => item.set({visible: true}))
-    canvas.getObjects().filter(obj => obj.id === WorkSpaceClipType).map(item => item.set({visible: showClip.value}))
-    canvas.getObjects().filter(obj => obj.id === WorkSpaceSafeType).map(item => item.set({visible: showSafe.value}))
-    if (activeObject) canvas.setActiveObject(activeObject)
-    canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
-    canvas.renderAll()
-  }
-
-  const getSVGData = () => {
-    const [ canvas ] = useCanvas()
-    const { left, top, width, height } = useCenter()
-    canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
-    canvas.renderAll()
-    const data = canvas.toSVG({
-      viewBox: {
-        x: left,
-        y: top,
-        width: width,
-        height: height,
-      },
-      width: width + 'px',
-      height: height + 'px'
-    }, (element) => element)
-    canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
-    canvas.renderAll()
-    return data
-  }
-
-  const getJSONData = () => {
-    const [ canvas ] = useCanvas()
-    const serializer = canvas.toObject(propertiesToInclude)
-    serializer.workSpace = currentTemplate.value.workSpace
-    serializer.zoom = currentTemplate.value.zoom
-    serializer.width = currentTemplate.value.width
-    serializer.height = currentTemplate.value.height
-    // console.log(JSON.stringify(serializer));
-    
-    return serializer
-  }
-
-  const exportSVG = () => {
-    const [ canvas ] = useCanvas()
-    const ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceThumbType.includes(obj.id))
-    ignoreObjects.map(item => item.set({visible: false}))
-    canvas.renderAll()
-    const data = getSVGData()
-    downloadSVGFile(data, `sd-designer-${Date.now()}.svg`)
-    ignoreObjects.map(item => item.set({visible: true}))
-    canvas.getObjects().filter(obj => obj.id === WorkSpaceClipType).map(item => item.set({visible: showClip.value}))
-    canvas.getObjects().filter(obj => obj.id === WorkSpaceSafeType).map(item => item.set({visible: showSafe.value}))
-    canvas.renderAll()
-  }
-
-  // 导出PDF
-  const exportPDF = async (rangeType: string) => {
-    convertFile('pdf', rangeType)
-  }
-
-  // 导出PSD
-  const exportPSD = async () => {
-    convertFile('psd')
-  }
-
-  const convertFile = async (filetype: string, rangeType?: string) => {
-    Exporting.value = true
-    const svgData: string[] = []
-    if (rangeType === 'all') {
-      for (let i = 0; i < templates.value.length; i++) {
-        const template = templates.value[i]
-        const width = template.width / template.zoom
-        const height = template.height / template.zoom
-        const thumpCanvas = templateCanvas.value.get(template.id) as StaticCanvas
-        thumpCanvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
-        const svg = thumpCanvas.toSVG({
-          viewBox: {
-            x: 0,
-            y: 0,
-            width: width,
-            height: height,
-          },
-          width: width + 'px',
-          height: height + 'px'
+
+    const getSVGData = () => {
+        const [ canvas ] = useCanvas()
+        const { left, top, width, height } = useCenter()
+        canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
+        canvas.renderAll()
+        const data = canvas.toSVG({
+            viewBox: {
+                x: left,
+                y: top,
+                width: width,
+                height: height,
+            },
+            width: width + 'px',
+            height: height + 'px'
         }, (element) => element)
-        svgData.push(btoa(unescape(encodeURIComponent(svg))))
-        thumpCanvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
-      }
-    } 
-    else {
-      svgData.push(btoa(unescape(encodeURIComponent(getSVGData()))))
+        canvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
+        canvas.renderAll()
+        return data
     }
-    const content = {
-      data: svgData,
-      filetype,
-      width: currentTemplate.value.width / currentTemplate.value.zoom,
-      height: currentTemplate.value.height / currentTemplate.value.zoom,
+
+
+
+
+
+    const convertSvgUnitsToMillimeters = (svgString) => {
+        const parser = new DOMParser();
+        const svgDoc = parser.parseFromString(svgString, "image/svg+xml");
+        const svgElement = svgDoc.documentElement;
+
+        function convertAttributes(element) {
+            const attributesToConvert = ['x', 'y', 'width', 'height', 'cx', 'cy', 'r', 'rx', 'ry', 'x1', 'y1', 'x2', 'y2', 'font-size'];
+            const transformAttributesToConvert = ['translate', 'matrix'];
+
+            attributesToConvert.forEach(attr => {
+                if (element.hasAttribute(attr)) {
+                    const valueInPx = element.getAttribute(attr).replace('px', '');
+                    const valueInMm = px2mm(valueInPx).toFixed(2) + 'mm';
+                    element.setAttribute(attr, valueInMm);
+                }
+            });
+
+            if (element.hasAttribute('transform')) {
+                let transform = element.getAttribute('transform');
+                transformAttributesToConvert.forEach(transformType => {
+                    const regex = new RegExp(`${transformType}\\(([^)]+)\\)`, 'g');
+                    transform = transform.replace(regex, (match, values) => {
+                        const convertedValues = values.split(/[ ,]/).map(v => px2mm(v).toFixed(2)).join(' ');
+                        return `${transformType}(${convertedValues})`;
+                    });
+                });
+                element.setAttribute('transform', transform);
+            }
+
+            for (let child of element.children) {
+                convertAttributes(child);
+            }
+        }
+
+        convertAttributes(svgElement);
+
+        // Convert SVG width and height
+        svgElement.setAttribute('width', px2mm(svgElement.getAttribute('width')).toFixed(2) + 'mm');
+        svgElement.setAttribute('height', px2mm(svgElement.getAttribute('height')).toFixed(2) + 'mm');
+
+        const serializer = new XMLSerializer();
+        return serializer.serializeToString(svgElement);
     }
-    const result = await exportFile(content)
-    if (result && result.data.link) {
-      downloadLinkFile(result.data.link, `sd-designer-${Date.now()}.${filetype}`)
+
+
+
+
+
+
+
+
+    const getJSONData = () => {
+        const [canvas] = useCanvas()
+        const serializer = canvas.toObject(propertiesToInclude)
+        serializer.workSpace = currentTemplate.value.workSpace
+        serializer.zoom = currentTemplate.value.zoom
+        serializer.width = currentTemplate.value.width
+        serializer.height = currentTemplate.value.height
+        // console.log(JSON.stringify(serializer));
+
+        return serializer
+    }
+
+    const exportSVG = () => {
+        const [canvas] = useCanvas()
+        const ignoreObjects = canvas.getObjects().filter(obj => WorkSpaceThumbType.includes(obj.id))
+        ignoreObjects.map(item => item.set({visible: false}))
+        canvas.renderAll()
+        const data = getSVGData()
+        downloadSVGFile(data, `sd-designer-${Date.now()}.svg`)
+        ignoreObjects.map(item => item.set({visible: true}))
+        canvas.getObjects().filter(obj => obj.id === WorkSpaceClipType).map(item => item.set({visible: showClip.value}))
+        canvas.getObjects().filter(obj => obj.id === WorkSpaceSafeType).map(item => item.set({visible: showSafe.value}))
+        canvas.renderAll()
+    }
+
+    // 导出PDF
+    const exportPDF = async (rangeType: string) => {
+        convertFile('pdf', rangeType)
+    }
+
+    // 导出PSD
+    const exportPSD = async () => {
+        convertFile('psd')
+    }
+
+    const convertFile = async (filetype: string, rangeType?: string) => {
+        Exporting.value = true
+        const svgData: string[] = []
+        if (rangeType === 'all') {
+            for (let i = 0; i < templates.value.length; i++) {
+                const template = templates.value[i]
+                const width = template.width / template.zoom
+                const height = template.height / template.zoom
+                const thumpCanvas = templateCanvas.value.get(template.id) as StaticCanvas
+                thumpCanvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === true).map(item => item.set({visible: false}))
+                const svg = thumpCanvas.toSVG({
+                    viewBox: {
+                        x: 0,
+                        y: 0,
+                        width: width,
+                        height: height,
+                    },
+                    width: width + 'px',
+                    height: height + 'px'
+                }, (element) => element)
+                svgData.push(btoa(unescape(encodeURIComponent(svg))))
+                thumpCanvas.getObjects().filter(item => item.type === ElementNames.REFERENCELINE && item.visible === false).map(item => item.set({visible: true}))
+            }
+        } else {
+            svgData.push(btoa(unescape(encodeURIComponent(getSVGData()))))
+        }
+        const content = {
+            data: svgData,
+            filetype,
+            width: currentTemplate.value.width / currentTemplate.value.zoom,
+            height: currentTemplate.value.height / currentTemplate.value.zoom,
+        }
+        const result = await exportFile(content)
+        if (result && result.data.link) {
+            downloadLinkFile(result.data.link, `sd-designer-${Date.now()}.${filetype}`)
+        }
+        Exporting.value = false
+    }
+
+    // 导出json
+    const exportJSON = () => {
+        const serializer = getJSONData()
+        const blob = new Blob([JSON.stringify(serializer)])
+        saveAs(blob, `sd-designer-${Date.now()}.json`)
+    }
+
+    return {
+        exportImage,
+        exportPDF,
+        exportPSD,
+        exportJSON,
+        exportSVG,
+        getJSONData,
+        getSVGData,
+        getSVGDataEx,
+        Exporting
     }
-    Exporting.value = false
-  }
-
-  // 导出json
-  const exportJSON = () => {
-    const serializer = getJSONData()
-    const blob = new Blob([JSON.stringify(serializer)])
-    saveAs(blob, `sd-designer-${Date.now()}.json`)
-  }
-
-  return {
-    exportImage,
-    exportPDF,
-    exportPSD,
-    exportJSON,
-    exportSVG,
-    getJSONData,
-    getSVGData,
-    Exporting
-  }
 }

+ 2 - 2
src/store/modules/main.ts

@@ -30,7 +30,7 @@ export interface MainState {
     thumbnailsFocus: boolean
     drawAreaFocus: boolean
     systemFonts: SystemFont[]
-    onlineFonts: SystemFont[]
+    onlineFonts: any[]
     disableHotkeys: boolean
     exportType: ExportTypes
     lastHelp: PoolType
@@ -169,7 +169,7 @@ export const useMainStore = defineStore('main', {
                     style.type = "text/css";
                     response.data.forEach(fontInfo => {
                         style.appendChild(document.createTextNode(
-                            `@font-face {font-family: '${fontInfo.fontName}'; src: url(${fontInfo.fontFilePath}) format('truetype');}`
+                            `@font-face {font-family: '${fontInfo.fontFamily}'; src: url(${fontInfo.fontFilePath}) format('truetype');}`
                         ));
                     })
                     document.head.appendChild(style);

+ 60 - 56
src/store/modules/user.ts

@@ -1,66 +1,70 @@
-import { Object as FabricObject } from 'fabric'
-import { customAlphabet } from 'nanoid'
-import { defineStore } from 'pinia'
-import { SYS_FONTS } from '@/configs/fonts'
-import { ImageCategoryInfo } from '@/configs/images'
-import { CanvasElement } from '@/types/canvas'
-import { RightStates, PointElement, ImageCategoryData } from '@/types/elements'
-import { ExportTypes, PoolType, SystemFont } from '@/types/common'
-import { FontInfo } from '@/api/static/types'
+import {Object as FabricObject} from 'fabric'
+import {customAlphabet} from 'nanoid'
+import {defineStore} from 'pinia'
+import {SYS_FONTS} from '@/configs/fonts'
+import {ImageCategoryInfo} from '@/configs/images'
+import {CanvasElement} from '@/types/canvas'
+import {RightStates, PointElement, ImageCategoryData} from '@/types/elements'
+import {ExportTypes, PoolType, SystemFont} from '@/types/common'
+import {FontInfo} from '@/api/static/types'
 import useCanvas from '@/views/Canvas/useCanvas'
 
 export interface UserState {
-  id: number
-  uuid: string
-  username: string
-  nickname: string
-  phone: string
-  avatar: string
-  deptId: number
-  email: string
-  isMultiLogin: boolean
-  isStaff: boolean
-  isSuperuser: boolean
-  joinTime: string
-  lastLoginTime: string
-  loginStatus: boolean
-  token: string
+    id: number
+    uuid: string
+    username: string
+    nickname: string
+    phone: string
+    avatar: string
+    deptId: number
+    email: string
+    isMultiLogin: boolean
+    isStaff: boolean
+    isSuperuser: boolean
+    joinTime: string
+    lastLoginTime: string
+    loginStatus: boolean
+    token: string
 }
 
 export const useUserStore = defineStore('user', {
-  state: (): UserState => ({
-    id: 0,
-    uuid: '',
-    username: '',
-    nickname: '',
-    phone: '',
-    avatar: '',
-    deptId: 0,
-    email: '',
-    isMultiLogin: false,
-    isStaff: false,
-    isSuperuser: false,
-    joinTime: '',
-    lastLoginTime: '',
-    loginStatus: false,
-    token: ''
-  }),
+    state: (): UserState => ({
+        id: 0,
+        uuid: '',
+        username: '',
+        nickname: '',
+        phone: '',
+        avatar: '',
+        deptId: 0,
+        email: '',
+        isMultiLogin: false,
+        isStaff: false,
+        isSuperuser: false,
+        joinTime: '',
+        lastLoginTime: '',
+        loginStatus: false,
+        token: ''
+    }),
+
+    getters: {
+        activeElementList() {
+            //   const slidesStore = useSlidesStore()
+            //   const currentSlide = slidesStore.currentSlide
+            //   if (!currentSlide || !currentSlide.elements) return []
+        }
 
-  getters: {
-    activeElementList() {
-    //   const slidesStore = useSlidesStore()
-    //   const currentSlide = slidesStore.currentSlide
-    //   if (!currentSlide || !currentSlide.elements) return []
     },
-  
-    
-  },
 
-  actions: {
-    
-    setLoginStatus(status: boolean) {
-      this.loginStatus = status
-    }
-    
-  },
+    actions: {
+
+        setLoginStatus(status: boolean) {
+            this.loginStatus = status
+        },
+
+        setUUID(UUID: string) {
+            this.uuid = UUID
+        }
+
+
+    },
 })

+ 1 - 1
src/utils/fonts.ts

@@ -40,7 +40,7 @@ export const getSupportFonts = (fontNames: SystemFont[]) => {
 export async function loadFont(fontFamily: string) {
   let font
   try {
-    const fonts = await window.queryLocalFonts();
+    const fonts = window.queryLocalFonts();
     font = fonts.filter(item => item.family === fontFamily)[0]
   } catch(e: any) {
     console.log(`Cannot query fonts: ${e.message}`)

+ 2 - 2
src/utils/image.ts

@@ -105,10 +105,10 @@ export const src2blob = async (src: string) => {
 
 // px2mm
 export const px2mm = (value: number) => {
-  return value / 300 * DefaultRatio
+  return value / DefaultDPI * DefaultRatio
 }
 
 // mm2px
 export const mm2px = (value: number) => {
-  return value * 300 / DefaultRatio
+  return value * DefaultDPI / DefaultRatio
 }

+ 78 - 5
src/views/Editor/CanvasCenter/index.vue

@@ -12,10 +12,10 @@
 <script lang="ts" setup>
 import {storeToRefs} from 'pinia'
 import {onMounted, onUnmounted} from 'vue'
-import {useFabricStore, useMainStore, useTemplatesStore} from '@/store'
+import {useFabricStore, useMainStore, useTemplatesStore, useUserStore} from '@/store'
 import {useRouter} from 'vue-router'
 import {unzip} from "@/utils/crypto"
-import {getDesignTemplateEdit, getTemplateData} from '@/api/template'
+import {getDesignTemplateEdit, getPreViewTemplate, getTemplateData} from '@/api/template'
 import {contextMenus} from '@/configs/contextMenu'
 import {initEditor} from '@/views/Canvas/useCanvas'
 import {initPixi} from '@/views/Canvas/usePixi'
@@ -26,7 +26,10 @@ const fabricStore = useFabricStore()
 const mainStore = useMainStore()
 const router = useRouter()
 const templatesStore = useTemplatesStore()
+const userStore = useUserStore()
+const {uuid} = storeToRefs(userStore);
 const {wrapperRef, canvasRef} = storeToRefs(fabricStore)
+
 const {drawAreaFocus} = storeToRefs(mainStore)
 const {keydownListener, keyupListener, pasteListener} = useCanvasHotkey()
 
@@ -81,24 +84,94 @@ const getTemplateDetail = async (pk: number) => {
   }
 }
 
-const initRouter = async (templateId?: number) => {
+const getPreviewTemplateDetail = async (pk: number, templateParams: any, outerSessionId: any) => {
+  //todo 传参测试
+  // const templateParams = {
+  //   backgroundWidth: 250.0,
+  //   backgroundHeight: 300.0,
+  //   backgroundColor: 'rgba(200, 100, 100, 1)'
+  // }
+  if (!outerSessionId) return
+
+  let params = {}
+  if (!templateParams) {
+    params = {
+      id: pk,
+      outerSessionId: outerSessionId
+    }
+  } else {
+    params = {
+      id: pk,
+      params: JSON.stringify(templateParams),
+      outerSessionId: outerSessionId
+    }
+  }
+  const res = await getPreViewTemplate(params)
+
+  if (res.httpCode == 200) {
+    try {
+      templatesStore.setTemplateName(res.data.templateName)
+      const data = res.data.jsonContent
+      await templatesStore.changeTemplate(JSON.parse(data))
+    } catch (e) {
+      ElMessage({
+        type: 'error',
+        message: '模板加载失败,请联系系统管理员',
+      })
+    }
+  }
+}
+
+const initRouter = async (templateId: number, runMode: number, outerSessionId: any) => {
   if (templateId) {
     templatesStore.setTemplateId(templateId)
     const loadingInstance = ElLoading.service({fullscreen: true, background: 'rgba(122, 122, 122, 0.5)'})
-    await getTemplateDetail(templateId)
+    //判断一下是后台设计还是前台预览
+    if (runMode == 1) {
+      await getTemplateDetail(templateId)
+    } else if (runMode == 0) {
+      await getPreviewTemplateDetail(templateId, null, outerSessionId)
+    }
     nextTick(() => loadingInstance.close())
   }
 }
 
 onMounted(async () => {
   const query = router.currentRoute.value.query
-  initRouter(query.template)
+  initRouter(query.template, query.runMode, query.sessionId)
   initEditor(query.template)
   initPixi()
   document.addEventListener('keydown', keydownListener)
   document.addEventListener('keyup', keyupListener)
   window.addEventListener('blur', keyupListener)
   window.addEventListener('paste', pasteListener as any)
+
+  if (query.runMode == 0) {
+    // 使用iframe方案,本网页是内嵌页面
+    // 监听来自父页面的消息
+    window.addEventListener("message", function (event) {
+      // 确保消息来自信任的来源
+      // if (event.origin !== "https://sd2000.com") {
+      //   return;
+      // }
+
+      // 处理接收到的消息
+      console.log("Received message:", event.data);
+
+      //消息格式
+      // {
+      //   msgType: 'loadTemplate',
+      //   data: {
+      //      xxx
+      //   }
+      // }
+      const message = JSON.parse(event.data);
+
+      if (message.msgType == "loadTemplate") {
+        getPreviewTemplateDetail(query.template, message.data, uuid.value)
+      }
+    })
+  }
 })
 
 onUnmounted(() => {

+ 4 - 3
src/views/Editor/CanvasFooter/components/ExportImage.vue

@@ -29,9 +29,10 @@
       <div class="row">
         <div class="title">{{ t('message.imageResolution') }}:</div>
         <el-radio-group class="config-item" v-model="dpiType">
-          <el-radio-button style="width: 33.33%;" :value="72" :label="72">72DPI</el-radio-button>
-          <el-radio-button style="width: 33.33%;" :value="150" :label="150">150DPI</el-radio-button>
-          <el-radio-button style="width: 33.33%;" :value="300" :label="300">300DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="72" :label="72">72DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="150" :label="150">150DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="300" :label="300">300DPI</el-radio-button>
+          <el-radio-button style="width: 25%;" :value="1200" :label="1200">1200DPI</el-radio-button>
         </el-radio-group>
       </div>
 

+ 27 - 6
src/views/Editor/CanvasRight/ElementStylePanel/TextboxStylePanel.vue

@@ -11,7 +11,7 @@
                          :style="{fontFamily: item.value}"></el-option>
             </template>
             <template v-else>
-              <el-option v-for="item in group.options" :key="item.id" :value="item.fontName" :label="item.fontName">
+              <el-option v-for="item in group.options" :key="item.id" :value="item.fontFamily" :label="item.fontName">
                 <el-image style="height: 18px; width: 90px" :src="item.fontThumbUrl"></el-image>
               </el-option>
             </template>
@@ -167,7 +167,7 @@
     <el-row class="mt-10">
       <el-col :span="12">
         <el-tooltip placement="top" content="转曲" :hide-after="0">
-          <el-button class="full-button" @click="handleElementCurve">
+          <el-button class="full-button" @click="handleElementCurveEx">
             <IconTextStyleOne/>
           </el-button>
         </el-tooltip>
@@ -451,17 +451,17 @@ const handleElementCharSpacing = (mode: '+' | '-') => {
 
 const changeLineHeight = (lineHeight: number) => {
   if (handleElement.value.isEditing) {
-    handleElement.value.setSelectionStyles({lineHeight})
+    handleElement.value.setSelectionStyles({lineHeight: lineHeight})
   } else {
-    templatesStore.modifedElement(handleElement.value, {lineHeight})
+    templatesStore.modifedElement(handleElement.value, {lineHeight: lineHeight})
   }
 }
 
 const changeCharSpacing = (charSpacing: number) => {
   if (handleElement.value.isEditing) {
-    handleElement.value.setSelectionStyles({charSpacing})
+    handleElement.value.setSelectionStyles({charSpacing: charSpacing})
   } else {
-    templatesStore.modifedElement(handleElement.value, {charSpacing})
+    templatesStore.modifedElement(handleElement.value, {charSpacing: charSpacing})
   }
 
   canvas.renderAll()
@@ -506,6 +506,27 @@ const handleElementCurve = async () => {
   canvas.renderAll()
 }
 
+const handleElementCurveEx = async () => {
+  // ElMessage
+  let fontElement: opentype.Font | undefined
+  const currentFont = onlineFonts.value.filter(item => item.fontFamily === hasFontFamily.value)[0]
+  if (currentFont) {
+    const fontURL = currentFont.fontFilePath
+    fontElement = await opentype.load(fontURL)
+  } else {
+    const fontData = await loadFont(hasFontFamily.value)
+    if (!fontData) return
+    const fontBlob = await fontData.blob()
+    const fontBuffer = await fontBlob.arrayBuffer()
+    fontElement = opentype.parse(fontBuffer)
+  }
+  if (!fontElement) return
+  const path = fontElement.getPath(handleElement.value.text, 0, 0, handleElement.value.fontSize);
+  createPathElement(path.toPathData(2), handleElement.value.left, handleElement.value.top)
+  canvas.remove(handleElement.value)
+  canvas.renderAll()
+}
+
 const handleElementDeformation = () => {
   const options = (handleElement.value as any).toObject(propertiesToInclude as any[]) as any
   options.originType = options.type

+ 49 - 2
src/views/Editor/computer.vue

@@ -36,15 +36,21 @@ import CanvasAffix from "./CanvasAffix/index.vue";
 import CanvasDom from "./CanvasDom/index.vue";
 import CanvasTour from "./CanvasTour/index.vue";
 
-import {onMounted} from "vue";
+import {computed, onMounted} from "vue";
 import router from "@/router";
 import {getCurrentUserTokenInfo} from "@/api/sys";
 import {setToken} from "@/utils/js-cookie";
 import {ElMessage} from "element-plus";
-import {useMainStore} from "@/store";
+import {useMainStore, useUserStore} from "@/store";
+import useCanvasExport from "@/hooks/useCanvasExport";
+import {newDesignOrder} from "@/api/template";
+import {storeToRefs} from "pinia";
 
 const mainStore = useMainStore();
+const userStore = useUserStore();
+const {uuid} = storeToRefs(userStore);
 const runMode = ref(0);
+const {getSVGDataEx, getSVGData} = useCanvasExport()
 
 onMounted(async () => {
   const query = router.currentRoute.value.query
@@ -70,6 +76,47 @@ onMounted(async () => {
         setToken('dataSourceId', response.data.dataSourceId)
       }
     });
+  } else if (runMode.value == 0) {
+    if (!query.sessionId) {
+      ElMessage.error('未传入用户标识,当前设计无法保存')
+      return
+    }
+    userStore.setUUID(query.sessionId)
+
+    // 使用iframe方案,本网页是内嵌页面
+    // 监听来自父页面的消息
+    window.addEventListener("message", function (event) {
+      // 确保消息来自信任的来源
+      // if (event.origin !== "https://sd2000.com") {
+      //   return;
+      // }
+
+      // 处理接收到的消息
+      console.log("Received message:", event.data);
+
+      //消息格式
+      // {
+      //   msgType: 'submitOrder'
+      // }
+      const message = JSON.parse(event.data);
+
+      if (message.msgType == "submitOrder") {
+        //提交当前设计
+        // const svgData: string[] = []
+        // svgData.push(btoa(unescape(encodeURIComponent(getSVGData()))))
+
+        // exportSVG()
+        const svgHtml = getSVGData()
+        console.log(svgHtml)
+        newDesignOrder(svgHtml, uuid.value).then((response) => {
+          if (response.httpCode == 200) {
+            console.log(response.data)
+            // 下载文件or直接后台拷贝至固定路径
+          }
+        });
+
+      }
+    });
   }
   mainStore.getFonts();
 })