Veronique 1 gadu atpakaļ
vecāks
revīzija
98eed56074

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "gifler": "^0.1.0",
     "html-to-image": "^1.11.11",
     "jsbarcode": "^3.11.6",
+    "js-cookie": "^3.0.5",
     "lodash-es": "^4.17.21",
     "mousetrap": "^1.6.5",
     "nanoid": "^5.0.3",

+ 9 - 0
pnpm-lock.yaml

@@ -68,6 +68,9 @@ dependencies:
   html-to-image:
     specifier: ^1.11.11
     version: 1.11.11
+  js-cookie:
+    specifier: ^3.0.5
+    version: 3.0.5
   jsbarcode:
     specifier: ^3.11.6
     version: 3.11.6
@@ -3443,6 +3446,7 @@ packages:
   /agent-base@6.0.2:
     resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
     engines: {node: '>= 6.0.0'}
+    requiresBuild: true
     dependencies:
       debug: 4.3.7
     transitivePeerDependencies:
@@ -6058,6 +6062,11 @@ packages:
     resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
     dev: true
 
+  /js-cookie@3.0.5:
+    resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+    engines: {node: '>=14'}
+    dev: false
+
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
     dev: true

+ 5 - 6
src/api/static/font.ts

@@ -1,11 +1,10 @@
 import request from '@/utils/request'
-import { QueryFont, FontInfoResult } from './types'
-import { AxiosPromise } from 'axios'
 
-export const getFontInfo = (params?: QueryFont): AxiosPromise<FontInfoResult> => {
+//获取当前用户token
+export function getDesignFonts(data: any): any {
   return request({
-    url: 'api/design/font/info',
-    method: 'get',
-    params,
+    url: "apis10/design/getDesignFonts",
+    method: "post",
+    params: data,
   });
 }

+ 10 - 0
src/api/sys/index.ts

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+//获取当前用户token
+export function getCurrentUserTokenInfo(data: any): any {
+    return request({
+        url: "apis10/design/getCurrentUserTokenInfo",
+        method: "post",
+        params: data,
+    });
+}

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

@@ -25,3 +25,19 @@ export const getTemplateData = (pk: number): AxiosPromise<TemplateInfo> => {
     method: 'get',
   })
 }
+
+export function getDesignTemplateEdit(data: any): any {
+  return request({
+    url: "apis10/design/getDesignTemplateEdit",
+    method: "post",
+    params: data,
+  });
+}
+
+export function updateDesignTemplate(data: any): any {
+  return request({
+    url: "apis10/design/updateDesignTemplate",
+    method: "post",
+    data: data,
+  });
+}

+ 82 - 12
src/components/FileInput.vue

@@ -1,19 +1,89 @@
 <template>
