diff --git a/package-lock.json b/package-lock.json index f504f3f..6b60a36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "axios": "^1.6.2", "convert-units": "^3.0.0-beta.5", "leafer-ui": "1.0.0-rc.8", + "leafer-x-ruler": "^1.0.0", "lodash": "^4.17.21", "mousetrap": "^1.6.5", "number-precision": "^1.6.0", @@ -3356,6 +3357,16 @@ "leafer-in": "1.0.0-rc.8" } }, + "node_modules/leafer-x-ruler": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/leafer-x-ruler/-/leafer-x-ruler-1.0.0.tgz", + "integrity": "sha512-JmHCCBsEhkE+68OMDhhI0y8pTKhQiYpEW4D1IzSofYDdfKmup6gDMjbbjywFKy+te4BrpG0ili4lUzBQK7CSOw==", + "dependencies": { + "@leafer-in/editor": "1.0.0-rc.8", + "@leafer-ui/core": "1.0.0-rc.8", + "@leafer-ui/interface": "1.0.0-rc.8" + } + }, "node_modules/less": { "version": "4.2.0", "resolved": "https://registry.npmmirror.com/less/-/less-4.2.0.tgz", @@ -8361,6 +8372,16 @@ "leafer-in": "1.0.0-rc.8" } }, + "leafer-x-ruler": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/leafer-x-ruler/-/leafer-x-ruler-1.0.0.tgz", + "integrity": "sha512-JmHCCBsEhkE+68OMDhhI0y8pTKhQiYpEW4D1IzSofYDdfKmup6gDMjbbjywFKy+te4BrpG0ili4lUzBQK7CSOw==", + "requires": { + "@leafer-in/editor": "1.0.0-rc.8", + "@leafer-ui/core": "1.0.0-rc.8", + "@leafer-ui/interface": "1.0.0-rc.8" + } + }, "less": { "version": "4.2.0", "resolved": "https://registry.npmmirror.com/less/-/less-4.2.0.tgz", diff --git a/package.json b/package.json index 7a0873e..5266c73 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@leafer-in/html": "^1.0.0-rc.8", "@leafer-ui/core": "^1.0.0-rc.8", "@leafer-ui/interface": "^1.0.0-rc.8", + "leafer-x-ruler": "^1.0.0", "@scena/guides": "^0.29.2", "@unocss/reset": "^0.57.7", "@vueuse/core": "^10.7.0", diff --git a/src/assets/data/modelData/3.json b/src/assets/data/modelData/3.json index 7c2983c..1191932 100644 --- a/src/assets/data/modelData/3.json +++ b/src/assets/data/modelData/3.json @@ -93,7 +93,7 @@ }, { "tag": "Text", - "width": 150, + "width": 170, "padding": [ 0, 0, @@ -150,7 +150,7 @@ "value": 150 }, "name": "图层5", - "x": 320, + "x": 340, "y": 70, "draggable": true, "editable": true @@ -182,7 +182,7 @@ "value": 150 }, "name": "图层6", - "x": 400, + "x": 420, "y": 70, "draggable": true, "editable": true @@ -221,7 +221,7 @@ }, { "tag": "Text", - "width": 150, + "width": 170, "padding": [ 0, 0, @@ -278,7 +278,7 @@ "value": 150 }, "name": "图层9", - "x": 320, + "x": 340, "y": 100, "draggable": true, "editable": true @@ -310,7 +310,7 @@ "value": 150 }, "name": "图层10", - "x": 400, + "x": 420, "y": 100, "draggable": true, "editable": true @@ -349,7 +349,7 @@ }, { "tag": "Text", - "width": 150, + "width": 170, "padding": [ 0, 0, @@ -406,7 +406,7 @@ "value": 150 }, "name": "图层13", - "x": 320, + "x": 340, "y": 130, "draggable": true, "editable": true @@ -438,13 +438,14 @@ "value": 150 }, "name": "图层14", - "x": 400, + "x": 420, "y": 130, "draggable": true, "editable": true }, { "tag": "Text", + "width": 70, "padding": [ 0, 0, @@ -470,7 +471,1341 @@ }, "name": "图层15", "x": 70, - "y": 50, + "y": 160, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 170, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "shuangxunian@gmail.com", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层16", + "x": 150, + "y": 160, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 70, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "毕业院校:", + "fontSize": 14, + "fontWeight": "bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层17", + "x": 340, + "y": 160, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "北京大学", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层18", + "x": 420, + "y": 160, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 70, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "住 址:", + "fontSize": 14, + "fontWeight": "bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层19", + "x": 70, + "y": 190, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 170, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "浙江省杭州市滨江区", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层20", + "x": 150, + "y": 190, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 70, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "学历:", + "fontSize": 14, + "fontWeight": "bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层21", + "x": 340, + "y": 190, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "本科", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层22", + "x": 420, + "y": 190, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 70, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "求职意向:", + "fontSize": 14, + "fontWeight": "bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层23", + "x": 70, + "y": 220, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 170, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "前端开发", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层24", + "x": 150, + "y": 220, + "draggable": true, + "editable": true + }, + { + "tag": "Image", + "url": "https://www.听闻.cn:5244/d/本地/阿里云盘资料备份共享/图片/图床/2023/12/14/657aba4355874.png", + "width": 153, + "height": 170, + "name": "图层25", + "x": 570, + "y": 70, + "draggable": true, + "editable": true, + "fill": { + "type": "image", + "mode": "strench", + "url": "https://www.听闻.cn:5244/d/本地/阿里云盘资料备份共享/图片/图床/2023/12/14/657aba4355874.png" + } + }, + { + "tag": "Rect", + "name": "图层26", + "x": 48, + "y": 260, + "width": 697, + "height": 20, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(216, 216, 216, 1)" + } + ] + }, + { + "tag": "Rect", + "name": "图层27", + "x": 48, + "y": 260, + "width": 100, + "height": 20, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(151,151,151,1)" + } + ] + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(255, 255, 255, 1)" + } + ], + "text": "教育背景", + "fontSize": 16, + "fontWeight": "semi-bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层28", + "x": 68, + "y": 258, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "height": 0, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "2017.07-2021.06", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层29", + "x": 60, + "y": 290, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "北京大学", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层30", + "x": 300, + "y": 290, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "计算机科学", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层31", + "x": 540, + "y": 290, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 80, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "主修课程:\n程序设计基础、数据结构与算法、操作系统、编译原理、数据库系统、算法分析、软件工程、离散数学、电路与电子学、数字逻辑和数字系统、计算机组成原理、计算机系统结构、计算机网络原理等。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层32", + "x": 70, + "y": 310, + "draggable": true, + "editable": true + }, + { + "tag": "Rect", + "name": "图层26", + "x": 48, + "y": 390, + "width": 697, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(216, 216, 216, 1)" + } + ] + }, + { + "tag": "Rect", + "name": "图层27", + "x": 48, + "y": 390, + "width": 100, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(151,151,151,1)" + } + ] + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(255, 255, 255, 1)" + } + ], + "text": "实习经历", + "fontSize": 16, + "fontWeight": "semi-bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层28", + "x": 68, + "y": 388, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 120, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "2017.07-2021.06", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层29", + "x": 60, + "y": 420, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 200, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "上海米哈游知天命科技有限公司", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层30", + "x": 300, + "y": 420, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "前端开发工程师", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层31", + "x": 540, + "y": 420, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 70, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "负责公司业务系统的设计及改进,参与公司网上商城系统产品功能设计及实施工作。\n负责客户调研、客户需求分析、方案写作等工作, 参与公司多个大型电子商务项目的策划工作,担任大商集团网上商城一期建设项目经理。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层39", + "x": 70, + "y": 450, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 120, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "2017.07-2021.06", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层29", + "x": 60, + "y": 520, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 200, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "上海米哈游知天命科技有限公司", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层30", + "x": 300, + "y": 520, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "前端开发工程师", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层31", + "x": 540, + "y": 520, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 80, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "负责公司业务系统的设计及改进,参与公司网上商城系统产品功能设计及实施工作。\n负责客户调研、客户需求分析、方案写作等工作, 参与公司多个大型电子商务项目的策划工作,担任大商集团网上商城一期建设项目经理。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层39", + "x": 70, + "y": 550, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Rect", + "name": "图层26", + "x": 48, + "y": 630, + "width": 697, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(216, 216, 216, 1)" + } + ] + }, + { + "tag": "Rect", + "name": "图层27", + "x": 48, + "y": 630, + "width": 100, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(151,151,151,1)" + } + ] + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(255, 255, 255, 1)" + } + ], + "text": "校内实践", + "fontSize": 16, + "fontWeight": "semi-bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层28", + "x": 68, + "y": 628, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 120, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "2017.07-2021.06", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层29", + "x": 60, + "y": 660, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 200, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "上海米哈游知天命科技有限公司", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层30", + "x": 300, + "y": 660, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 150, + "height": 20, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "前端开发工程师", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层31", + "x": 540, + "y": 660, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 80, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "负责公司业务系统的设计及改进,参与公司网上商城系统产品功能设计及实施工作。\n负责客户调研、客户需求分析、方案写作等工作, 参与公司多个大型电子商务项目的策划工作,担任大商集团网上商城一期建设项目经理。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层39", + "x": 70, + "y": 690, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Rect", + "name": "图层26", + "x": 48, + "y": 770, + "width": 697, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(216, 216, 216, 1)" + } + ] + }, + { + "tag": "Rect", + "name": "图层27", + "x": 48, + "y": 770, + "width": 100, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(151,151,151,1)" + } + ] + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(255, 255, 255, 1)" + } + ], + "text": "技能证书", + "fontSize": 16, + "fontWeight": "semi-bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层28", + "x": 68, + "y": 768, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 80, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "普通话一级甲等;\n大学英语四/六级(CET-4/6),良好的听说读写能力,快速浏览英语专业文件及书籍;\n通过全国计算机二级考试,熟练运用office相关软件。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层32", + "x": 70, + "y": 800, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Rect", + "name": "图层26", + "x": 48, + "y": 880, + "width": 697, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(216, 216, 216, 1)" + } + ] + }, + { + "tag": "Rect", + "name": "图层27", + "x": 48, + "y": 880, + "width": 100, + "height": 20, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true, + "fill": [ + { + "type": "solid", + "color": "rgba(151,151,151,1)" + } + ] + }, + { + "tag": "Text", + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(255, 255, 255, 1)" + } + ], + "text": "自我评价", + "fontSize": 16, + "fontWeight": "semi-bold", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层28", + "x": 70, + "y": 878, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, + "draggable": true, + "editable": true + }, + { + "tag": "Text", + "width": 633, + "height": 80, + "padding": [ + 0, + 0, + 0, + 0 + ], + "fill": [ + { + "type": "solid", + "color": "rgba(0,0,0,1)" + } + ], + "text": "深度互联网从业人员,对互联网保持高度的敏感性和关注度,熟悉产品开发流程,有很强的产品规划、需求分析、交互设计能力,能独立承担APP和WEB项目的管控工作,善于沟通,贴近用户。", + "fontSize": 14, + "fontWeight": "normal", + "letterSpacing": { + "type": "px", + "value": 0 + }, + "lineHeight": { + "type": "percent", + "value": 150 + }, + "name": "图层32", + "x": 70, + "y": 910, + "scaleX": 1, + "scaleY": 1, + "rotation": 0, + "skewX": 0, + "skewY": 0, "draggable": true, "editable": true } diff --git a/src/views/Editor/app/editor/clipboard.ts b/src/views/Editor/app/editor/clipboard.ts new file mode 100644 index 0000000..20a4746 --- /dev/null +++ b/src/views/Editor/app/editor/clipboard.ts @@ -0,0 +1,137 @@ +import { + MLeaferCanvas, + IMLeaferCanvas, +} from "@/views/Editor/core/canvas/mLeaferCanvas"; +import { Disposable } from "@/views/Editor/utils/lifecycle"; +import { + IKeybindingService, + KeybindingService, +} from "@/views/Editor/core/keybinding/keybindingService"; +import { + ClipboardService, + IClipboardService, +} from "@/views/Editor/core/clipboard/clipboardService"; +import { + IUndoRedoService, + UndoRedoService, +} from "@/views/Editor/app/editor/undoRedo/undoRedoService"; +import { clamp, clone } from "lodash"; +import { appInstance } from "@/views/Editor/app"; +import { PointerEvent, Point, Group, LeafList } from "leafer-ui"; +import { IGroup, IUI } from "@leafer-ui/interface"; +import { typeUtil } from "@/views/Editor/utils/utils"; +import { EditorHelper } from "@leafer-in/editor/src/helper/EditorHelper"; +import { MEditorHelper } from "@/views/Editor/utils/MEditorHelper"; +import { Matrix } from "@leafer-ui/core"; + +export class Clipboard extends Disposable { + private pointer = new Point(); + private activeObject: IUI; + private group: IGroup; + + constructor( + @IMLeaferCanvas private readonly canvas: MLeaferCanvas, + @IKeybindingService readonly keybinding: KeybindingService, + @IClipboardService private readonly clipboard: ClipboardService, + @IUndoRedoService private readonly undoRedo: UndoRedoService + ) { + super(); + + keybinding.bind({ + "mod+x": this.clip.bind(this), + "mod+c": this.copy.bind(this), + "mod+v": this.paste.bind(this, false), + "mod+shift+v": this.paste.bind(this, true), + }); + canvas.app.tree.on(PointerEvent.MOVE, (arg: PointerEvent) => { + this.pointer = new Point(arg.x, arg.y); + }); + } + + private async copy() { + const _activeObject = this.canvas.getActiveObject(); + if (!_activeObject || typeUtil.isBottomCanvas(_activeObject)) return; + this.activeObject = clone(_activeObject); + + // 不管怎样都进组,最后再拆 + if (typeUtil.isVirtualElement(this.activeObject)) { + // 选中元素进组 + let list: IUI[] = []; + const objects = this.canvas.getActiveObjects(); + objects.forEach((value) => { + const clo = value.clone(); + clo.parent = value.parent; + list.push(clo); + }); + this.group = MEditorHelper.group(list, objects[0]); + } else { + const cloneObj = this.activeObject.clone(); + this.group = MEditorHelper.group([cloneObj], this.activeObject); + } + // 转json + const json = JSON.stringify(this.group.toJSON()); + + // 写剪贴板 + this.clipboard.writeText(json); + } + + private paste(currentLocation = false) { + this.clipboard.readBlob().then((blobs) => { + if (!blobs) return; + blobs.forEach(async (blob) => { + // 读取json + const json = await blob.text(); + let serialized: any | undefined; + + if (json) { + try { + serialized = JSON.parse(json); + } catch (error) { + // + } + } + // 插入元素到画板内 + const addObjects = (groupData: object) => { + const group = new Group(groupData); + // 粘贴到当前位置 + if (currentLocation) { + // TODO 拖动、缩放画布后重新复制元素时坐标有问题需获取到正确的坐标 + const { x, y } = + appInstance.editor.contextMenu?.pointer || this.pointer; + const point = this.activeObject.parent + ? this.activeObject.parent.getInnerPoint({ + x: x, + y: y, + }) + : this.canvas.contentFrame.getInnerPoint({ x: x, y: y }); + group.x = point.x; + group.y = point.y; + } else { + // 略微在原基础上偏移粘贴 + group.x += 15; + group.y += 15; + } + this.canvas.add(group); + // 选中元素 + this.canvas.setActiveObjects(group.children); + // 解组 + MEditorHelper.ungroup([group]); + }; + addObjects(serialized); + // this.undoRedo.saveState() + currentLocation && + (appInstance.editor.contextMenu!.pointer = undefined); + }); + }); + } + + private clip() { + this.copy(); + this.keybinding.trigger("del"); + } + + public dispose(): void { + super.dispose(); + this.keybinding.unbind(["mod+x", "mod+c", "mod+v", "mod+shift+v"]); + } +} diff --git a/src/views/Editor/app/editor/contextMenu.ts b/src/views/Editor/app/editor/contextMenu.ts index 503e922..002a3c9 100644 --- a/src/views/Editor/app/editor/contextMenu.ts +++ b/src/views/Editor/app/editor/contextMenu.ts @@ -1,60 +1,71 @@ -import { IMLeaferCanvas, MLeaferCanvas } from '@/views/Editor/core/canvas/mLeaferCanvas' -import { Disposable } from '@/views/Editor/utils/lifecycle' -import MenuComponent from '@/components/contextMenu' -import { layerItems, zoomItems } from '@/views/Editor/utils/contextMenu' -import { IKeybindingService, KeybindingService } from '@/views/Editor/core/keybinding/keybindingService' -import {Point,PointerEvent} from "leafer-ui"; +import { + IMLeaferCanvas, + MLeaferCanvas, +} from "@/views/Editor/core/canvas/mLeaferCanvas"; +import { Disposable } from "@/views/Editor/utils/lifecycle"; +import MenuComponent from "@/components/contextMenu"; +import { layerItems, zoomItems } from "@/views/Editor/utils/contextMenu"; +import { + IKeybindingService, + KeybindingService, +} from "@/views/Editor/core/keybinding/keybindingService"; +import { Point, PointerEvent } from "leafer-ui"; +import { typeUtil } from "@/views/Editor/utils/utils"; export class ContextMenu extends Disposable { + public pointer: Point | undefined; + constructor( - @IMLeaferCanvas private readonly canvas: MLeaferCanvas, - @IKeybindingService private readonly keybindingService: KeybindingService, + @IMLeaferCanvas private readonly canvas: MLeaferCanvas, + @IKeybindingService private readonly keybindingService: KeybindingService ) { - super() - canvas.app.on(PointerEvent.MENU,(arg:PointerEvent) => { - this.showLayerContextMenu(arg) - }) - + super(); + canvas.contentFrame.on(PointerEvent.MENU, (arg: PointerEvent) => { + this.pointer = new Point(arg.x, arg.y); + this.showLayerContextMenu(arg); + }); + canvas.app.editor.on(PointerEvent.MENU, (arg: PointerEvent) => { + this.pointer = new Point(arg.x, arg.y); + this.showLayerContextMenu(arg); + }); } - public pointer: Point | undefined - private showBlankContextMenu(e: PointerEvent) { - e.stopDefault() - const event = e.origin - const { mod } = this.keybindingService + e.stopDefault(); + const event = e.origin; + const { mod } = this.keybindingService; MenuComponent.showContextMenu({ x: event.clientX, y: event.clientY - 5, preserveIconWidth: false, items: [ { - label: '选择全部', + label: "选择全部", onClick: () => { - this.keybindingService.trigger('mod+a') + this.keybindingService.trigger("mod+a"); }, shortcut: `${mod} A`, }, { - label: '粘贴到当前位置', + label: "粘贴到当前位置", onClick: () => { - this.keybindingService.trigger('mod+shift+v') + this.keybindingService.trigger("mod+shift+v"); }, shortcut: `${mod} ⇧ V`, }, ...zoomItems(), ], - }) + }); } private showLayerContextMenu(e: PointerEvent) { - e.stopDefault() - const event = e.origin - const object = this.canvas.activeObject.value + e.stopDefault(); + const event = e.origin; + const object = this.canvas.activeObject.value; // 置空选项 - if (!object) { - this.showBlankContextMenu(e) - return + if (!object || typeUtil.isBottomCanvas(object)) { + this.showBlankContextMenu(e); + return; } MenuComponent.showContextMenu({ @@ -62,6 +73,6 @@ export class ContextMenu extends Disposable { y: event.clientY - 5, preserveIconWidth: false, items: layerItems(), - }) + }); } } diff --git a/src/views/Editor/app/editor/editor.ts b/src/views/Editor/app/editor/editor.ts index fdc19a0..8b1cd28 100644 --- a/src/views/Editor/app/editor/editor.ts +++ b/src/views/Editor/app/editor/editor.ts @@ -1,127 +1,153 @@ -import { ContextMenu } from '@/views/Editor/app/editor/contextMenu' -import { Layer } from '@/views/Editor/app/editor/layer' -import { SyncDescriptor } from '@/views/Editor/core/instantiation/descriptors' -import { IInstantiationService, ServiceIdentifier } from '@/views/Editor/core/instantiation/instantiation' -import { ServiceCollection } from '@/views/Editor/core/instantiation/serviceCollection' -import { EditorPlugin, IEditorPluginContext, getActiveCore } from '@/views/Editor/core' -import { IKeybindingService, KeybindingService } from '@/views/Editor/core/keybinding/keybindingService' -import { IWorkspacesService, WorkspacesService } from '@/views/Editor/core/workspaces/workspacesService' -import { IEventbusService, EventbusService } from '@/views/Editor/core/eventbus/eventbusService' -import { BaseApp } from '@/views/Editor/app/baseApp' -import { UsableSolts } from '@/views/Editor/core/types' -import { toDisposable } from '@/views/Editor/utils/lifecycle' -import type { DefineComponent } from 'vue' -import { useEditor } from '@/views/Editor/app' -import { runWhenIdle } from '@/views/Editor/utils/async' -import { IMLeaferCanvas, MLeaferCanvas} from "@/views/Editor/core/canvas/mLeaferCanvas"; -import {Zoom} from "@/views/Editor/app/editor/zoom"; -import {Ruler} from "@/views/Editor/app/editor/ruler2"; -import {ToolBar} from "@/views/Editor/app/editor/toolBar"; -import { IUndoRedoService, UndoRedoService } from '@/views/Editor/app/editor/undoRedo/undoRedoService' - +import { ContextMenu } from "@/views/Editor/app/editor/contextMenu"; +import { Layer } from "@/views/Editor/app/editor/layer"; +import { SyncDescriptor } from "@/views/Editor/core/instantiation/descriptors"; +import { + IInstantiationService, + ServiceIdentifier, +} from "@/views/Editor/core/instantiation/instantiation"; +import { ServiceCollection } from "@/views/Editor/core/instantiation/serviceCollection"; +import { + EditorPlugin, + IEditorPluginContext, + getActiveCore, +} from "@/views/Editor/core"; +import { + IKeybindingService, + KeybindingService, +} from "@/views/Editor/core/keybinding/keybindingService"; +import { + IWorkspacesService, + WorkspacesService, +} from "@/views/Editor/core/workspaces/workspacesService"; +import { + IEventbusService, + EventbusService, +} from "@/views/Editor/core/eventbus/eventbusService"; +import { BaseApp } from "@/views/Editor/app/baseApp"; +import { UsableSolts } from "@/views/Editor/core/types"; +import { toDisposable } from "@/views/Editor/utils/lifecycle"; +import type { DefineComponent } from "vue"; +import { useEditor } from "@/views/Editor/app"; +import { runWhenIdle } from "@/views/Editor/utils/async"; +import { + IMLeaferCanvas, + MLeaferCanvas, +} from "@/views/Editor/core/canvas/mLeaferCanvas"; +import { Zoom } from "@/views/Editor/app/editor/zoom"; +import { ToolBar } from "@/views/Editor/app/editor/toolBar"; +import { + IUndoRedoService, + UndoRedoService, +} from "@/views/Editor/app/editor/undoRedo/undoRedoService"; +import { Clipboard } from "@/views/Editor/app/editor/clipboard"; export class EditorMain extends BaseApp { - public service!: IInstantiationService + public service!: IInstantiationService; - private readonly pluginInstance = new Map() + private readonly pluginInstance = new Map(); - public contextMenu: ContextMenu | undefined + public contextMenu: ContextMenu | undefined; - constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) { - super() + constructor( + @IInstantiationService + private readonly instantiationService: IInstantiationService + ) { + super(); } public startup() { super.scopeRun(() => { - this.service = this.initServices() + this.service = this.initServices(); this.service.invokeFunction((accessor) => { - const workspacesService = accessor.get(IWorkspacesService) + const workspacesService = accessor.get(IWorkspacesService); if (workspacesService.size() === 0) { - workspacesService.setCurrentId(workspacesService.add('1')) + workspacesService.setCurrentId(workspacesService.add("1")); } - }) + }); const instances = [ - // TODO 标尺使用mm单位 - this.service.createInstance(Ruler), this.service.createInstance(Layer), this.service.createInstance(ToolBar), this.service.createInstance(Zoom), (this.contextMenu = this.service.createInstance(ContextMenu)), - ] + this.service.createInstance(Clipboard), + ]; instances.forEach((instance) => { - this._register(instance) - }) + this._register(instance); + }); // 插件载入 - provide('useEditor', useEditor) - const core = getActiveCore() + provide("useEditor", useEditor); + const core = getActiveCore(); core._p.forEach((plugin) => { - this.use(plugin) - }) - }) + this.use(plugin); + }); + }); } public use(plugin: EditorPlugin) { const instance = plugin({ service: this.service, use: this.use, - }) as IEditorPluginContext + }) as IEditorPluginContext; // 存储实例 - instance._id = Symbol() - this.pluginInstance.set(instance._id, instance) + instance._id = Symbol(); + this.pluginInstance.set(instance._id, instance); // 生命周期 runWhenIdle(() => { // 插件安装 - instance.setup?.() + instance.setup?.(); this._register( - toDisposable(() => { - // 插件销毁 - instance.dispose?.() - this.pluginInstance.delete(instance._id) - }), - ) - }) + toDisposable(() => { + // 插件销毁 + instance.dispose?.(); + this.pluginInstance.delete(instance._id); + }) + ); + }); } private initServices() { - const services = new ServiceCollection() + const services = new ServiceCollection(); - const define = (id: ServiceIdentifier, ctor: new (...args: any[]) => T) => { + const define = ( + id: ServiceIdentifier, + ctor: new (...args: any[]) => T + ) => { if (!services.has(id)) { - services.set(id, new SyncDescriptor(ctor)) + services.set(id, new SyncDescriptor(ctor)); } - } - define(IEventbusService, EventbusService) - define(IWorkspacesService, WorkspacesService) - define(IMLeaferCanvas, MLeaferCanvas) - define(IUndoRedoService, UndoRedoService) - define(IKeybindingService, KeybindingService) + }; + define(IEventbusService, EventbusService); + define(IWorkspacesService, WorkspacesService); + define(IMLeaferCanvas, MLeaferCanvas); + define(IUndoRedoService, UndoRedoService); + define(IKeybindingService, KeybindingService); - return this.instantiationService.createChild(services) + return this.instantiationService.createChild(services); } public dispose() { try { - provide('useEditor', undefined) - super.dispose() + provide("useEditor", undefined); + super.dispose(); this.service.invokeFunction((accessor) => { - accessor.get(IKeybindingService).reset() - accessor.get(IUndoRedoService).reset() - accessor.get(IWorkspacesService).dispose() - accessor.get(IEventbusService).all.clear() - }) - this.service = undefined! + accessor.get(IKeybindingService).reset(); + accessor.get(IUndoRedoService).reset(); + accessor.get(IWorkspacesService).dispose(); + accessor.get(IEventbusService).all.clear(); + }); + this.service = undefined!; } catch (_e) { - console.error(_e) + console.error(_e); } } public getPluginSlots(name: UsableSolts) { - const pluginSlots: DefineComponent<{}, {}, any>[] = [] + const pluginSlots: DefineComponent<{}, {}, any>[] = []; this.pluginInstance.forEach((plugin) => { - if (!plugin.slots) return - const slots = plugin.slots[name] - slots && pluginSlots.push(...slots) - }) - return pluginSlots + if (!plugin.slots) return; + const slots = plugin.slots[name]; + slots && pluginSlots.push(...slots); + }); + return pluginSlots; } } diff --git a/src/views/Editor/core/canvas/mLeaferCanvas.ts b/src/views/Editor/core/canvas/mLeaferCanvas.ts index cdfc2c6..bfacf08 100644 --- a/src/views/Editor/core/canvas/mLeaferCanvas.ts +++ b/src/views/Editor/core/canvas/mLeaferCanvas.ts @@ -1,7 +1,8 @@ import {createDecorator} from '@/views/Editor/core/instantiation/instantiation' -import {ILeafer, IPointData, IUI, IUIInputData} from "@leafer-ui/interface"; +import {ICanvasContext2D, ILeafer, IPointData, IUI, IUIInputData} from "@leafer-ui/interface"; import {App, ChildEvent, Frame, Leafer, PropertyEvent, ResizeEvent} from "leafer-ui"; import '@leafer-in/editor' +import {Ruler} from 'leafer-x-ruler' import {IWorkspacesService, WorkspacesService} from "@/views/Editor/core/workspaces/workspacesService"; import {EventbusService, IEventbusService} from "@/views/Editor/core/eventbus/eventbusService"; import {typeUtil} from "@/views/Editor/utils/utils"; @@ -21,6 +22,7 @@ type ExtendedOption = { } type ObjectType = + // 官方元素tag 'UI' | 'App' | 'Leafer' @@ -34,6 +36,8 @@ type ObjectType = | 'Text' | 'Pen' | 'HTMLText' + // 自定义元素tag + | 'Image2' interface Page { children: any @@ -79,6 +83,10 @@ export class MLeaferCanvas { private _app?: App // 内容层 private _contentLayer?: ILeafer + + // 标尺 + public ruler: Ruler + // 内容画板 private _contentFrame: Frame // 操作选项 @@ -93,24 +101,23 @@ export class MLeaferCanvas { public readonly ref = { zoom: ref(toFixed(this.getZoom(), 2)), _children: computed(() => this.contentFrame.children), + // 是否启用辅助线 + enabledRuler: computed(() => this.ruler.enabled), } public backgroundColor?: string - // 是否启用辅助线 - public enabledRuler: boolean = true - constructor( @IWorkspacesService private readonly workspacesService: WorkspacesService, @IEventbusService private readonly eventbus: EventbusService, ) { const app = new App({ - width: 793, - height: 1122, + width: 800, + height: 800, editor: {}, }) this.wrapperEl = app.canvas.view - + this.ruler = new Ruler(app) const contentLayer = app.tree contentLayer.fill = 'transparent' // TODO 2023-11-10 等待修复Leafer的fill的功能后放开下面注释启用背景填充 @@ -118,7 +125,6 @@ export class MLeaferCanvas { // type:'image', // url:'https://www.toptal.com/designers/subtlepatterns/uploads/white_carbon.png' // } - this._contentLayer = contentLayer this._app = app this.pageId = this.workspacesService.getCurrentId() @@ -137,6 +143,7 @@ export class MLeaferCanvas { this.discardActiveObject() } }) + } // 工作区 | 页面管理 @@ -233,10 +240,11 @@ export class MLeaferCanvas { let initFrameWH = true // resize事件 this.contentLayer.on(ResizeEvent.RESIZE, (e2: ResizeEvent) => { - // if (initFrameWH){ - // this.contentFrame.width = e2.width - // this.contentFrame.height = e2.height - // } + if (initFrameWH){ + // 第一次初始化画布时设置画布宽高为可视区域大小 + this.contentFrame.width = e2.width + this.contentFrame.height = e2.height + } this.eventbus.emit('layoutResizeEvent', e2) initFrameWH = false }) @@ -374,6 +382,13 @@ export class MLeaferCanvas { this.selectObject(_child) this.childrenEffect() } + /** + * 添加元素 + */ + public addMany(..._children: IUI[]) { + this.contentFrame.addMany(..._children) + this.childrenEffect() + } /** * 重新加载json数据(一般用于切换页面) @@ -472,6 +487,7 @@ export class MLeaferCanvas { } } + public setZoom(scale: number | undefined) { // TODO 处理初次切换页面时页面展示的缩放值不匹配的问题 this.zoomToInnerPoint(scale) @@ -506,4 +522,4 @@ export class MLeaferCanvas { }) return objects } -} +} \ No newline at end of file diff --git a/src/views/Editor/core/clipboard/clipboardService.ts b/src/views/Editor/core/clipboard/clipboardService.ts new file mode 100644 index 0000000..819c546 --- /dev/null +++ b/src/views/Editor/core/clipboard/clipboardService.ts @@ -0,0 +1,96 @@ +import { createDecorator } from '@/views/Editor/core/instantiation/instantiation' +import { registerSingleton, InstantiationType } from '@/views/Editor/core/instantiation/extensions' + +export const IClipboardService = createDecorator('clipboardService') + +export class ClipboardService { + declare readonly _serviceBrand: undefined + + private memoryBlob: Blob[] | undefined + + private async readMemoryBlob(): Promise { + return this.memoryBlob + } + + private async writeMemoryBlob(blob: Blob[]): Promise { + this.memoryBlob = blob + } + + public async writeBlob(blob: Blob): Promise { + try { + // 写入内存 + this.writeMemoryBlob([blob]) + return await navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]) + } catch (error) { + console.error(error) + } + } + + public async readBlob(): Promise { + try { + const clipboardItems = await navigator.clipboard.read() + const blobs: Blob[] = [] + for (const clipboardItem of clipboardItems) { + for (const type of clipboardItem.types) { + blobs.push(await clipboardItem.getType(type)) + } + } + return blobs + } catch (error) { + console.error(error) + // 读取内存 + return await this.readMemoryBlob() + } + } + + async writeText(text: string): Promise { + // Guard access to navigator.clipboard with try/catch + // as we have seen DOMExceptions in certain browsers + // due to security policies. + try { + return await navigator.clipboard.writeText(text) + } catch (error) { + console.error(error) + } + + // Fallback to textarea and execCommand solution + + const activeElement = document.activeElement + + const textnode = document.createElement('textarea') + textnode.setAttribute('aria-hidden', 'true') + const textArea: HTMLTextAreaElement = document.body.appendChild(textnode) + textArea.style.height = '1px' + textArea.style.width = '1px' + textArea.style.position = 'absolute' + + textArea.value = text + textArea.focus() + textArea.select() + + document.execCommand('copy') + + if (activeElement instanceof HTMLElement) { + activeElement.focus() + } + + document.body.removeChild(textArea) + + return + } + + async readText(): Promise { + try { + return await navigator.clipboard.readText() + } catch (error) { + console.error(error) + return '' + } + } +} + +registerSingleton(IClipboardService, ClipboardService, InstantiationType.Eager) \ No newline at end of file diff --git a/src/views/Editor/layouts/header/headerBar.vue b/src/views/Editor/layouts/header/headerBar.vue index 6f23728..e06c54b 100644 --- a/src/views/Editor/layouts/header/headerBar.vue +++ b/src/views/Editor/layouts/header/headerBar.vue @@ -5,13 +5,9 @@

