修改看版配置
parent
ea2754a41c
commit
a8791791d7
@ -1,214 +1,215 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="renderer" content="webkit" />
|
<meta name="renderer" content="webkit" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" />
|
||||||
<title>智造MOM平台系统</title>
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<!--[if lt IE 11
|
<title>智造MOM平台系统</title>
|
||||||
]><script>
|
<!--[if lt IE 11
|
||||||
window.location.href = '/html/ie.html';
|
]><script>
|
||||||
</script><!
|
window.location.href = '/html/ie.html';
|
||||||
[endif]-->
|
</script><!
|
||||||
<style>
|
[endif]-->
|
||||||
html,
|
<style>
|
||||||
body,
|
html,
|
||||||
#app {
|
body,
|
||||||
height: 100%;
|
#app {
|
||||||
margin: 0px;
|
height: 100%;
|
||||||
padding: 0px;
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chromeframe {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
background: #ccc;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
margin: -75px 0 0 -75px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #fff;
|
||||||
|
-webkit-animation: spin 2s linear infinite;
|
||||||
|
-ms-animation: spin 2s linear infinite;
|
||||||
|
-moz-animation: spin 2s linear infinite;
|
||||||
|
-o-animation: spin 2s linear infinite;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #fff;
|
||||||
|
-webkit-animation: spin 3s linear infinite;
|
||||||
|
-moz-animation: spin 3s linear infinite;
|
||||||
|
-o-animation: spin 3s linear infinite;
|
||||||
|
-ms-animation: spin 3s linear infinite;
|
||||||
|
animation: spin 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #fff;
|
||||||
|
-moz-animation: spin 1.5s linear infinite;
|
||||||
|
-o-animation: spin 1.5s linear infinite;
|
||||||
|
-ms-animation: spin 1.5s linear infinite;
|
||||||
|
-webkit-animation: spin 1.5s linear infinite;
|
||||||
|
animation: spin 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chromeframe {
|
100% {
|
||||||
margin: 0.2em 0;
|
-webkit-transform: rotate(360deg);
|
||||||
background: #ccc;
|
-ms-transform: rotate(360deg);
|
||||||
color: #000;
|
transform: rotate(360deg);
|
||||||
padding: 0.2em 0;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#loader-wrapper {
|
100% {
|
||||||
position: fixed;
|
-webkit-transform: rotate(360deg);
|
||||||
top: 0;
|
-ms-transform: rotate(360deg);
|
||||||
left: 0;
|
transform: rotate(360deg);
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 999999;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#loader {
|
#loader-wrapper .loader-section {
|
||||||
display: block;
|
position: fixed;
|
||||||
position: relative;
|
top: 0;
|
||||||
left: 50%;
|
width: 51%;
|
||||||
top: 50%;
|
height: 100%;
|
||||||
width: 150px;
|
background: #7171c6;
|
||||||
height: 150px;
|
z-index: 1000;
|
||||||
margin: -75px 0 0 -75px;
|
-webkit-transform: translateX(0);
|
||||||
border-radius: 50%;
|
-ms-transform: translateX(0);
|
||||||
border: 3px solid transparent;
|
transform: translateX(0);
|
||||||
border-top-color: #fff;
|
}
|
||||||
-webkit-animation: spin 2s linear infinite;
|
|
||||||
-ms-animation: spin 2s linear infinite;
|
|
||||||
-moz-animation: spin 2s linear infinite;
|
|
||||||
-o-animation: spin 2s linear infinite;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
z-index: 1001;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loader:before {
|
#loader-wrapper .loader-section.section-left {
|
||||||
content: '';
|
left: 0;
|
||||||
position: absolute;
|
}
|
||||||
top: 5px;
|
|
||||||
left: 5px;
|
|
||||||
right: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 3px solid transparent;
|
|
||||||
border-top-color: #fff;
|
|
||||||
-webkit-animation: spin 3s linear infinite;
|
|
||||||
-moz-animation: spin 3s linear infinite;
|
|
||||||
-o-animation: spin 3s linear infinite;
|
|
||||||
-ms-animation: spin 3s linear infinite;
|
|
||||||
animation: spin 3s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loader:after {
|
#loader-wrapper .loader-section.section-right {
|
||||||
content: '';
|
right: 0;
|
||||||
position: absolute;
|
}
|
||||||
top: 15px;
|
|
||||||
left: 15px;
|
|
||||||
right: 15px;
|
|
||||||
bottom: 15px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 3px solid transparent;
|
|
||||||
border-top-color: #fff;
|
|
||||||
-moz-animation: spin 1.5s linear infinite;
|
|
||||||
-o-animation: spin 1.5s linear infinite;
|
|
||||||
-ms-animation: spin 1.5s linear infinite;
|
|
||||||
-webkit-animation: spin 1.5s linear infinite;
|
|
||||||
animation: spin 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes spin {
|
.loaded #loader-wrapper .loader-section.section-left {
|
||||||
0% {
|
-webkit-transform: translateX(-100%);
|
||||||
-webkit-transform: rotate(0deg);
|
-ms-transform: translateX(-100%);
|
||||||
-ms-transform: rotate(0deg);
|
transform: translateX(-100%);
|
||||||
transform: rotate(0deg);
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
}
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
100% {
|
.loaded #loader-wrapper .loader-section.section-right {
|
||||||
-webkit-transform: rotate(360deg);
|
-webkit-transform: translateX(100%);
|
||||||
-ms-transform: rotate(360deg);
|
-ms-transform: translateX(100%);
|
||||||
transform: rotate(360deg);
|
transform: translateX(100%);
|
||||||
}
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
}
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
.loaded #loader {
|
||||||
0% {
|
opacity: 0;
|
||||||
-webkit-transform: rotate(0deg);
|
-webkit-transition: all 0.3s ease-out;
|
||||||
-ms-transform: rotate(0deg);
|
transition: all 0.3s ease-out;
|
||||||
transform: rotate(0deg);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
.loaded #loader-wrapper {
|
||||||
-webkit-transform: rotate(360deg);
|
visibility: hidden;
|
||||||
-ms-transform: rotate(360deg);
|
-webkit-transform: translateY(-100%);
|
||||||
transform: rotate(360deg);
|
-ms-transform: translateY(-100%);
|
||||||
}
|
transform: translateY(-100%);
|
||||||
}
|
-webkit-transition: all 0.3s 1s ease-out;
|
||||||
|
transition: all 0.3s 1s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
#loader-wrapper .loader-section {
|
.no-js #loader-wrapper {
|
||||||
position: fixed;
|
display: none;
|
||||||
top: 0;
|
}
|
||||||
width: 51%;
|
|
||||||
height: 100%;
|
|
||||||
background: #7171c6;
|
|
||||||
z-index: 1000;
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
-ms-transform: translateX(0);
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#loader-wrapper .loader-section.section-left {
|
.no-js h1 {
|
||||||
left: 0;
|
color: #222222;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loader-wrapper .loader-section.section-right {
|
#loader-wrapper .load_title {
|
||||||
right: 0;
|
font-family: 'Open Sans';
|
||||||
}
|
color: #fff;
|
||||||
|
font-size: 19px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 9999999999999;
|
||||||
|
position: absolute;
|
||||||
|
top: 60%;
|
||||||
|
opacity: 1;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.loaded #loader-wrapper .loader-section.section-left {
|
#loader-wrapper .load_title span {
|
||||||
-webkit-transform: translateX(-100%);
|
font-weight: normal;
|
||||||
-ms-transform: translateX(-100%);
|
font-style: italic;
|
||||||
transform: translateX(-100%);
|
font-size: 13px;
|
||||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
color: #fff;
|
||||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
.loaded #loader-wrapper .loader-section.section-right {
|
<body>
|
||||||
-webkit-transform: translateX(100%);
|
<div id="app">
|
||||||
-ms-transform: translateX(100%);
|
<div id="loader-wrapper">
|
||||||
transform: translateX(100%);
|
<div id="loader"></div>
|
||||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
<div class="loader-section section-left"></div>
|
||||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
<div class="loader-section section-right"></div>
|
||||||
}
|
<div class="load_title">正在加载系统资源,请耐心等待</div>
|
||||||
|
</div>
|
||||||
.loaded #loader {
|
</div>
|
||||||
opacity: 0;
|
<script type="module" src="/src/main.ts"></script>
|
||||||
-webkit-transition: all 0.3s ease-out;
|
</body>
|
||||||
transition: all 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loaded #loader-wrapper {
|
|
||||||
visibility: hidden;
|
|
||||||
-webkit-transform: translateY(-100%);
|
|
||||||
-ms-transform: translateY(-100%);
|
|
||||||
transform: translateY(-100%);
|
|
||||||
-webkit-transition: all 0.3s 1s ease-out;
|
|
||||||
transition: all 0.3s 1s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-js #loader-wrapper {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-js h1 {
|
|
||||||
color: #222222;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loader-wrapper .load_title {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
color: #fff;
|
|
||||||
font-size: 19px;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 9999999999999;
|
|
||||||
position: absolute;
|
|
||||||
top: 60%;
|
|
||||||
opacity: 1;
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loader-wrapper .load_title span {
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #fff;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app">
|
|
||||||
<div id="loader-wrapper">
|
|
||||||
<div id="loader"></div>
|
|
||||||
<div class="loader-section section-left"></div>
|
|
||||||
<div class="loader-section section-right"></div>
|
|
||||||
<div class="load_title">正在加载系统资源,请耐心等待</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="module" src="/src/main.ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,39 +1,255 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="overflow:hidden;">
|
||||||
<div class="ep-draggable-item" />
|
<div class="top">
|
||||||
<div id="hiprint-printTemplate" />
|
<div style="line-height: 60px;margin-left: 12px;">
|
||||||
<div id="PrintElementOptionSetting" />
|
<el-button-group>
|
||||||
|
<el-button :type="pageType === 'A3' ? 'primary' : ''" @click="setPage('A3',42,29.7)">A3</el-button>
|
||||||
|
<el-button :type="pageType === 'A4' ? 'primary' : ''" @click="setPage('A4',21,29.7)">A4</el-button>
|
||||||
|
<el-button :type="pageType === 'A5' ? 'primary' : ''" @click="setPage('A5',14.8,21)">A5</el-button>
|
||||||
|
<el-button :type="pageType === 'B3' ? 'primary' : ''" @click="setPage('B3',35.3,50)">B3</el-button>
|
||||||
|
<el-button :type="pageType === 'B4' ? 'primary' : ''" @click="setPage('B4',25,35.2)">B4</el-button>
|
||||||
|
<el-button :type="pageType === 'B5' ? 'primary' : ''" @click="setPage('B5',17.6,25)">B5</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
<el-button @click="zoomChange(-0.1)" icon="ZoomOut" circle style="margin-left: 12px;" />
|
||||||
|
<el-input v-model="zoomInput" disabled style="margin-left: 8px;width:100px" />
|
||||||
|
<el-button @click="zoomChange(0.1)" icon="ZoomIn" circle style="margin-left: 8px;" />
|
||||||
|
<el-button type="primary" @click="view" style="margin-left: 12px;">预览</el-button>
|
||||||
|
<el-button type="primary" @click="save" style="margin-left: 12px;">保存</el-button>
|
||||||
|
<el-button type="primary" @click="clear" style="margin-left: 12px;">清空</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="leftPanel">
|
||||||
|
<h4>基础组件</h4>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'text',pid)" class="mx-1" size="large">文字</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'image',pid)" class="mx-1" size="large">图片</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'barCode',pid)" class="mx-1" size="large">条形码
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'QRCode',pid)" class="mx-1" size="large">二维码
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'dateTime',pid)" class="mx-1" size="large">日期时间
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'transverseLine',pid)" class="mx-1" size="large">横线
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'verticalLine',pid)" class="mx-1" size="large">竖线
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'rectangle',pid)" class="mx-1" size="large">矩形
|
||||||
|
</el-tag>
|
||||||
|
<el-tag :draggable="true" @dragstart="onDragStart($event, 'circle',pid)" class="mx-1" size="large">圆形
|
||||||
|
</el-tag>
|
||||||
|
<h4>表单组件</h4>
|
||||||
|
</div>
|
||||||
|
<div class="content" @drop="onDrop">
|
||||||
|
<div class="flowArea" :style="{width:zoom * cmToPx(pageWidth)+'px',height:zoom * cmToPx(pageHeight)+'px'}">
|
||||||
|
<VueFlow :autoPanSpeed="0" :min-zoom="0.01" ref="flowRef" v-model:nodes="nodes" v-model:edges="edges"
|
||||||
|
:zoomOnScroll="false"
|
||||||
|
:snapToGrid="isSnapToGrid" :snapGrid="[cmToPx(0.5), cmToPx(0.5)]"
|
||||||
|
:panOnDrag="false"
|
||||||
|
fit-view-on-init
|
||||||
|
default-marker-color="#409EFF"
|
||||||
|
@dragover="onDragOver"
|
||||||
|
@node-click="logEvent('click', $event)"
|
||||||
|
@pane-click="logEvent('paneClick', $event)"
|
||||||
|
@node-drag-start="logEvent('nodeDrag', $event)"
|
||||||
|
>
|
||||||
|
<Background variant="lines" :size="0.4" :gap="cmToPx(0.5)" pattern-color="#ddd"
|
||||||
|
style="background-color: #fff" />
|
||||||
|
|
||||||
|
<template #node-area="areaNodeProps">
|
||||||
|
<AreaNode v-bind="areaNodeProps"
|
||||||
|
:pageData="{width: cmToPx(pageWidth)+'px',height: cmToPx(pageHeight)+'px'}"></AreaNode>
|
||||||
|
</template>
|
||||||
|
<template #node-text="textNodeProps">
|
||||||
|
<TextNode v-bind="textNodeProps"
|
||||||
|
:pageSize="{width:zoom * cmToPx(pageWidth) ,height:zoom * cmToPx(pageHeight) }"></TextNode>
|
||||||
|
</template>
|
||||||
|
</VueFlow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="rightPanel" style="padding: 8px">
|
||||||
|
<el-form :model="nodeAttrForm" label-width="auto" style="max-width: 600px">
|
||||||
|
<el-form-item label="名称" v-if="Object.keys(nodeAttrForm).includes('name')">
|
||||||
|
<el-input v-model="nodeAttrForm.name" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段名" v-if="Object.keys(nodeAttrForm).includes('field')">
|
||||||
|
<el-input v-model="nodeAttrForm.field" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="缺省显示" v-if="Object.keys(nodeAttrForm).includes('default')">
|
||||||
|
<el-input v-model="nodeAttrForm.default" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import { hiprint, defaultElementTypeProvider } from 'vue-plugin-hiprint';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { VueFlow, useVueFlow } from '@vue-flow/core';
|
||||||
|
import { Background } from '@vue-flow/background';
|
||||||
|
import { StarFilled } from '@element-plus/icons-vue';
|
||||||
|
import tool, { options } from './tool';
|
||||||
|
import AreaNode from './nodes/areaNode.vue';
|
||||||
|
import TextNode from './nodes/textNode.vue';
|
||||||
|
|
||||||
console.log([new defaultElementTypeProvider()]);
|
const router = useRouter();
|
||||||
hiprint.init({
|
// 获取自定义的方法
|
||||||
providers: [new defaultElementTypeProvider()]
|
const { onDragStart, onDrop, onDragOver } = tool();
|
||||||
});
|
const { cmToPx } = options;
|
||||||
hiprint.PrintElementTypeManager.buildByHtml($('.ep-draggable-item'));
|
|
||||||
let hiprintTemplate = new hiprint.PrintTemplate({
|
const flowRef = ref();
|
||||||
template: {}, // 模板json
|
const isSnapToGrid = ref(true);
|
||||||
settingContainer: '#PrintElementOptionSetting', // 元素参数容器
|
const pageWidth = ref(21);
|
||||||
history: true, // 是否需要 撤销重做功能
|
const pageHeight = ref(29.7);
|
||||||
onDataChanged: (type, json) => {
|
const pageType = ref('A4');
|
||||||
// 模板发生改变回调
|
const zoom = ref(1);
|
||||||
console.log(type); // 新增、移动、删除、修改(参数调整)、大小、旋转
|
const zoomInput = ref('100%');
|
||||||
console.log(json); // 返回 template
|
const nodeAttrForm = ref({});
|
||||||
},
|
const pid = ref(`area_${uuidv4().replaceAll('-', '_')}`);
|
||||||
onUpdateError: (e) => {
|
|
||||||
// 更新失败回调
|
const logEvent = async (eventname, event) => {
|
||||||
console.log(e);
|
switch (eventname) {
|
||||||
|
case 'paneClick':
|
||||||
|
nodeAttrForm.value = {};
|
||||||
|
break;
|
||||||
|
case 'click':
|
||||||
|
nodeAttrForm.value = event.node.data.options;
|
||||||
|
break;
|
||||||
|
case 'nodeDrag':
|
||||||
|
console.log(event.nodes);
|
||||||
|
if (event.nodes.length === 1) {
|
||||||
|
nodeAttrForm.value = event.node.data.options;
|
||||||
|
} else {
|
||||||
|
nodeAttrForm.value = {};
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
const nodes = ref([{
|
||||||
|
id: pid.value,
|
||||||
|
name: 'area',
|
||||||
|
type: 'area',
|
||||||
|
position: {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
|
}]);
|
||||||
|
const edges = ref([]);
|
||||||
|
|
||||||
|
const setPage = (type, width, height) => {
|
||||||
|
pageType.value = type;
|
||||||
|
pageHeight.value = height;
|
||||||
|
pageWidth.value = width;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoomChange = (e) => {
|
||||||
|
console.log(flowRef.value.autoPanSpeed);
|
||||||
|
flowRef.value.viewport.x = 0;
|
||||||
|
flowRef.value.viewport.y = 0;
|
||||||
|
let num = zoom.value;
|
||||||
|
num += e;
|
||||||
|
zoom.value = parseFloat(Math.min(2, Math.max(0.2, num)).toFixed(2));
|
||||||
|
zoomInput.value = (zoom.value * 100).toFixed(0) + '%';
|
||||||
|
flowRef.value.setTransform({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
zoom: zoom.value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const view = () => {
|
||||||
|
|
||||||
|
};
|
||||||
|
const save = () => {
|
||||||
|
};
|
||||||
|
const clear = () => {
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
flowRef.value.onInit(() => {
|
||||||
|
flowRef.value.setTransform({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
zoom: 1
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
// 设计器的容器
|
watch(() => flowRef.value?.viewport, () => {
|
||||||
hiprintTemplate.design('#hiprint-printTemplate');
|
if (flowRef.value && (flowRef.value.viewport.x !== 0 || flowRef.value.viewport.y !== 0)) {
|
||||||
|
console.log('重置原点');
|
||||||
|
flowRef.value.setTransform({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
zoom: zoom.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
const toggleSnapToGrid = (e) => {
|
||||||
|
if (e.key === 'Alt') {
|
||||||
|
isSnapToGrid.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const keyup = () => {
|
||||||
|
isSnapToGrid.value = true;
|
||||||
|
};
|
||||||
|
window.addEventListener('keydown', toggleSnapToGrid);
|
||||||
|
window.addEventListener('keyup', keyup);
|
||||||
|
// flow内置方法
|
||||||
|
const {
|
||||||
|
updateNode
|
||||||
|
} = useVueFlow();
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style lang="less" scoped>
|
||||||
.ep-draggable-item, #hiprint-printTemplate, #PrintElementOptionSetting {
|
:deep(.vue-flow__node-area) {
|
||||||
|
z-index: -1 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tag) {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
height: 64px;
|
||||||
|
margin: 8px 8px 0 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
width: calc(100% - 16px);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
height: calc(100vh - 64px - 16px - 8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.leftPanel, .rightPanel {
|
||||||
|
vertical-align: top;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
|
margin: 8px 8px 0;
|
||||||
|
overflow: auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
vertical-align: top;
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100vw - 300px - 300px - 16px - 16px);
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flowArea {
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div style="pointer-events: none">
|
||||||
|
<div class="custom-node">
|
||||||
|
<div class="area"
|
||||||
|
:style='`width:${props.pageData?.width || "100px"};height:${props.pageData?.height || "100px"};border: 1px solid #fff;`'></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
pageData: {
|
||||||
|
type: Object,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.area {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
|
||||||
|
<NodeResizer :min-width="96 / 2.54" :min-height="96 / 2.54" :max-width="pageSize.width"
|
||||||
|
:max-height="pageSize.height" color="#000"
|
||||||
|
v-if="!props.isView && !props.isHideHandle && props.selected" />
|
||||||
|
|
||||||
|
<div class="custom-node"
|
||||||
|
:style="{textAlign:props.data.options.align,width:props.dimensions.width+'px',lineHeight:props.dimensions.height+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
|
||||||
|
<img :src="props.data.options.imageSrc"
|
||||||
|
:style="{color:props.data.options.color,fontSize:props.dimensions.height+'px'}" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
import { NodeResizer } from '@vue-flow/node-resizer';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isView: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
isHideHandle: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageData: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.custom-node {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
|
||||||
|
<NodeResizer :min-width="96 / 2.54" :min-height="96 / 2.54" :max-width="pageSize.width"
|
||||||
|
:max-height="pageSize.height" color="#000"
|
||||||
|
v-if="!props.isView && !props.isHideHandle && props.selected" />
|
||||||
|
|
||||||
|
<div class="custom-node"
|
||||||
|
:style="{textAlign:props.data.options.align,width:props.dimensions.width+'px',lineHeight:props.dimensions.height+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
|
||||||
|
<span
|
||||||
|
:style="{color:props.data.options.color,fontSize:props.dimensions.height+'px'}">
|
||||||
|
{{ props.data.options.name || '文字' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
import { NodeResizer } from '@vue-flow/node-resizer';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
isView: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
isHideHandle: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageData: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.custom-node {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,109 @@
|
|||||||
|
import { useVueFlow } from '@vue-flow/core';
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
|
||||||
|
const getId = (type) => {
|
||||||
|
return `${type}_${uuidv4().replaceAll('-', '_')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cmToPx = (cm) => {
|
||||||
|
return cm * 96 / 2.54;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const getOption = (e) => {
|
||||||
|
if (e === 'text') {
|
||||||
|
return { name: '', field: '', default: '' };
|
||||||
|
} else if (e === 'image') {
|
||||||
|
return { name: '', field: '', imageSrc: '', imageType: '' };
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getNodeSize = (e) => {
|
||||||
|
if (e === 'line' || e === 'multiLines' || e === 'bar' || e === 'multiBars' || e === 'curve' || e === 'multiCurves' || e === 'customBoard' || e === 'pie') {
|
||||||
|
return { width: cmToPx(5), height: cmToPx(2) };
|
||||||
|
} else {
|
||||||
|
return { width: cmToPx(5), height: cmToPx(2) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tool = () => {
|
||||||
|
const nodeType = ref('');
|
||||||
|
const parentId = ref('');
|
||||||
|
const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow();
|
||||||
|
const onDragStart = (event, type, pid) => {
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
event.dataTransfer.setData('application/vueflow', type);
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeType.value = type;
|
||||||
|
parentId.value = pid;
|
||||||
|
document.addEventListener('drop', onDragEnd);
|
||||||
|
};
|
||||||
|
const onDragEnd = () => {
|
||||||
|
nodeType.value = null;
|
||||||
|
document.removeEventListener('drop', onDragEnd);
|
||||||
|
};
|
||||||
|
const onDrop = (event) => {
|
||||||
|
const dimensions = getNodeSize(nodeType.value);
|
||||||
|
|
||||||
|
const position = screenToFlowCoordinate({
|
||||||
|
x: event.clientX, y: event.clientY
|
||||||
|
});
|
||||||
|
|
||||||
|
const nodeId = getId(nodeType.value);
|
||||||
|
const newNode = {
|
||||||
|
id: nodeId,
|
||||||
|
name: nodeType.value,
|
||||||
|
type: nodeType.value,
|
||||||
|
parentNode: parentId.value,
|
||||||
|
extent: 'parent',
|
||||||
|
dimensions,
|
||||||
|
position,
|
||||||
|
data: { options: getOption(nodeType.value), outputData: {} }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const { off } = onNodesInitialized(() => {
|
||||||
|
updateNode(nodeId, (node) => ({
|
||||||
|
position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 }
|
||||||
|
}));
|
||||||
|
|
||||||
|
off();
|
||||||
|
});
|
||||||
|
|
||||||
|
addNodes(newNode);
|
||||||
|
|
||||||
|
};
|
||||||
|
const onDragOver = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (nodeType.value) {
|
||||||
|
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
onDragStart, onDragEnd, onDrop, onDragOver
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export default tool;
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
isD: false, isJSON: (str) => {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
try {
|
||||||
|
JSON.parse(str);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, cmToPx: cmToPx
|
||||||
|
};
|
Loading…
Reference in New Issue