-  <div class="file-input" @click="handleClick()">
-    <slot></slot>
-    <input 
-      class="input"
-      type="file" 
-      name="upload" 
-      ref="inputRef" 
-      :accept="accept" 
-      @change="$event => handleChange($event)"
-    >
-  </div>
+  <!--  <div class="file-input" @click="handleClick()">-->
+  <!--    <slot></slot>-->
+  <!--    <input -->
+  <!--      class="input"-->
+  <!--      type="file" -->
+  <!--      name="upload" -->
+  <!--      ref="inputRef" -->
+  <!--      :accept="accept" -->
+  <!--      @change="$event => handleChange($event)"-->
+  <!--    >-->
+  <!--  </div>-->
+  <el-upload
+      ref="upload"
+      :multiple="false"
+      class="avatar-uploader"
+      action="apis10/upload/bucketFile"
+      :headers="headers"
+      :show-file-list="false"
+      accept=".jpg,.png"
+      :on-exceed="handleExceed"
+      :before-upload="beforeUpload"
+      :on-success="successFile"
+      :data="uploadParams"
+  >
+    <template #trigger>
+      <el-button type="primary">
+        <!--        <i-ep-Picture/>&nbsp;&nbsp;-->
+        <el-icon>
+          <UploadFilled/>
+        </el-icon>
+      </el-button>
+    </template>
+  </el-upload>
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
+import {ref} from 'vue'
+import {ElMessage, genFileId, UploadInstance, UploadProps, UploadRawFile} from "element-plus";
+import {UploadFilled} from "@element-plus/icons-vue";
+import {getToken} from "@/utils/js-cookie";
+
+//el-upload
+const upload = ref<UploadInstance>();
+const headers = ref({
+  "X-ERP-User-From": 10,
+  "X-ERP-DataSource-Id": getToken("dataBaseAlias"),
+  "X-ERP-Supplier-Code": getToken("shardingKey"),
+  "X-Token": getToken("token"),
+});
+const uploadParams = reactive({
+  srcfilename: "",
+  chunks: 1,
+  bucketName: "webImage",
+});
+const handleExceed: UploadProps["onExceed"] = (files) => {
+  upload.value!.clearFiles();
+  const file = files[0] as UploadRawFile;
+  file.uid = genFileId();
+  upload.value!.handleStart(file);
+};
+
+function beforeUpload(file) {
+  console.log(file);
+  uploadParams.srcfilename = file.name;
+  return new Promise((resolve, reject) => {
+    if (file.size > 307200) {
+      ElMessage.warning(
+          "图片大小不能大于300KB,请您注意图片的长和宽,网页图片的分辨率为72"
+      );
+      reject();
+    } else {
+      resolve(file);
+    }
+  });
+}
+
+function successFile(res, file, fileList) {
+  // console.log(res);
+  // formData.posterLocationImage = res.fileLink
+  // formData.fontThumbUrl = res.url;
+
+  if (res) emit('change', res)
+  ElMessage.success("上传成功");
+}
+
 
 defineProps({
   accept: {

+ 219 - 205
src/store/modules/main.ts

@@ -1,218 +1,232 @@
-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 { getSupportFonts } from '@/utils/fonts'
-import { CanvasElement } from '@/types/canvas'
-import { RightStates, PointElement, ImageCategoryData } from '@/types/elements'
-import { ExportTypes, PoolType, SystemFont } from '@/types/common'
-import { getFontInfo } from '@/api/static/font'
-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 {getSupportFonts} from '@/utils/fonts'
+import {CanvasElement} from '@/types/canvas'
+import {RightStates, PointElement, ImageCategoryData} from '@/types/elements'
+import {ExportTypes, PoolType, SystemFont} from '@/types/common'
+import {getDesignFonts, getFontInfo} from '@/api/static/font'
+import {FontInfo} from '@/api/static/types'
 import useCanvas from '@/views/Canvas/useCanvas'
 
 export interface MainState {
-  canvasObject: FabricObject | undefined
-  hoveredObject: FabricObject | undefined 
-  leavedObject: FabricObject | undefined 
-  clonedObject: FabricObject | undefined
-  currentPoint: PointElement | null
-  rightState: RightStates
-  imageCategoryType: string[]
-  imageCategoryData: ImageCategoryData[]
-  illustrationCategoryType: string[]
-  illustrationCategoryData: ImageCategoryData[]
-  handleElementId: string
-  sizeMode: number
-  unitMode: number
-  gridColorSelf: [string[]]
-  databaseId: string
-  selectedTemplatesIndex: number[]
-  thumbnailsFocus: boolean
-  drawAreaFocus: boolean
-  systemFonts: SystemFont[]
-  onlineFonts: SystemFont[]
-  disableHotkeys: boolean
-  exportType: ExportTypes
-  lastHelp: PoolType
-  lastEdit: PoolType
-  poolType: PoolType
-  poolShow: boolean
+    canvasObject: FabricObject | undefined
+    hoveredObject: FabricObject | undefined
+    leavedObject: FabricObject | undefined
+    clonedObject: FabricObject | undefined
+    currentPoint: PointElement | null
+    rightState: RightStates
+    imageCategoryType: string[]
+    imageCategoryData: ImageCategoryData[]
+    illustrationCategoryType: string[]
+    illustrationCategoryData: ImageCategoryData[]
+    handleElementId: string
+    sizeMode: number
+    unitMode: number
+    gridColorSelf: [string[]]
+    databaseId: string
+    selectedTemplatesIndex: number[]
+    thumbnailsFocus: boolean
+    drawAreaFocus: boolean
+    systemFonts: SystemFont[]
+    onlineFonts: SystemFont[]
+    disableHotkeys: boolean
+    exportType: ExportTypes
+    lastHelp: PoolType
+    lastEdit: PoolType
+    poolType: PoolType
+    poolShow: boolean
 }
 
 const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')
 export const databaseId = nanoid(10)
 
 export const useMainStore = defineStore('main', {
-  state: (): MainState => ({
-    canvasObject: undefined,
-    clonedObject: undefined,
-    hoveredObject: undefined,
-    leavedObject: undefined,
-    currentPoint: null,
-    rightState: RightStates.ELEMENT_CANVAS,
-    imageCategoryType: [],
-    imageCategoryData: ImageCategoryInfo,
-    illustrationCategoryType: [],
-    illustrationCategoryData: ImageCategoryInfo,
-    handleElementId: '', // 正在操作的元素ID
-    sizeMode: 0,  // 模板样式
-    unitMode: 0,  // 单位
-    gridColorSelf: [[]], // 自定义颜色
-    databaseId, // 标识当前应用的indexedDB数据库ID
-    selectedTemplatesIndex: [],
-    thumbnailsFocus: false, // 左侧导航缩略图区域聚焦
-    drawAreaFocus: false, // 编辑区聚焦
-    systemFonts: SYS_FONTS, // 系统字体
-    onlineFonts: [], // 在线字体
-    disableHotkeys: false, // 禁用快捷键
-    exportType: 'image', // 导出面板
-    lastEdit: 'editor', // 左边栏
-    lastHelp: 'editor', // 左边栏
-    poolType: 'editor', // 左边栏
-    poolShow: false, // 显示左边栏
-  }),
-
-  getters: {
-    activeElementList() {
-    //   const slidesStore = useSlidesStore()
-    //   const currentSlide = slidesStore.currentSlide
-    //   if (!currentSlide || !currentSlide.elements) return []
-    },
-  
-    handleElement() {
-    //   const slidesStore = useSlidesStore()
-    //   const currentSlide = slidesStore.currentSlide
-    //   if (!currentSlide || !currentSlide.elements) return null
-    //   return currentSlide.elements.find(element => state.handleElementId === element.id) || null
-    },
-  },
-
-  actions: {
-    
-    setCanvasObject(canvasObject: FabricObject | undefined) {
-      this.canvasObject = canvasObject
-      // this.getFonts()
-    },
-
-    setHoveredObject(hoveredObject: FabricObject | undefined) {
-      this.hoveredObject = hoveredObject
-    },
-
-    setLeaveddObject(leavedObject: FabricObject | undefined) {
-      this.leavedObject = leavedObject
-    },
-
-    setActiveObject() {
-      const [ canvas ] = useCanvas()
-      if (!canvas) return
-      const activeObject = canvas._activeObject as CanvasElement | null
-    },
-    // setHandleElementId(handleElementId: string) {
-    //   this.handleElementId = handleElementId
-    // },
-    
-    // setActiveGroupElementId(activeGroupElementId: string) {
-    //   this.activeGroupElementId = activeGroupElementId
-    // },
-    
-    // setHiddenElementIdList(hiddenElementIdList: string[]) {
-    //   this.hiddenElementIdList = hiddenElementIdList
-    // },
-  
-    // setCanvasDragged(isDragged: boolean) {
-    //   this.canvasDragged = isDragged
-    // },
-    setPoolType(poolType: PoolType) {
-      if (poolType === 'help') this.lastHelp = this.poolType
-      // if (poolType === 'editor') this.lastEdit = this.poolType
-      this.poolType = poolType
-    },
-
-    setRightState(rightState: RightStates) {
-      this.rightState = rightState
-    },
-  
-    setThumbnailsFocus(isFocus: boolean) {
-      this.thumbnailsFocus = isFocus
+    state: (): MainState => ({
+        canvasObject: undefined,
+        clonedObject: undefined,
+        hoveredObject: undefined,
+        leavedObject: undefined,
+        currentPoint: null,
+        rightState: RightStates.ELEMENT_CANVAS,
+        imageCategoryType: [],
+        imageCategoryData: ImageCategoryInfo,
+        illustrationCategoryType: [],
+        illustrationCategoryData: ImageCategoryInfo,
+        handleElementId: '', // 正在操作的元素ID
+        sizeMode: 0,  // 模板样式
+        unitMode: 0,  // 单位
+        gridColorSelf: [[]], // 自定义颜色
+        databaseId, // 标识当前应用的indexedDB数据库ID
+        selectedTemplatesIndex: [],
+        thumbnailsFocus: false, // 左侧导航缩略图区域聚焦
+        drawAreaFocus: false, // 编辑区聚焦
+        systemFonts: SYS_FONTS, // 系统字体
+        onlineFonts: [], // 在线字体
+        disableHotkeys: false, // 禁用快捷键
+        exportType: 'image', // 导出面板
+        lastEdit: 'editor', // 左边栏
+        lastHelp: 'editor', // 左边栏
+        poolType: 'editor', // 左边栏
+        poolShow: false, // 显示左边栏
+    }),
+
+    getters: {
+        activeElementList() {
+            //   const slidesStore = useSlidesStore()
+            //   const currentSlide = slidesStore.currentSlide
+            //   if (!currentSlide || !currentSlide.elements) return []
+        },
+
+        handleElement() {
+            //   const slidesStore = useSlidesStore()
+            //   const currentSlide = slidesStore.currentSlide
+            //   if (!currentSlide || !currentSlide.elements) return null
+            //   return currentSlide.elements.find(element => state.handleElementId === element.id) || null
+        },
     },
 
-    getFonts() {
-      this.getSystemFonts()
-      this.getOnlineFonts()
+    actions: {
+
+        setCanvasObject(canvasObject: FabricObject | undefined) {
+            this.canvasObject = canvasObject
+            // this.getFonts()
+        },
+
+        setHoveredObject(hoveredObject: FabricObject | undefined) {
+            this.hoveredObject = hoveredObject
+        },
+
+        setLeaveddObject(leavedObject: FabricObject | undefined) {
+            this.leavedObject = leavedObject
+        },
+
+        setActiveObject() {
+            const [canvas] = useCanvas()
+            if (!canvas) return
+            const activeObject = canvas._activeObject as CanvasElement | null
+        },
+        // setHandleElementId(handleElementId: string) {
+        //   this.handleElementId = handleElementId
+        // },
+
+        // setActiveGroupElementId(activeGroupElementId: string) {
+        //   this.activeGroupElementId = activeGroupElementId
+        // },
+
+        // setHiddenElementIdList(hiddenElementIdList: string[]) {
+        //   this.hiddenElementIdList = hiddenElementIdList
+        // },
+
+        // setCanvasDragged(isDragged: boolean) {
+        //   this.canvasDragged = isDragged
+        // },
+        setPoolType(poolType: PoolType) {
+            if (poolType === 'help') this.lastHelp = this.poolType
+            // if (poolType === 'editor') this.lastEdit = this.poolType
+            this.poolType = poolType
+        },
+
+        setRightState(rightState: RightStates) {
+            this.rightState = rightState
+        },
+
+        setThumbnailsFocus(isFocus: boolean) {
+            this.thumbnailsFocus = isFocus
+        },
+
+        getFonts() {
+            this.getSystemFonts()
+            this.getOnlineFonts()
+        },
+
+        getSystemFonts() {
+            this.systemFonts = getSupportFonts(SYS_FONTS)
+        },
+
+        async getOnlineFonts() {
+            // const res = await getFontInfo()
+            // if (res.data.code === 200) {
+            //   // this.onlineFonts = res.data.data
+            //   const style = document.createElement("style");
+            //   style.type = "text/css";
+            //   res.data.data.forEach(fontInfo => {
+            //     this.onlineFonts.push({label: fontInfo.fontname, value: fontInfo.fontname})
+            //     style.appendChild(document.createTextNode(
+            //       `@font-face {font-family: '${fontInfo.fontname}'; src: url(${fontInfo.url}) format('truetype');}`
+            //     ));
+            //   })
+            //   document.head.appendChild(style);
+            // }
+
+            getDesignFonts({}).then((response: any) => {
+                if (response.httpCode == 200) {
+                    this.onlineFonts = response.data
+                    const style = document.createElement("style");
+                    style.type = "text/css";
+                    response.data.forEach(fontInfo => {
+                        style.appendChild(document.createTextNode(
+                            `@font-face {font-family: '${fontInfo.fontName}'; src: url(${fontInfo.fontFilePath}) format('truetype');}`
+                        ));
+                    })
+                    document.head.appendChild(style);
+                }
+            });
+        },
+
+        setExportType(type: ExportTypes) {
+            this.exportType = type
+        },
+
+        setDrawAreaFocus(status: boolean) {
+            this.drawAreaFocus = status
+        },
+
+        // setDisableHotkeysState(disable: boolean) {
+        //   this.disableHotkeys = disable
+        // },
+
+        // setGridLineSize(size: number) {
+        //   this.gridLineSize = size
+        // },
+
+        // setRulerState(show: boolean) {
+        //   this.showRuler = show
+        // },
+
+        // setClipingImageElementId(elId: string) {
+        //   this.clipingImageElementId = elId
+        // },
+
+        // setSelectedTableCells(cells: string[]) {
+        //   this.selectedTableCells = cells
+        // },
+
+        // setScalingState(isScaling: boolean) {
+        //   this.isScaling = isScaling
+        // },
+
+        updateSelectedTemplatesIndex(selectedTemplatesIndex: number[]) {
+            this.selectedTemplatesIndex = selectedTemplatesIndex
+        },
+
+        // setDialogForColor(show: boolean) {
+        //   this.dialogForColor = show
+        // },
+
+        // saveDialogForColor(colors: string[]) {
+        //   this.dialogForColor = false
+        //   this.colorSelfStore.push(colors)
+        // },
+
+        // setDialogForTemplate(show: boolean) {
+        //   this.dialogForTemplate = show
+        // },
+
+        // setSelectPanelState(show: boolean) {
+        //   this.showSelectPanel = show
+        // },
     },
-
-    getSystemFonts() {
-      this.systemFonts = getSupportFonts(SYS_FONTS)
-    },
-
-    async getOnlineFonts() {
-      const res = await getFontInfo()
-      if (res.data.code === 200) {
-        // this.onlineFonts = res.data.data
-        const style = document.createElement("style");
-        style.type = "text/css";
-        res.data.data.forEach(fontInfo => {
-          this.onlineFonts.push({label: fontInfo.fontname, value: fontInfo.fontname})
-          style.appendChild(document.createTextNode(
-            `@font-face {font-family: '${fontInfo.fontname}'; src: url(${fontInfo.url}) format('truetype');}`
-          ));
-        })
-        document.head.appendChild(style);
-      }
-    },
-    
-    setExportType(type: ExportTypes) {
-      this.exportType = type
-    },
-
-    setDrawAreaFocus(status: boolean) {
-      this.drawAreaFocus = status
-    },
-  
-    // setDisableHotkeysState(disable: boolean) {
-    //   this.disableHotkeys = disable
-    // },
-  
-    // setGridLineSize(size: number) {
-    //   this.gridLineSize = size
-    // },
-  
-    // setRulerState(show: boolean) {
-    //   this.showRuler = show
-    // },
-
-    // setClipingImageElementId(elId: string) {
-    //   this.clipingImageElementId = elId
-    // },
-  
-    // setSelectedTableCells(cells: string[]) {
-    //   this.selectedTableCells = cells
-    // },
-  
-    // setScalingState(isScaling: boolean) {
-    //   this.isScaling = isScaling
-    // },
-    
-    updateSelectedTemplatesIndex(selectedTemplatesIndex: number[]) {
-      this.selectedTemplatesIndex = selectedTemplatesIndex
-    },
-
-    // setDialogForColor(show: boolean) {
-    //   this.dialogForColor = show
-    // },
-
-    // saveDialogForColor(colors: string[]) {
-    //   this.dialogForColor = false
-    //   this.colorSelfStore.push(colors)
-    // },
-
-    // setDialogForTemplate(show: boolean) {
-    //   this.dialogForTemplate = show
-    // },
-
-    // setSelectPanelState(show: boolean) {
-    //   this.showSelectPanel = show
-    // },
-  },
 })

+ 6 - 0
src/store/modules/template.ts

@@ -23,6 +23,7 @@ interface UpdateElementData {
 
 export interface TemplatesState {
   templateId: string
+  templateName: string
   templates: Template[]
   templateIndex: number
   templateCanvas: Map<string, StaticCanvas>
@@ -32,6 +33,7 @@ export const useTemplatesStore = defineStore('Templates', {
   state: (): TemplatesState => ({
     // theme: theme, // 主题样式
     templateId: '',
+    templateName: '空白模板',
     templates: Templates, // 页面页面数据
     templateIndex: 0, // 当前页面索引
     templateCanvas: new Map()
@@ -228,6 +230,10 @@ export const useTemplatesStore = defineStore('Templates', {
       this.templateId = templateId
     },
 
+    setTemplateName(templateName:string){
+      this.templateName = templateName
+    },
+
     setTemplateIndex(index: number) {
       this.templateIndex = index
     },

+ 172 - 170
src/types/elements.ts

@@ -1,258 +1,260 @@
-import { ImageHit } from "@/api/static/types"
-import { XY } from "fabric"
-import { ImageElement } from "./canvas"
+import {ImageHit} from "@/api/static/types"
+import {XY} from "fabric"
+import {ImageElement} from "./canvas"
 
 export const enum ElementNames {
-  TEXTBOX = 'textbox',
-  TEXT = 'text',
-  ITEXT = 'i-text',
-  INPUTTEXT = 'itext',
-  ARCTEXT = 'arctext',
-  VERTICALTEXT = 'verticaltext',
-  IMAGE = 'image',
-  SVGIMAGE = 'svgimage',
-  CROPIMAGE = 'cropimage',
-  MASK = 'mask',
-  PATH = 'path',
-  RECT = 'rect',
-  LINE = 'line',
-  ARROW = 'arrow',
-  POLYLINE = 'polyline',
-  ELLIPSE = 'ellipse',
-  QRCODE = 'qrcode',
-  BARCODE = 'barcode',
-  GROUP = 'group',
-  ACTIVE = 'activeselection',
-  CIRCLE = 'circle',
-  REFERENCELINE = 'referenceline',
-  DOT = 'dot',
+    TEXTBOX = 'textbox',
+    TEXT = 'text',
+    ITEXT = 'i-text',
+    INPUTTEXT = 'itext',
+    ARCTEXT = 'arctext',
+    VERTICALTEXT = 'verticaltext',
+    IMAGE = 'image',
+    SVGIMAGE = 'svgimage',
+    CROPIMAGE = 'cropimage',
+    MASK = 'mask',
+    PATH = 'path',
+    RECT = 'rect',
+    LINE = 'line',
+    ARROW = 'arrow',
+    POLYLINE = 'polyline',
+    ELLIPSE = 'ellipse',
+    QRCODE = 'qrcode',
+    BARCODE = 'barcode',
+    GROUP = 'group',
+    ACTIVE = 'activeselection',
+    CIRCLE = 'circle',
+    REFERENCELINE = 'referenceline',
+    DOT = 'dot',
 }
 
 export const SupportEffects = [
-  'group',
-  'activeselection',
-  'itext',
-  'text',
-  'textbox',
-  'image',
+    'group',
+    'activeselection',
+    'itext',
+    'text',
+    'textbox',
+    'image',
 ]
 
 export interface ColorStop {
-  color: string
-  offset: number
-  opacity?: number
+    color: string
+    offset: number
+    opacity?: number
 }
 
 /**
  * 形状渐变
- * 
+ *
  * type: 渐变类型(径向、线性)
- * 
+ *
  * color: 渐变颜色
- * 
+ *
  * rotate: 渐变角度(线性渐变)
  */
- export interface PathGradient {
-  type: 'linear' | 'radial'
-  name: string
-  color: string[]
-  rotate: number
+export interface PathGradient {
+    type: 'linear' | 'radial'
+    name: string
+    color: string[]
+    rotate: number
 }
 
 
-export type LinePoint = '' | 'arrow' | 'dot' 
+export type LinePoint = '' | 'arrow' | 'dot'
 
 export interface Mask extends ImageElement {
-  src: string
-  defaultColor: number
+    src: string
+    defaultColor: number
 }
 
 export interface LinePoolItem {
-  path: string
-  style: 'solid' | 'dashed'
-  points: [LinePoint, LinePoint]
-  data: XY[]
-  isBroken?: boolean
-  isCurve?: boolean
-  isCubic?: boolean
+    path: string
+    style: 'solid' | 'dashed'
+    points: [LinePoint, LinePoint]
+    data: XY[]
+    isBroken?: boolean
+    isCurve?: boolean
+    isCubic?: boolean
 }
 
 export const enum ShapePathFormulasKeys {
-  ROUND_RECT = 'roundRect',
-  ROUND_RECT_DIAGONAL = 'roundRectDiagonal',
-  ROUND_RECT_SINGLE = 'roundRectSingle',
-  ROUND_RECT_SAMESIDE = 'roundRectSameSide',
-  CUT_RECT_DIAGONAL = 'cutRectDiagonal',
-  CUT_RECT_SINGLE = 'cutRectSingle',
-  CUT_RECT_SAMESIDE = 'cutRectSameSide',
-  MESSAGE = 'message',
-  ROUND_MESSAGE = 'roundMessage',
-  L = 'L',
-  RING_RECT = 'ringRect',
-  PLUS = 'plus',
-  TRIANGLE = 'triangle',
-  PARALLELOGRAM_LEFT = 'parallelogramLeft',
-  PARALLELOGRAM_RIGHT = 'parallelogramRight',
-  TRAPEZOID = 'trapezoid',
-  BULLET = 'bullet',
-  INDICATOR = 'indicator',
+    ROUND_RECT = 'roundRect',
+    ROUND_RECT_DIAGONAL = 'roundRectDiagonal',
+    ROUND_RECT_SINGLE = 'roundRectSingle',
+    ROUND_RECT_SAMESIDE = 'roundRectSameSide',
+    CUT_RECT_DIAGONAL = 'cutRectDiagonal',
+    CUT_RECT_SINGLE = 'cutRectSingle',
+    CUT_RECT_SAMESIDE = 'cutRectSameSide',
+    MESSAGE = 'message',
+    ROUND_MESSAGE = 'roundMessage',
+    L = 'L',
+    RING_RECT = 'ringRect',
+    PLUS = 'plus',
+    TRIANGLE = 'triangle',
+    PARALLELOGRAM_LEFT = 'parallelogramLeft',
+    PARALLELOGRAM_RIGHT = 'parallelogramRight',
+    TRAPEZOID = 'trapezoid',
+    BULLET = 'bullet',
+    INDICATOR = 'indicator',
 }
 
 export interface PathPoolItem {
-  viewBox: [number, number]
-  path: string
-  special?: boolean
-  pathFormula?: ShapePathFormulasKeys
-  outlined?: boolean
+    viewBox: [number, number]
+    path: string
+    special?: boolean
+    pathFormula?: ShapePathFormulasKeys
+    outlined?: boolean
 }
 
 export interface PathListItem {
-  type: string
-  children: PathPoolItem[]
+    type: string
+    children: PathPoolItem[]
 }
 
 export interface verticalLine {
-  x: number
-  y1: number
-  y2: number
+    x: number
+    y1: number
+    y2: number
 }
+
 export interface horizontalLine {
-  y: number
-  x1: number
-  x2: number
+    y: number
+    x1: number
+    x2: number
 }
 
 // 边框矩形
 export interface StrokeRect {
-  x: number,
-  y: number,
-  w: number,
-  h: number
+    x: number,
+    y: number,
+    w: number,
+    h: number
 }
 
 export interface AngleRect {
-  x: number
-  y: number
-  w: number
-  h: number
+    x: number
+    y: number
+    w: number
+    h: number
 }
 
 export interface ElementStrokeRect {
-  id: string
-  strokeRect: StrokeRect
+    id: string
+    strokeRect: StrokeRect
 }
 
 // 渐变背景填充坐标
 export interface GradientCoords {
-  x1: number
-  y1: number
-  x2: number
-  y2: number,
-  r1?: number,
-  r2?: number
+    x1: number
+    y1: number
+    x2: number
+    y2: number,
+    r1?: number,
+    r2?: number
 }
 
 export interface PointElement {
-  x: number,
-  y: number
+    x: number,
+    y: number
 }
 
 export const enum RightStates {
-  ELEMENT_CANVAS = 'design',
-  ELEMENT_TEXT = 'text',
-  ELEMENT_SVG = 'path',
-  ELEMENT_IMAGE = 'image',
-  ELEMENT_CODE = 'code',
-  ELEMENT_STYLE = 'style',
-  ELEMENT_POSITION = 'position',
-  ELEMENT_LAYER = 'layer',
-  ELEMENT_EFFECT = 'effect',
+    ELEMENT_CANVAS = 'design',
+    ELEMENT_TEXT = 'text',
+    ELEMENT_SVG = 'path',
+    ELEMENT_IMAGE = 'image',
+    ELEMENT_CODE = 'code',
+    ELEMENT_STYLE = 'style',
+    ELEMENT_POSITION = 'position',
+    ELEMENT_LAYER = 'layer',
+    ELEMENT_EFFECT = 'effect',
 }
 
 // 底纹背景元素
 export interface ShadingColorLib {
-  title: string
-  slug: string
-  mode: string
-  colors: number
-  maxStroke: number
-  maxScale: number
-  maxSpacing: number[]
-  width: number
-  height: number
-  vHeight: number
-  tags?: string[]
-  path: string
+    title: string
+    slug: string
+    mode: string
+    colors: number
+    maxStroke: number
+    maxScale: number
+    maxSpacing: number[]
+    width: number
+    height: number
+    vHeight: number
+    tags?: string[]
+    path: string
 }
 
 // 底纹背景填充
 export interface ShadingBackground {
-  id: number
-  colors: string[]
-  colorCounts: number
-  stroke: number
-  scale: number
-  spacing: number[]
-  angle: number
-  join: number
-  moveLeft: number
-  moveTop: number
+    id: number
+    colors: string[]
+    colorCounts: number
+    stroke: number
+    scale: number
+    spacing: number[]
+    angle: number
+    join: number
+    moveLeft: number
+    moveTop: number
 }
 
 // 字体类型
 export interface FontOption {
-  label: string
-  value: string
+    label: string
+    value: string
 }
 
 // 字体分组
 export interface FontGroupOption {
-  label: string
-  options: FontOption[]
+    type: number
+    label: string
+    options: any[]
 }
 
 // 条形码参数
 export interface BarCodeOption {
-  format: string
-  width?: number
-  height?: number
-  displayValue?: boolean   // 是否在条形码显示文字
-  fontOptions?: string     // 设置条形码文本的粗体和斜体样式 bold / italic / bold italic
-  font?: string            // 设置条形码显示文本的字体
-  fontSize?: number        // 设置条形码文本的字体大小
-  textAlign?: string       // 条形码文本的水平对齐方式,和css中的类似: left / center / right
-  textPosition?: string    // 条形码文本的位置 bottom / top
-  textMargin?: string      // 条形码文本 和 条形码之间的间隙大小
-  background?: string      // 整个条形码容器的背景颜色
-  lineColor?: string       // 条形码和文本的颜色
-  margin?: number          // 整个条形码的外面距
-  marginTop?: number       
-  marginBottom?: number    
-  marginLeft?: number      
-  marginRight?: number    
+    format: string
+    width?: number
+    height?: number
+    displayValue?: boolean   // 是否在条形码显示文字
+    fontOptions?: string     // 设置条形码文本的粗体和斜体样式 bold / italic / bold italic
+    font?: string            // 设置条形码显示文本的字体
+    fontSize?: number        // 设置条形码文本的字体大小
+    textAlign?: string       // 条形码文本的水平对齐方式,和css中的类似: left / center / right
+    textPosition?: string    // 条形码文本的位置 bottom / top
+    textMargin?: string      // 条形码文本 和 条形码之间的间隙大小
+    background?: string      // 整个条形码容器的背景颜色
+    lineColor?: string       // 条形码和文本的颜色
+    margin?: number          // 整个条形码的外面距
+    marginTop?: number
+    marginBottom?: number
+    marginLeft?: number
+    marginRight?: number
 }
 
 export const enum AlignCommand {
-  LEFT = 'left',
-  RIGHT = 'right',
-  HORIZONTAL = 'horizontal',
-  VERTICAL = 'vertical',
-  CENTER = 'center',
-  TOP = 'top',
-  BOTTOM = 'bottom',
+    LEFT = 'left',
+    RIGHT = 'right',
+    HORIZONTAL = 'horizontal',
+    VERTICAL = 'vertical',
+    CENTER = 'center',
+    TOP = 'top',
+    BOTTOM = 'bottom',
 }
 
 export const enum LayerCommand {
-  UP = 'left',
-  DOWN = 'right',
-  TOP = 'top',
-  BOTTOM = 'bottom',
+    UP = 'left',
+    DOWN = 'right',
+    TOP = 'top',
+    BOTTOM = 'bottom',
 }
 
 export interface ImageCategoryData {
-  id: number
-  type: string
-  name: string
-  category: ImageHit[]
-  total: ImageHit[]
+    id: number
+    type: string
+    name: string
+    category: ImageHit[]
+    total: ImageHit[]
 }

+ 16 - 0
src/utils/js-cookie.ts

@@ -0,0 +1,16 @@
+// @ts-ignore
+import Cookies from 'js-cookie'
+
+// const TokenKey = 'Access-Token'//后端存登陆信息的
+
+export function getToken(TokenKey:string) {
+  return Cookies.get(TokenKey)
+}
+
+export function setToken(TokenKey:string,token:string) {
+  return Cookies.set(TokenKey, token)
+}
+
+export function removeToken(TokenKey:string) {
+  return Cookies.remove(TokenKey)
+}

+ 49 - 69
src/utils/request.ts

@@ -1,84 +1,64 @@
-import axios, { AxiosResponse } from 'axios';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { localStorage } from '@/utils/storage';
-import { useUserStore } from '@/store';
-import { storeToRefs } from 'pinia';
-
+import axios, {InternalAxiosRequestConfig, AxiosResponse} from "axios";
+import {getToken, setToken, removeToken} from '@/utils/js-cookie'
+import {ElMessage, ElMessageBox} from "element-plus";
 // 创建 axios 实例
 const service = axios.create({
-  baseURL: import.meta.env.VITE_APP_BASE_API,
-  timeout: 500000,
-  headers: { 'Content-Type': 'application/json;charset=utf-8' },
+    baseURL: import.meta.env.VITE_APP_BASE_API,
+    timeout: 50000,
+    headers: {"Content-Type": "application/json;charset=utf-8"},
 });
 
 // 请求拦截器
 service.interceptors.request.use(
-  (config: any) => {
-    if (!config.headers) {
-      throw new Error(
-        `Expected 'config' and 'config.headers' not to be undefined`
-      );
-    }
-    const { loginStatus } = storeToRefs(useUserStore())
-    if (loginStatus && localStorage.get('access_token')) {
-      config.headers.Authorization = `Bearer ${localStorage.get('access_token')}`;
+    (config: InternalAxiosRequestConfig) => {
+        config.headers['X-ERP-User-From'] = 10;
+        if (getToken('token')) {
+            config.headers['X-Token'] = getToken('token');
+        }
+        if (getToken('dataBaseAlias')) {
+            config.headers['X-ERP-DataSource-Id'] = getToken('dataSourceId');
+        }
+        if (getToken('shardingKey')) {
+            config.headers['X-ERP-Supplier-Code'] = getToken('supplierCode');
+        }
+        return config;
+    },
+    (error: any) => {
+        return Promise.reject(error);
     }
-    return config;
-  },
-  (error: any) => {
-    return Promise.reject(error);
-  }
 );
 
 // 响应拦截器
 service.interceptors.response.use(
-  (response: AxiosResponse) => {
-    const { code, msg } = response.data;
-    if (code === 200) {
-      return response;
-    }
-    else if (code === 401) {
-      localStorage.remove('access_token')
-      return response;
-    }
-    else {
-      // 响应数据为二进制流处理(Excel导出)
-      if (response.data instanceof ArrayBuffer) {
-        return response;
-      }
-      if (response.data instanceof Array) {
-        return response;
-      }
-
-      ElMessage({
-        message: msg || '系统出错',
-        type: 'error',
-      });
-      return Promise.reject(new Error(msg || 'Error'));
-    }
-  },
-  (error: any) => {
-    if (error.response.data) {
-      const { detail } = error.response.data;
-      console.log('code:', error.response.data)
-      // token 过期,重新登录
-      if (detail === 'Signature has expired.') {
-        ElMessageBox.confirm('当前页面已失效,请重新登录', 'Warning', {
-          confirmButtonText: 'OK',
-          type: 'warning',
-        }).then(() => {
-          localStorage.clear();
-          window.location.href = '/';
-        });
-      } else {
-        ElMessage({
-          message: detail || '系统出错',
-          type: 'error',
-        });
-      }
+    (response: AxiosResponse) => {
+        const res = response.data
+        // console.log(res);
+        if (res.httpCode !== 200 && res.httpCode != undefined) {
+            ElMessage({
+                message: res.msg || res.data,
+                type: 'error',
+                duration: 5 * 1000,
+                showClose: true,
+            })
+            if (res.httpCode === 403 || res.httpCode === 401 || res.httpCode === 50014) {
+                // to re-login
+                ElMessageBox.confirm('您已注销,可以取消以留在此页,或重新登录', '确认?', {
+                    confirmButtonText: '重新登录',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    location.reload()
+                })
+            }
+            return Promise.reject(res)
+        } else {
+            return res
+        }
+    },
+    (error: any) => {
+        console.log('err' + error) // for debug
+        return Promise.reject(error)
     }
-    return Promise.reject(error.message);
-  }
 );
 
 // 导出 axios 实例

+ 25 - 8
src/views/Editor/CanvasCenter/index.vue

@@ -15,7 +15,7 @@ import {onMounted, onUnmounted} from 'vue'
 import {useFabricStore, useMainStore, useTemplatesStore} from '@/store'
 import {useRouter} from 'vue-router'
 import {unzip} from "@/utils/crypto"
-import {getTemplateData} from '@/api/template'
+import {getDesignTemplateEdit, getTemplateData} from '@/api/template'
 import {contextMenus} from '@/configs/contextMenu'
 import {initEditor} from '@/views/Canvas/useCanvas'
 import {initPixi} from '@/views/Canvas/usePixi'
@@ -40,14 +40,31 @@ const remDrawAreaFocus = () => {
 }
 
 const getTemplateDetail = async (pk: number) => {
-  const result = await getTemplateData(pk)
-  if (result.data && result.data.code === 200 && result.data.data) {
+  // const result = await getTemplateData(pk)
+  // if (result.data && result.data.code === 200 && result.data.data) {
+  //   try {
+  //     router.push(`${router.currentRoute.value.path}?template=${pk}`)
+  //     console.log('result.data.data.id:', result.data.data.id)
+  //     const data = unzip(result.data.data.data)
+  //     await templatesStore.changeTemplate(data)
+  //   } catch (error) {
+  //     ElMessage({
+  //       type: 'error',
+  //       message: '模板加载失败,请联系管理员修改bug了',
+  //     })
+  //   }
+  // }
+  const params = {
+    id: pk
+  }
+  const res = await getDesignTemplateEdit(params)
+
+  if (res.httpCode == 200) {
     try {
-      router.push(`${router.currentRoute.value.path}?template=${pk}`)
-      console.log('result.data.data.id:', result.data.data.id)
-      const data = unzip(result.data.data.data)
-      await templatesStore.changeTemplate(data)
-    } catch (error) {
+      templatesStore.setTemplateName(res.data.templateName)
+      const data = res.data.jsonContent
+      await templatesStore.changeTemplate(JSON.parse(data))
+    } catch (e) {
       ElMessage({
         type: 'error',
         message: '模板加载失败,请联系管理员修改bug了',

+ 5 - 4
src/views/Editor/CanvasLeft/Menu/components/ImagePool.vue

@@ -38,10 +38,11 @@ const { t } = useI18n();
 const { createImageElement } = useHandleCreate();
 
 const activeImage = ref("data");
-const drawImage = (files: FileList) => {
-  const imageFile = files[0];
-  if (!imageFile) return;
-  getImageDataURL(imageFile).then((dataURL) => createImageElement(dataURL));
+const drawImage = (files: any) => {
+  // const imageFile = files[0];
+  // if (!imageFile) return;
+  // getImageDataURL(imageFile).then((dataURL) => createImageElement(dataURL));
+  createImageElement(files.fileLink)
 };
 </script>
 

+ 12 - 9
src/views/Editor/CanvasRight/Backgrounds/index.vue

@@ -563,9 +563,11 @@ const shadingBackground = ref<ShadingBackground>(ShadingBackgroudInit);
 onMounted(async () => {
   const recentGridCache = localStorage.getItem(RECENT_GRIDS);
   if (recentGridCache) gridColorRecent.value = JSON.parse(recentGridCache);
-  const res = await getColorShading();
-  shadingColorLibs.value = res.data;
-  shadingColorLib.value = shadingColorLibs.value[0];
+  // const res = await getColorShading();
+  // if (res) {
+  //   shadingColorLibs.value = res.data;
+  //   shadingColorLib.value = shadingColorLibs.value[0];
+  // }
 });
 
 const background = computed(() => {
@@ -689,12 +691,13 @@ const changeBackgroundImage = async (imageURL: string) => {
 };
 
 // 上传背景图片
-const uploadBackgroundImage = (files: FileList) => {
-  const imageFile = files[0];
-  if (!imageFile) return;
-  getImageDataURL(imageFile).then((imageURL) => {
-    changeBackgroundImage(imageURL);
-  });
+const uploadBackgroundImage = (files: any) => {
+  // const imageFile = files[0];
+  // if (!imageFile) return;
+  // getImageDataURL(imageFile).then((imageURL) => {
+  //   changeBackgroundImage(imageURL);
+  // });
+  changeBackgroundImage(files.fileLink)
 };
 
 // 修改背景图片

+ 139 - 112
src/views/Editor/CanvasRight/ElementStylePanel/TextboxStylePanel.vue

@@ -1,43 +1,52 @@
 <template>
   <div class="text-style-panel">
     <ElementPosition/>
-    <el-divider style="margin: 12px 0" />
+    <el-divider style="margin: 12px 0"/>
     <el-row>
       <el-col :span="12">
         <el-select v-model="elementFontFamily" placement="left" @change="handleElementFontFamily">
           <el-option-group v-for="group in fontOptionGroups" :key="group.label" :label="group.label">
-            <el-option v-for="item in group.options" :key="item" :value="item.value" :label="item.label" :style="{fontFamily: item.value}"></el-option>
+            <template v-if="group.type == 0">
+              <el-option v-for="item in group.options" :key="item" :value="item.value" :label="item.label"
+                         :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-image style="height: 18px; width: 90px" :src="item.fontThumbUrl"></el-image>
+              </el-option>
+            </template>
           </el-option-group>
         </el-select>
       </el-col>
       <el-col :span="12">
-        <el-select 
-          v-model="handleElement.fontSize" 
-          filterable 
-          allow-create 
-          default-first-option 
-          :filterMethod="handleElementInputSize" 
-          placement="left" 
-          @change="handleElementFontSize"
+        <el-select
+            v-model="handleElement.fontSize"
+            filterable
+            allow-create
+            default-first-option
+            :filterMethod="handleElementInputSize"
+            placement="left"
+            @change="handleElementFontSize"
         >
           <el-option v-for="item in FontSizeLibs" :key="item" :label="item" :value="item"></el-option>
         </el-select>
       </el-col>
-    </el-row> 
-    
+    </el-row>
+
     <el-row class="mt-10">
       <el-col :span="6">
-        <el-tooltip placement="top" content="文字颜色" :hide-after="0" >
+        <el-tooltip placement="top" content="文字颜色" :hide-after="0">
           <div @click.stop class="tooltip-popover">
             <el-popover trigger="click" placement="bottom" :width="265" @click.stop>
               <template #reference>
                 <el-button class="font-color">
                   <TextColorButton :color="handleElement.color">
-                    <IconText />
+                    <IconText/>
                   </TextColorButton>
                 </el-button>
               </template>
-              <ColorPicker :modelValue="handleElement.color" @update:modelValue="(color: string) => updateFontColor(color)"/>
+              <ColorPicker :modelValue="handleElement.color"
+                           @update:modelValue="(color: string) => updateFontColor(color)"/>
             </el-popover>
           </div>
         </el-tooltip>
@@ -49,11 +58,12 @@
               <template #reference>
                 <el-button class="high-light">
                   <TextColorButton :color="elementBackgrounColor">
-                    <IconHighLight />
+                    <IconHighLight/>
                   </TextColorButton>
                 </el-button>
               </template>
-              <ColorPicker :modelValue="elementBackgrounColor" @update:modelValue="(color: string) => updateBackgroundColor(color)"/>
+              <ColorPicker :modelValue="elementBackgrounColor"
+                           @update:modelValue="(color: string) => updateBackgroundColor(color)"/>
             </el-popover>
           </div>
         </el-tooltip>
@@ -62,13 +72,15 @@
         <el-button-group class="full-group">
           <el-tooltip placement="top" content="增大字号" :hide-after="0">
             <el-button class="font-size" @click="handleElementFontsize('+')">
-              <IconFontSize />+
+              <IconFontSize/>
+              +
             </el-button>
           </el-tooltip>
 
           <el-tooltip placement="top" content="减小字号" :hide-after="0">
             <el-button @click="handleElementFontsize('-')">
-              <IconFontSize />-
+              <IconFontSize/>
+              -
             </el-button>
           </el-tooltip>
         </el-button-group>
@@ -79,22 +91,22 @@
       <div class="full-checkbox">
         <el-tooltip placement="top" content="加粗" :hide-after="0">
           <el-checkbox-button :value="hasFontWeight" @change="handleElementBlod()">
-            <IconTextBold />
+            <IconTextBold/>
           </el-checkbox-button>
         </el-tooltip>
         <el-tooltip placement="top" content="斜体" :hide-after="0">
           <el-checkbox-button v-model="hasFontStyle" @change="handleElementItalic()">
-            <IconTextItalic />
+            <IconTextItalic/>
           </el-checkbox-button>
         </el-tooltip>
         <el-tooltip placement="top" content="下划线" :hide-after="0">
           <el-checkbox-button v-model="hasUnderline" @change="handleElementUnderline()">
-            <IconTextUnderline />
+            <IconTextUnderline/>
           </el-checkbox-button>
         </el-tooltip>
         <el-tooltip placement="top" content="删除线" :hide-after="0">
           <el-checkbox-button v-model="hasLinethrough" @change="handleElementLinethrough()">
-            <IconStrikethrough />
+            <IconStrikethrough/>
           </el-checkbox-button>
         </el-tooltip>
       </div>
@@ -104,22 +116,22 @@
       <el-button-group class="full-group">
         <el-tooltip placement="top" content="横向" :hide-after="0">
           <el-button @click="handleElementArrange(false)" :type="elementGrapheme ? 'primary': ''">
-            <IconTextRotationNone />
+            <IconTextRotationNone/>
           </el-button>
         </el-tooltip>
         <el-tooltip placement="top" content="纵向" :hide-after="0">
           <el-button @click="handleElementArrange(true)" :type="!elementGrapheme ? 'primary': ''">
-            <IconTextRotationDown />
+            <IconTextRotationDown/>
           </el-button>
         </el-tooltip>
         <el-tooltip placement="top" content="减小缩进" :hide-after="0">
           <el-button @click="handleElementCharSpacing('-')">
-            <IconIndentLeft />
+            <IconIndentLeft/>
           </el-button>
         </el-tooltip>
         <el-tooltip placement="top" content="增大缩进" :hide-after="0">
           <el-button @click="handleElementCharSpacing('+')">
-            <IconIndentRight />
+            <IconIndentRight/>
           </el-button>
         </el-tooltip>
       </el-button-group>
@@ -130,22 +142,22 @@
         <el-radio-group class="full-ratio" v-model="textAlign" @change="handleTextAlign">
           <el-tooltip placement="top" content="左对齐" :hide-after="0">
             <el-radio-button value="justify-left">
-              <IconAlignTextLeft />
+              <IconAlignTextLeft/>
             </el-radio-button>
           </el-tooltip>
           <el-tooltip placement="top" content="居中" :hide-after="0">
             <el-radio-button value="justify-center">
-              <IconAlignTextCenter />
+              <IconAlignTextCenter/>
             </el-radio-button>
           </el-tooltip>
           <el-tooltip placement="top" content="右对齐" :hide-after="0">
             <el-radio-button value="justify-right">
-              <IconAlignTextRight />
+              <IconAlignTextRight/>
             </el-radio-button>
           </el-tooltip>
           <el-tooltip placement="top" content="两边对齐" :hide-after="0">
             <el-radio-button value="justify">
-              <IconAlignTextBoth />
+              <IconAlignTextBoth/>
             </el-radio-button>
           </el-tooltip>
         </el-radio-group>
@@ -156,14 +168,16 @@
       <el-col :span="12">
         <el-tooltip placement="top" content="转曲" :hide-after="0">
           <el-button class="full-button" @click="handleElementCurve">
-            <IconTextStyleOne />
+            <IconTextStyleOne/>
           </el-button>
         </el-tooltip>
       </el-col>
       <el-col :span="12">
         <el-tooltip placement="top" content="变形" :hide-after="0">
-          <el-button class="full-button" :type="handleElement.type.toLowerCase() === ElementNames.ARCTEXT ? 'primary' : ''" @click="handleElementDeformation">
-            <i class="handler-item iconfont icon-text-path" />
+          <el-button class="full-button"
+                     :type="handleElement.type.toLowerCase() === ElementNames.ARCTEXT ? 'primary' : ''"
+                     @click="handleElementDeformation">
+            <i class="handler-item iconfont icon-text-path"/>
           </el-button>
         </el-tooltip>
       </el-col>
@@ -171,74 +185,80 @@
 
     <el-row class="mt-10" v-show="handleElement.type.toLowerCase() === ElementNames.ARCTEXT">
       <el-col :span="4" class="flex-align">
-        <el-radio-group class="full-ratio" v-model="(handleElement as ArcText).showCurvature" @change="changeArcTextStatus">
-          <el-tooltip placement="top" content="隐藏弧度" :hide-after="0" v-if="(handleElement as ArcText).showCurvature">
+        <el-radio-group class="full-ratio" v-model="(handleElement as ArcText).showCurvature"
+                        @change="changeArcTextStatus">
+          <el-tooltip placement="top" content="隐藏弧度" :hide-after="0"
+                      v-if="(handleElement as ArcText).showCurvature">
             <el-radio-button :value="false">
-              <IconPreviewClose />
+              <IconPreviewClose/>
             </el-radio-button>
           </el-tooltip>
           <el-tooltip placement="top" content="显示弧度" :hide-after="0" v-else>
             <el-radio-button :value="true">
-              <IconPreviewOpen />
+              <IconPreviewOpen/>
             </el-radio-button>
           </el-tooltip>
         </el-radio-group>
       </el-col>
       <el-col :span="1"></el-col>
       <el-col :span="12" class="flex-align">
-        <el-slider :min="66" :max="1000" :step="1" v-model="(handleElement as ArcText).radius" @change="changeArcTextRadius" size="small"></el-slider>
+        <el-slider :min="66" :max="1000" :step="1" v-model="(handleElement as ArcText).radius"
+                   @change="changeArcTextRadius" size="small"></el-slider>
       </el-col>
       <el-col :span="1"></el-col>
       <el-col :span="6" class="flex-align">
-        <el-input :min="1" :max="10" v-model="(handleElement as ArcText).radius" controls-position="right" size="default"/>
+        <el-input :min="1" :max="10" v-model="(handleElement as ArcText).radius" controls-position="right"
+                  size="default"/>
       </el-col>
     </el-row>
 
-    <el-divider style="margin: 12px 0" />
-    <ElementFill />
-    <el-divider style="margin: 12px 0" />
+    <el-divider style="margin: 12px 0"/>
+    <ElementFill/>
+    <el-divider style="margin: 12px 0"/>
 
     <div class="row">
       <div style="flex: 2;">行距:</div>
-      <el-select style="flex: 3" suffix-icon="IconRowHeight" v-model="handleElement.lineHeight" @change="changeLineHeight">
+      <el-select style="flex: 3" suffix-icon="IconRowHeight" v-model="handleElement.lineHeight"
+                 @change="changeLineHeight">
         <el-option v-for="item in LineHeightLibs" :key="item" :value="item" :label="item"></el-option>
       </el-select>
       <div style="flex: 1;"></div>
       <div style="flex: 2;">字距:</div>
-      <el-select style="flex: 3" suffix-icon="IconFullwidth" v-model="handleElement.charSpacing" @change="changeCharSpacing">
+      <el-select style="flex: 3" suffix-icon="IconFullwidth" v-model="handleElement.charSpacing"
+                 @change="changeCharSpacing">
         <el-option v-for="item in CharSpaceLibs" :key="item" :value="item" :label="item"></el-option>
       </el-select>
     </div>
 
-    <el-divider style="margin: 12px 0" />
-    <ElementEffects />
-    <el-divider style="margin: 12px 0" />
-    <ElementStroke :hasStroke="hasStroke" />
-    <el-divider style="margin: 12px 0" />
-    <ElementShadow :hasShadow="hasShadow" />
-    <el-divider style="margin: 12px 0" />
-    <ElementPatterns :hasPatterns="hasPatterns" />
-    <el-divider style="margin: 12px 0" />
-    <ElementOpacity />
+    <el-divider style="margin: 12px 0"/>
+    <ElementEffects/>
+    <el-divider style="margin: 12px 0"/>
+    <ElementStroke :hasStroke="hasStroke"/>
+    <el-divider style="margin: 12px 0"/>
+    <ElementShadow :hasShadow="hasShadow"/>
+    <el-divider style="margin: 12px 0"/>
+    <ElementPatterns :hasPatterns="hasPatterns"/>
+    <el-divider style="margin: 12px 0"/>
+    <ElementOpacity/>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { computed, ref, onMounted } from 'vue'
-import { useMainStore, useTemplatesStore } from '@/store'
-import { storeToRefs } from 'pinia'
-import { ElMessage } from 'element-plus'
-import { FabricObject, IText, Textbox } from 'fabric'
-import { FontSizeLibs, LineHeightLibs, CharSpaceLibs } from '@/configs/texts'
-import { WEB_FONTS } from '@/configs/fonts'
-import { propertiesToInclude } from '@/configs/canvas'
-import { TextboxElement } from '@/types/canvas'
-import { ElementNames, FontGroupOption } from '@/types/elements'
-import { loadFont } from '@/utils/fonts'
-import { nanoid } from 'nanoid'
-import { ArcText } from '@/extension/object/ArcText'
-import { CurvedText } from '@/extension/object/CurvedText'
-import { VerticalText } from '@/extension/object/VerticalText'
+import {computed, ref, onMounted} from 'vue'
+import {useMainStore, useTemplatesStore} from '@/store'
+import {storeToRefs} from 'pinia'
+import {ElMessage} from 'element-plus'
+import {FabricObject, IText, Textbox} from 'fabric'
+import {FontSizeLibs, LineHeightLibs, CharSpaceLibs} from '@/configs/texts'
+import {WEB_FONTS} from '@/configs/fonts'
+import {propertiesToInclude} from '@/configs/canvas'
+import {TextboxElement} from '@/types/canvas'
+import {ElementNames, FontGroupOption} from '@/types/elements'
+import {loadFont} from '@/utils/fonts'
+import {nanoid} from 'nanoid'
+import {ArcText} from '@/extension/object/ArcText'
+import {CurvedText} from '@/extension/object/CurvedText'
+import {VerticalText} from '@/extension/object/VerticalText'
 import opentype from "opentype.js"
 import ElementPosition from '../Components/ElementPosition.vue'
 import ElementStroke from '../Components/ElementStroke.vue'
@@ -251,12 +271,11 @@ import useHandleCreate from "@/hooks/useHandleCreate"
 import useCanvas from '@/views/Canvas/useCanvas'
 
 
-
 const mainStore = useMainStore()
 const templatesStore = useTemplatesStore()
-const { canvasObject, systemFonts, onlineFonts } = storeToRefs(mainStore)
-const { createPathElement } = useHandleCreate()
-const [ canvas ] = useCanvas()
+const {canvasObject, systemFonts, onlineFonts} = storeToRefs(mainStore)
+const {createPathElement} = useHandleCreate()
+const [canvas] = useCanvas()
 const handleElement = computed(() => canvasObject.value as Textbox | ArcText)
 const elementGrapheme = computed(() => handleElement.value.type.toLowerCase() !== ElementNames.VERTICALTEXT)
 const elementBackgrounColor = computed(() => {
@@ -277,10 +296,12 @@ const hasPatterns = computed(() => (handleElement.value as TextboxElement).fillT
 const elementFontFamily = ref<string>(hasFontFamily.value)
 const fontOptionGroups = ref<FontGroupOption[]>([
   {
+    type: 0,
     label: '系统字体',
     options: systemFonts.value
   },
   {
+    type: 1,
     label: '在线字体',
     options: onlineFonts.value
   }
@@ -290,8 +311,7 @@ const fontOptionGroups = ref<FontGroupOption[]>([
 const handleElementFontFamily = (fontFamily: string) => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({fontFamily})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {fontFamily})
   }
   canvas.renderAll()
@@ -311,8 +331,7 @@ const handleElementFontSize = (fontSize: string) => {
   if (!fontSize) return
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({fontSize})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {fontSize})
   }
   canvas.renderAll()
@@ -320,25 +339,23 @@ const handleElementFontSize = (fontSize: string) => {
 
 // 修改字体颜色
 const updateFontColor = (fill: string) => {
-  
+
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({fill})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {fill, color: fill})
   }
 }
 
 // 修改背景颜色
 const updateBackgroundColor = (backgroundColor: string) => {
-  let changeData: Record<string, any> = { backgroundColor }
+  let changeData: Record<string, any> = {backgroundColor}
   if (handleElement.value.type.toLowerCase() === ElementNames.ARCTEXT) {
-    changeData = { 'textBackgroundColor': backgroundColor }
+    changeData = {'textBackgroundColor': backgroundColor}
   }
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles(changeData)
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, changeData)
   }
 }
@@ -349,8 +366,7 @@ const handleElementFontsize = (mode: string) => {
   const fontSize = mode === '+' ? handleElement.value.fontSize + 1 : handleElement.value.fontSize - 1
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({fontSize})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {fontSize})
   }
   canvas.renderAll()
@@ -363,12 +379,10 @@ const handleElementBlod = () => {
     const blodState = handleElement.value.getSelectionStyles().find(item => item.fontWeight !== fontBold)
     if (!blodState || (JSON.stringify(blodState) === '{}' && handleElement.value.fontWeight === fontBold)) {
       handleElement.value.setSelectionStyles({'fontWeight': fontNormal})
-    } 
-    else {
+    } else {
       handleElement.value.setSelectionStyles({'fontWeight': fontBold})
     }
-  }
-  else {
+  } else {
     const elementStyle = handleElement.value.styles
     if (handleElement.value.fontWeight === fontBold) {
       templatesStore.modifedElement(handleElement.value, {fontWeight: fontNormal})
@@ -377,8 +391,7 @@ const handleElementBlod = () => {
           (elementStyle[i][j] as TextboxElement).set({fontWeight: fontNormal})
         }
       }
-    }
-    else {
+    } else {
       templatesStore.modifedElement(handleElement.value, {fontWeight: fontBold})
       for (let i in elementStyle) {
         for (let j in elementStyle[i]) {
@@ -392,23 +405,21 @@ const handleElementBlod = () => {
 
 // 修改斜体
 const handleElementItalic = () => {
-  const fontStyle = handleElement.value.fontStyle === 'italic' ? 'normal': 'italic'
+  const fontStyle = handleElement.value.fontStyle === 'italic' ? 'normal' : 'italic'
 
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({fontStyle})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {fontStyle})
   }
-  
+
 }
 
 // 修改删除线
 const handleElementLinethrough = () => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({linethrough: !handleElement.value.linethrough})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {linethrough: !handleElement.value.linethrough})
   }
 }
@@ -417,8 +428,7 @@ const handleElementLinethrough = () => {
 const handleElementUnderline = () => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({underline: !handleElement.value.underline})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {underline: !handleElement.value.underline})
   }
 }
@@ -427,8 +437,7 @@ const handleElementUnderline = () => {
 const handleTextAlign = (textAlign: string) => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({textAlign})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {textAlign})
   }
 }
@@ -437,26 +446,24 @@ const handleTextAlign = (textAlign: string) => {
 const handleElementCharSpacing = (mode: '+' | '-') => {
   const handleCharSpacing = handleElement.value.charSpacing
   const charSpacing = mode === '+' ? handleCharSpacing + 10 : handleCharSpacing - 10
-  templatesStore.modifedElement(handleElement.value, { charSpacing })
+  templatesStore.modifedElement(handleElement.value, {charSpacing})
 }
 
 const changeLineHeight = (lineHeight: number) => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({lineHeight})
-  }
-  else {
-    templatesStore.modifedElement(handleElement.value, { lineHeight })
+  } else {
+    templatesStore.modifedElement(handleElement.value, {lineHeight})
   }
 }
 
 const changeCharSpacing = (charSpacing: number) => {
   if (handleElement.value.isEditing) {
     handleElement.value.setSelectionStyles({charSpacing})
-  }
-  else {
+  } else {
     templatesStore.modifedElement(handleElement.value, {charSpacing})
   }
-  
+
   canvas.renderAll()
 }
 
@@ -519,12 +526,12 @@ const handleElementDeformation = () => {
 
 const changeArcTextRadius = (val: number) => {
   (handleElement.value as ArcText).setRadius(val)
-  templatesStore.modifedElement(handleElement.value, { radius: val })
+  templatesStore.modifedElement(handleElement.value, {radius: val})
 }
 
 const changeArcTextStatus = (showCurvature: boolean) => {
   (handleElement.value as ArcText).set({showCurvature})
-  templatesStore.modifedElement(handleElement.value, { showCurvature })
+  templatesStore.modifedElement(handleElement.value, {showCurvature})
 }
 
 </script>
@@ -533,17 +540,20 @@ const changeArcTextStatus = (showCurvature: boolean) => {
 .text-style-panel {
   user-select: none;
 }
+
 .row {
   width: 100%;
   display: flex;
   align-items: center;
   margin-bottom: 10px;
 }
+
 .preset-style {
   display: flex;
   flex-wrap: wrap;
   margin-bottom: 10px;
 }
+
 .preset-style-item {
   width: 50%;
   height: 50px;
@@ -565,26 +575,33 @@ const changeArcTextStatus = (showCurvature: boolean) => {
   &:nth-child(2n) {
     margin-left: -1px;
   }
+
   &:nth-child(n+3) {
     margin-top: -1px;
   }
 }
+
 .font-size-btn {
   padding: 0;
 }
+
 .link-popover {
   width: 240px;
+
   .btns {
     margin-top: 10px;
     text-align: right;
   }
 }
+
 .mt-10 {
   margin-top: 10px;
 }
+
 .full-group {
   display: flex;
   flex: 1;
+
   .el-button {
     width: 50%;
   }
@@ -595,32 +612,39 @@ const changeArcTextStatus = (showCurvature: boolean) => {
     width: 100%;
     border-radius: 0;
   }
+
   .font-color {
     border-top-left-radius: 4px;
     border-bottom-left-radius: 4px;
     border-right: 0;
   }
+
   .high-light {
     border-right: 0;
   }
 }
+
 .font-size {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
+
 .full-ratio {
   display: flex;
   flex: 1;
+
   .el-radio-button {
     position: relative;
     display: inline-flex;
     outline: 0;
     flex: 1;
   }
+
   .el-radio-button__inner {
     width: 100%
   }
 }
+
 .flex-align {
   display: flex;
   align-items: center;
@@ -630,8 +654,10 @@ const changeArcTextStatus = (showCurvature: boolean) => {
   display: flex;
   flex: 1;
 }
+
 .full-button {
   width: 100%;
+
   .iconfont {
     font-size: 32px;
   }
@@ -650,6 +676,7 @@ const changeArcTextStatus = (showCurvature: boolean) => {
   outline: 0;
   flex: 1;
 }
+
 :deep(.full-checkbox .el-checkbox-button) {
   position: relative;
   display: inline-flex;

+ 104 - 24
src/views/Editor/CanvasRight/index.vue

@@ -2,28 +2,29 @@
   <div>
     <div class="right-top">
       <div class="flex align-middle px-[8px]">
-        <Lang />
+        <Lang/>
       </div>
       <div>
-<!--        <el-button text>分享</el-button>-->
+        <!--        <el-button text>分享</el-button>-->
         <el-button type="primary" @click="exportFile">下载</el-button>
-<!--        <el-button text href="https://github.com/dromara/sd-designer" tag="a" target="_blank" rel="noopener noreferrer">-->
-<!--          &lt;!&ndash; <a href="https://github.com/dromara/sd-designer" target="_blank" rel="noopener noreferrer"> &ndash;&gt;-->
-<!--            &lt;!&ndash; <el-tooltip placement="top" :hide-after="0" :content="t('message.github')"> &ndash;&gt;-->
-<!--            <IconGithub class="footer-button"></IconGithub>-->
-<!--            &lt;!&ndash; </el-tooltip> &ndash;&gt;-->
-<!--          &lt;!&ndash; </a> &ndash;&gt;-->
-<!--        </el-button>-->
+        <el-button type="success" @click="onSaveTemplate">保存</el-button>
+        <!--        <el-button text href="https://github.com/dromara/sd-designer" tag="a" target="_blank" rel="noopener noreferrer">-->
+        <!--          &lt;!&ndash; <a href="https://github.com/dromara/sd-designer" target="_blank" rel="noopener noreferrer"> &ndash;&gt;-->
+        <!--            &lt;!&ndash; <el-tooltip placement="top" :hide-after="0" :content="t('message.github')"> &ndash;&gt;-->
+        <!--            <IconGithub class="footer-button"></IconGithub>-->
+        <!--            &lt;!&ndash; </el-tooltip> &ndash;&gt;-->
+        <!--          &lt;!&ndash; </a> &ndash;&gt;-->
+        <!--        </el-button>-->
       </div>
     </div>
     <div class="right-bottom">
       <div class="right-tabs">
         <div
-          class="tab"
-          :class="[ tab.value === rightState && currentTabs.length > 1 ? 'active' : 'no-active' ]"
-          v-for="tab in currentTabs"
-          :key="tab.value"
-          @click="setRightState(tab.value)"
+            class="tab"
+            :class="[ tab.value === rightState && currentTabs.length > 1 ? 'active' : 'no-active' ]"
+            v-for="tab in currentTabs"
+            :key="tab.value"
+            @click="setRightState(tab.value)"
         >
           {{ tab.label }}
         </div>
@@ -32,26 +33,72 @@
         <component :is="currentPanelComponent"></component>
       </div>
     </div>
-    <FileExport v-model:visible="exportFileDialog" @close="exportFileHide" @save="exportFileHandle" />
+    <FileExport v-model:visible="exportFileDialog" @close="exportFileHide" @save="exportFileHandle"/>
+    <el-dialog
+        v-model="showSaveDlg"
+        title="保存模板"
+        width="580px"
+        @close="closeSaveDlg">
+      <el-form
+          ref="formRef"
+          :model="formData"
+          :rules="rules"
+          label-width="120px"
+      >
+        <el-row>
+          <el-col :span="24">
+            <el-form-item prop="templateName" label="模板名称">
+              <el-input v-model="formData.templateName"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit"
+          >确 定
+          </el-button>
+          <el-button @click="showSaveDlg = false">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 <script lang="ts" setup>
-import { computed, watch } from "vue";
-import { RightStates, ElementNames } from "@/types/elements";
-import { storeToRefs } from "pinia";
-import { useMainStore } from "@/store/modules/main";
+import {computed, watch} from "vue";
+import {RightStates, ElementNames} from "@/types/elements";
+import {storeToRefs} from "pinia";
+import {useMainStore} from "@/store/modules/main";
 import Lang from "@/components/Lang/index.vue";
 import CanvasStylePanel from "./CanvasStylePanel/index.vue";
 import ElemnetStylePanel from "./ElementStylePanel/index.vue";
 import EffectStylePanel from "./EffectStylePanel/index.vue";
 import LayerStylePanel from "./LayerStylePanel/index.vue";
 import useI18n from "@/hooks/useI18n";
-const { t } = useI18n();
+import {useTemplatesStore} from "@/store";
+import useCanvasExport from "@/hooks/useCanvasExport";
+import {updateDesignTemplate} from "@/api/template";
+import {ElMessage, FormInstance} from "element-plus";
+
+const templatesStore = useTemplatesStore()
+const {getJSONData} = useCanvasExport()
+
+const {t} = useI18n();
 
 const mainStore = useMainStore();
-const { canvasObject, rightState } = storeToRefs(mainStore);
+const {canvasObject, rightState} = storeToRefs(mainStore);
 const exportFileDialog = ref(false)
 
+const showSaveDlg = ref(false)
+const formRef = ref<FormInstance>();
+const rules = reactive({
+  templateName: [{required: true, message: "请输入名称", trigger: "blur"}],
+});
+const formData = reactive({
+  templateName: '',
+  jsonContent: '',
+  id: 0,
+});
 
 const exportFileHide = () => {
   exportFileDialog.value = false
@@ -65,12 +112,41 @@ const exportFile = () => {
   exportFileDialog.value = true
 }
 
+const onSaveTemplate = () => {
+  formData.templateName = templatesStore.templateName
+  showSaveDlg.value = true
+}
+
+const handleSubmit = () => {
+  formRef.value.validate((valid: any) => {
+    if (valid) {
+      formData.id = templatesStore.templateId
+      formData.jsonContent = getJSONData()
+
+      updateDesignTemplate(JSON.stringify(formData)).then((res) => {
+        if (res.httpCode == 200) {
+          ElMessage.success('保存成功')
+          showSaveDlg.value = false
+        }
+      })
+
+    }
+  })
+
+}
+
+const closeSaveDlg = () => {
+  formData.id = 0
+  formData.templateName = templatesStore.templateName
+  formData.jsonContent = ''
+}
+
 const canvasTabs = [
-  { label: t("style.canvas"), value: RightStates.ELEMENT_CANVAS },
+  {label: t("style.canvas"), value: RightStates.ELEMENT_CANVAS},
   // { label: t("style.layer"), value: RightStates.ELEMENT_LAYER },
 ];
 const styleTabs = [
-  { label: t("style.style"), value: RightStates.ELEMENT_STYLE },
+  {label: t("style.style"), value: RightStates.ELEMENT_STYLE},
   // { label: t("style.layer"), value: RightStates.ELEMENT_LAYER },
 ];
 
@@ -86,7 +162,7 @@ const currentTabs = computed(() => {
 
 watch(currentTabs, () => {
   const currentTabsValue: RightStates[] = currentTabs.value.map(
-    (tab) => tab.value
+      (tab) => tab.value
   );
   if (!currentTabsValue.includes(rightState.value)) {
     mainStore.setRightState(currentTabsValue[0]);
@@ -113,9 +189,11 @@ const currentPanelComponent = computed(() => {
   align-items: center;
   border-bottom: 1px solid $borderColor;
 }
+
 .right-bottom {
   height: calc(100% - 40px);
 }
+
 .right-tabs {
   height: 32px;
   font-size: 12px;
@@ -123,6 +201,7 @@ const currentPanelComponent = computed(() => {
   display: flex;
   user-select: none;
 }
+
 .tab {
   flex: 1;
   display: flex;
@@ -141,6 +220,7 @@ const currentPanelComponent = computed(() => {
     border-left: 1px solid $borderColor;
   }
 }
+
 .right-content {
   padding: 10px 5px 10px 10px;
   font-size: 13px;

+ 43 - 9
src/views/Editor/computer.vue

@@ -9,18 +9,18 @@
 <template>
   <div class="h-full" v-drop-image="{ url: 'UploadUrl', highlightStyle: { backgroundColor: 'lightblue' } }">
     <div class="layout-content flex">
-      <CanvasLeft />
+      <CanvasLeft/>
       <div class="layout-content-center">
-        <CanvasHeader class="center-header relative flex justify-between py-[10px] text-[14px] select-none h-[39px]" />
-        <CanvasCenter class="center-body" />
+        <CanvasHeader class="center-header relative flex justify-between py-[10px] text-[14px] select-none h-[39px]"/>
+        <CanvasCenter class="center-body"/>
         <!-- <CanvasFooter class="center-footer h-[40px] relative leading-1.5 flex justify-between" /> -->
-        <CanvasAffix  class="center-affix"/>
-<!--        <CanvasICP />-->
+        <CanvasAffix class="center-affix"/>
+        <!--        <CanvasICP />-->
       </div>
-      <CanvasRight class="layout-content-right h-full w-[260px] bg-[#fff] flex flex-col" />
-      <CanvasDom class="absolute -z-[200] -left-[300px]" />
+      <CanvasRight class="layout-content-right h-full w-[260px] bg-[#fff] flex flex-col"/>
+      <CanvasDom class="absolute -z-[200] -left-[300px]"/>
     </div>
-    <CanvasTour />
+    <CanvasTour/>
   </div>
 </template>
 
@@ -34,27 +34,61 @@ import CanvasICP from "./CanvasICP/index.vue";
 import CanvasAffix from "./CanvasAffix/index.vue";
 import CanvasDom from "./CanvasDom/index.vue";
 import CanvasTour from "./CanvasTour/index.vue";
+
+import {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";
+
+const mainStore = useMainStore();
+
+onMounted(async () => {
+  const query = router.currentRoute.value.query
+  if (!query.virtualCode){
+    ElMessage.error('当前用户未登录,设计将无法保存')
+    return
+  }
+  const param = {
+    virtualCode: query.virtualCode
+  }
+
+  getCurrentUserTokenInfo(param).then((response) => {
+    if (response.httpCode == 200) {
+      setToken('token', response.data.token)
+      setToken('supplierCode', response.data.supplierCode)
+      setToken('dataSourceId', response.data.dataSourceId)
+    }
+  });
+
+  mainStore.getFonts();
+})
 </script>
 
 <style lang="scss" scoped>
 .layout-content {
   height: calc(100% - 40px);
 }
+
 .layout-content-center {
-  width: calc(100% - 50px /*- 160px*/ - 260px);
+  width: calc(100% - 50px/*- 160px*/ - 260px);
 
   .center-header {
     // border-left: 1px solid $borderColor;
   }
+
   .center-body {
     height: 100%;
     // margin: 100px;
   }
+
   .center-footer {
     border-top: 1px solid $borderColor;
     background-color: $lightGray;
   }
 }
+
 .layout-content-right {
   // border-left: solid 1px $borderColor;
 }

+ 5 - 13
vite.config.mts

@@ -13,24 +13,16 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
       host: '0.0.0.0',
       port: 9191,
       proxy: {
-        '/api': {
-          // target: 'https://yft.design',
+        '/apis10': {
           target: 'http://192.168.1.44:9991',
           changeOrigin: true,
-          rewrite: (path) => path.replace(new RegExp('^'), ''),
+          rewrite: (path) => path.replace(new RegExp('^/apis10'), ''),
         },
         '/static': {
-          // target: 'https://yft.design',
-          target: 'http://127.0.0.1:8789',
+          target: 'http://192.168.1.44:11994',
           changeOrigin: true,
-          rewrite: (path) => path.replace(new RegExp('^'), ''),
-        },
-        '/yft-static': {
-          // target: 'https://yft.design',
-          target: 'http://127.0.0.1:8789',
-          changeOrigin: true,
-          rewrite: (path) => path.replace(new RegExp('^'), ''),
-        },
+          rewrite: (path) => path.replace(new RegExp('^/static'), ''),
+        }
       },
     },
     plugins: createVitePlugins(mode),