不做简历

-
- - +
+ + +
@@ -27,7 +23,6 @@
@@ -47,43 +42,43 @@ import { Platform, Group, Text, Line, Rect, Image } from "leafer-ui"; import { getDefaultName } from "@/views/Editor/utils/utils"; import Zoom from "./left/zoom.vue"; import SaveOper from "./right/saveOper.vue"; +import { selectFiles } from "@/utils/designUtil"; Platform.image.suffix = ""; -const { keybinding, editor } = useEditor(); - -const changeLineGuides = () => { - keybinding.trigger("shift+r"); -} -const dragStart = (e: Element, item: any) => {} - +const { canvas, editor } = useEditor(); const iconList = ref([ { name: "icon-24gl-pointer", content: "选择", type: "point" }, - // { name: 'icon-bianji', content: '铅笔', type: 'pencil' }, { name: "icon-editor-text", content: "文字", type: "text" }, { name: "icon-fengexian", content: "线", type: "line" }, { name: "icon-kuang", content: "框", type: "box" }, { name: "icon-tupian", content: "图片", type: "img" }, ]); - const nowSelectOp = ref({ name: "icon-24gl-pointer", content: "选择", type: "point", }) -function selectOp(item: any) { - if (item === -1) { - changeLineGuides() - } else { - nowSelectOp.value = item - iconClick(item) - } +const selectOp = (item: any) => { + nowSelectOp.value = item + iconClick(item) } -function gotoGithub() { +const gotoGithub = () => { window.open("https://github.com/shuangxunian/no-resume", "_blank"); } +const importJsonFile = () => { + selectFiles({ accept: ".json" }).then((files: any) => { + const [file] = files + const reader = new FileReader() + reader.readAsText(file, "UTF-8") + reader.onload = () => { + canvas.importJsonToCurrentPage(JSON.parse(reader.result), true) + } + }) +} + const addText = (item: any) => { let text; if (editor.objectIsTypes(item.json, "Text")) { @@ -215,6 +210,7 @@ const iconClick = (item: any) => { border-radius: 8px; line-height: 32px; text-align: center; + cursor: pointer; } .select-icon-box { background-color: #e9e7ef; diff --git a/src/views/Editor/layouts/header/left/fileOper.vue b/src/views/Editor/layouts/header/left/fileOper.vue index 670d8c6..cb44ee7 100644 --- a/src/views/Editor/layouts/header/left/fileOper.vue +++ b/src/views/Editor/layouts/header/left/fileOper.vue @@ -1,227 +1,233 @@ - + diff --git a/src/views/Editor/layouts/header/right/saveOper.vue b/src/views/Editor/layouts/header/right/saveOper.vue index 32b35dc..0806b7b 100644 --- a/src/views/Editor/layouts/header/right/saveOper.vue +++ b/src/views/Editor/layouts/header/right/saveOper.vue @@ -6,12 +6,6 @@ 预览 - - - 保存 - 下载作品