导入流程相关组件

This commit is contained in:
xiangheng
2023-12-11 14:02:03 +08:00
parent d00e477094
commit 2474fe0cf9
94 changed files with 4409 additions and 50 deletions

View File

@@ -3,8 +3,8 @@
"editor.tabSize": 4,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"source.fixAll.eslint": "explicit"
},
"css.validate": false,
"less.validate": false,
"scss.validate": false

View File

@@ -13,6 +13,8 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@highlightjs/vue-plugin": "^2.1.0",
"@logicflow/core": "^1.2.18",
"@logicflow/extension": "^1.2.19",
"@vue/shared": "^3.3.9",
"@vueuse/core": "^10.6.1",
"@wangeditor/editor": "^5.1.23",
@@ -27,6 +29,7 @@
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"vform3-builds": "^3.0.10",
"vue": "^3.3.9",
"vue-clipboard3": "^2.0.0",
"vue-echarts": "^6.6.1",

View File

@@ -0,0 +1,108 @@
<template>
<div class="setting-container">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
label-width="100px"
label-position="top"
>
<el-form-item label="审批人去重" prop="autoRepeat">
<el-select
v-model="formData.autoRepeat"
placeholder="请选择去重类型"
:style="{ width: '100%' }"
>
<el-option
v-for="(item, index) in autoRepeatOptions"
:key="index"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
></el-option>
</el-select>
<el-checkbox v-model="formData.myAuditAutoPass"
>发起人审批时自动通过</el-checkbox
>
</el-form-item>
<el-form-item label="审批意见">
<el-checkbox v-model="formData.remarkRequired">必填</el-checkbox>
<!-- <el-checkbox v-model="formData.notVisibleForSponsor"
>对发起人不可见</el-checkbox
> -->
</el-form-item>
<el-form-item label="审批意见填写提示" prop="remarkTip">
<el-input
v-model="formData.remarkTip"
type="textarea"
placeholder="请输入"
:maxlength="100"
show-word-limit
:autosize="{ minRows: 4, maxRows: 4 }"
:style="{ width: '100%' }"
></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
components: {},
props: ["conf"],
data() {
return {
formData: {
autoRepeat: false, //审批人去重
myAuditAutoPass: false, //发起人审批时自动通过
remarkTip: "", //审批意见填写提示
remarkRequired: false,
notVisibleForSponsor: false,
},
rules: {
autoRepeat: [
{
required: true,
message: "请选择选择分组",
trigger: "change",
},
],
},
autoRepeatOptions: [
{
label: "启用自动去重",
value: true,
},
{
label: "不启用自动去重",
value: false,
},
],
};
},
created() {
if (typeof this.conf === "object" && this.conf !== null) {
Object.assign(this.formData, this.conf);
}
},
methods: {
getData() {
return this.formData;
},
},
};
</script>
<style lang="scss" scoped>
.setting-container {
width: 600px;
height: 100%;
margin: auto;
background: white;
padding: 16px;
// >>> .el-form--label-top .el-form-item__label {
// padding-bottom: 0;
// }
}
</style>

View File

@@ -0,0 +1,303 @@
<template>
<el-dialog
v-model="dialogVisible"
append-to-body
:show-close="false"
:fullscreen="true"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
top="1px"
style="height: 100vh"
class="flow-config-dialog"
>
<template #header="{ close, titleId, titleClass }">
<header class="page__header">
<div class="page-actions">
{{ title }}
</div>
<div class="step-tab">
<div
v-for="(item, index) in steps"
:key="index"
class="step"
:class="[activeStep == item.key ? 'active' : '']"
@click="changeSteps(item)"
>
<span class="step-index">{{ index + 1 }}</span>
{{ item.label }}
</div>
</div>
<el-button class="publish-btn" @click="close">关闭</el-button>
<el-button class="publish-btn" type="primary" @click="publish">发布</el-button>
</header>
</template>
<div class="page__content" v-if="mockData">
<BasicSetting
ref="basicSetting"
:conf="mockData.basicSetting"
v-show="activeStep === 'basicSetting'"
tabName="basicSetting"
/>
<XForm
ref="formDesign"
:conf="mockData.flowFormData"
v-show="activeStep === 'formDesign'"
tabName="formDesign"
/>
<Diagram
ref="processDesign"
v-show="activeStep === 'processDesign'"
tabName="processDesign"
:fieldList="fieldList"
:conf="mockData.flowProcessData"
></Diagram>
<AdvancedSetting
ref="advancedSetting"
:conf="mockData.advancedSetting"
v-show="activeStep === 'advancedSetting'"
/>
</div>
</el-dialog>
</template>
<script>
import XForm from './XForm/index.vue'
import Diagram from './flowEdit/Diagram.vue'
import BasicSetting from './BasicSetting/index.vue'
import AdvancedSetting from './AdvancedSetting/index.vue'
const beforeUnload = function (e) {
const confirmationMessage = '离开网站可能会丢失您编辑得内容'
;(e || window.event).returnValue = confirmationMessage // Gecko and Trident
return confirmationMessage // Gecko and WebKit
}
export default {
name: 'Approver',
components: {
// Process,
Diagram,
// DynamicForm,
XForm,
BasicSetting,
AdvancedSetting
},
props: {
title: {
type: String,
default: '流程配置'
},
save: {
type: Function,
default: () => {}
}
},
data() {
return {
dialogVisible: false,
activeStep: 'basicSetting', // 激活的步骤面板
mockData: {
basicSetting: {},
flowFormData: {},
flowProcessData: {},
advancedSetting: {}
},
fieldList: [],
steps: [
{ label: '基础设置', key: 'basicSetting' },
{ label: '表单设计', key: 'formDesign' },
{ label: '流程设计', key: 'processDesign' }
// { label: "高级设置", key: "advancedSetting" },
]
}
},
beforeRouteEnter(to, from, next) {
window.addEventListener('beforeunload', beforeUnload)
next()
},
beforeRouteLeave(to, from, next) {
window.removeEventListener('beforeunload', beforeUnload)
next()
},
computed: {},
mounted() {},
methods: {
reset() {
this.mockData = {}
this.activeStep = 'basicSetting'
this.fieldList = []
},
open(data) {
this.reset()
console.log('data', data)
if (data) {
this.mockData = { ...data }
} else {
this.mockData = {
basicSetting: {},
flowFormData: {},
flowProcessData: {},
advancedSetting: {}
}
}
this.dialogVisible = true
},
async changeSteps(item) {
const fieldList = this.$refs.formDesign.getFieldWidgets()
this.fieldList = fieldList
this.activeStep = item.key
},
publish() {
const getCmpData = (name) => {
console.log(name)
return this.$refs[name].getData()
}
// basicSetting formDesign processDesign 返回的是Promise 因为要做校验
// advancedSetting返回的就是值
const p1 = getCmpData('basicSetting')
const p2 = getCmpData('formDesign')
const p3 = getCmpData('processDesign')
Promise.all([p1, p2, p3])
.then((res) => {
console.log('res', res)
const param = {
id: this?.mockData?.id,
basicSetting: res[0].formData,
flowFormData: res[1].formData,
flowProcessData: res[2].formData
// advancedSetting: getCmpData("advancedSetting"),
}
console.log(param)
this.sendToServer(param)
})
.catch((err) => {
console.error(err)
err.target && (this.activeStep = err.target)
err.msg && this.$message.error(err.msg)
})
},
sendToServer(param) {
this.$notify({
title: '数据已整合完成',
message: '请在控制台中查看数据输出',
position: 'bottom-right'
})
this.save(param)
.then(() => {
this.dialogVisible = false
})
.catch((err) => {
err.message && this.$message.error(err.message)
})
console.log('配置数据', param)
},
exit() {
this.$confirm('离开此页面您得修改将会丢失, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
window.history.back()
})
.catch(() => {})
}
}
}
</script>
<style>
.flow-config-dialog .el-dialog__header {
font-size: var(--el-font-size-large);
padding: 0;
margin: 0;
}
</style>
<style lang="scss" scoped>
$header-height: 54px;
.page__header {
position: fixed;
z-index: 100;
width: 100%;
height: $header-height;
display: flex;
align-items: center;
justify-content: center;
// justify-content: space-between;
box-sizing: border-box;
color: white;
background: #3296fa;
font-size: 14px;
user-select: none;
.page-actions {
line-height: $header-height;
height: 100%;
padding-left: 20px;
padding-right: 20px;
}
.step-tab {
flex: 1;
display: flex;
justify-content: center;
height: 100%;
position: relative;
> .step {
width: 140px;
line-height: $header-height;
padding-left: 30px;
padding-right: 30px;
cursor: pointer;
position: relative;
&.active > .step-index {
background: white;
color: #4483f2;
}
> .step-index {
display: inline-block;
width: 18px;
height: 18px;
border: 1px solid #fff;
border-radius: 8px;
line-height: 18px;
text-align: center;
box-sizing: border-box;
}
}
}
}
// width: 100vw;
// height: 100vh;
// padding-top: $header-height;
.page__content {
padding-top: $header-height;
height: 100%;
box-sizing: border-box;
background: #f5f5f7;
}
.publish-btn {
margin-right: 20px;
// color: #3296fa;
padding: 7px 20px;
border-radius: 4px;
font-size: 14px;
}
</style>

View File

@@ -0,0 +1,166 @@
<template>
<div class="setting-container">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
label-width="100px"
label-position="top"
>
<el-form-item label="审批名称" prop="flowName">
<el-input
v-model="formData.flowName"
placeholder="请输入审批名称"
clearable
:style="{ width: '100%' }"
>
</el-input>
</el-form-item>
<el-form-item label="选择分组" prop="flowGroup">
<el-select
v-model="formData.flowGroup"
placeholder="请选择选择分组"
clearable
:style="{ width: '100%' }"
>
<el-option
v-for="(item, index) in flowGroupOptions"
:key="index"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="谁可以发起审批" prop="approver">
<span style="font-size: 12px; color: #aaa">默认所有人</span>
</el-form-item> -->
<el-form-item label="审批说明" prop="flowRemark">
<el-input
v-model="formData.flowRemark"
type="textarea"
placeholder="请输入审批说明"
:maxlength="100"
show-word-limit
:autosize="{ minRows: 4, maxRows: 4 }"
:style="{ width: '100%' }"
></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'BasicSetting',
components: {},
props: ['tabName', 'conf'],
data() {
return {
formData: {
flowName: '',
flowImg: '',
flowGroup: undefined,
flowRemark: undefined
},
rules: {
flowName: [
{
required: true,
message: '请输入审批名称',
trigger: 'blur'
}
],
flowGroup: [
{
required: true,
message: '请选择选择分组',
trigger: 'change'
}
]
},
// iconList,
flowGroupOptions: [
{
label: '假勤管理',
value: 1
},
{
label: '人事管理',
value: 2
},
{
label: '财务管理',
value: 3
},
{
label: '业务管理',
value: 4
},
{
label: '行政管理',
value: 5
},
{
label: '法务管理',
value: 6
},
{
label: '其他',
value: 7
}
]
}
},
computed: {
// activeIconSrc() {
// const icon = this.iconList.find((t) => t.id === this.activeIcon);
// return icon ? icon.src : "";
// },
},
created() {
if (typeof this.conf === 'object' && this.conf !== null) {
Object.assign(this.formData, this.conf)
}
},
methods: {
// 给父级页面提供得获取本页数据得方法
getData() {
return new Promise((resolve, reject) => {
this.$refs['elForm'].validate((valid) => {
if (!valid) {
reject({ target: this.tabName })
return
}
// this.formData.flowImg = this.activeIcon
resolve({ formData: this.formData, target: this.tabName }) // TODO 提交表单
})
})
}
}
}
</script>
<style lang="scss" scoped>
.icon-item {
width: 40px;
height: 40px;
margin: 6px;
position: relative;
cursor: pointer;
opacity: 0.5;
&.active {
opacity: 1;
}
&:hover {
opacity: 1;
}
}
.setting-container {
width: 600px;
margin: auto;
background: #fff;
padding: 16px;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<v-form-designer ref="designerRef" :designer-config="designerConfig"></v-form-designer>
</template>
<script setup>
import { ref } from 'vue'
import 'vform3-builds/dist/designer.style.css' //引入VForm3样式
const designerRef = ref(null)
function setData(json) {
console.log('setFormJson', json)
designerRef.value.setFormJson(json)
}
function getFieldWidgets() {
const fieldList = designerRef.value.getFieldWidgets()
console.log('getFieldWidgets', fieldList)
return fieldList
}
function getData() {
return new Promise((resolve, reject) => {
const jsonData = designerRef.value.getFormJson()
console.log('jsonData', jsonData)
resolve({ formData: jsonData })
})
}
const props = defineProps({
conf: {
type: Object,
default: () => {}
}
})
const designerConfig = {
languageMenu: false,
externalLink: false,
formTemplates: false
}
onMounted(() => {
setData(props.conf)
})
defineExpose({
setData,
getData,
getFieldWidgets
})
</script>
<style lang="scss">
// body {
// margin: 0; /* 如果页面出现垂直滚动条则加入此行CSS以消除之 */
// }
</style>

View File

@@ -0,0 +1,292 @@
<template>
<div class="diagram">
<diagram-toolbar
v-if="lf"
class="diagram-toolbar"
:lf="lf"
:active-edges="activeEdges"
@saveGraph="$_saveGraph"
@importData="importData"
/>
<div class="diagram-main">
<diagram-sidebar class="diagram-sidebar" @dragInNode="$_dragInNode" />
<div ref="container" class="diagram-container">
<div class="diagram-wrapper">
<div ref="diagram" class="lf-diagram"></div>
</div>
</div>
</div>
<!-- 右侧属性面板 -->
<PropertyPanel ref="panelRef" @setProperties="$setProperties" />
</div>
</template>
<script>
import LogicFlow from '@logicflow/core'
import { SelectionSelect, Menu, BpmnElement } from '@logicflow/extension'
import '@logicflow/core/dist/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import DiagramToolbar from './DiagramToolbar.vue'
import DiagramSidebar from './DiagramSidebar.vue'
import PropertyPanel from './PropertyPanel.vue'
import { registerCustomElement } from './node'
// import { Control } from "@logicflow/extension";
export default {
name: 'Diagram',
components: {
DiagramToolbar,
DiagramSidebar,
PropertyPanel
},
props: {
fieldList: {
type: Array,
default: () => {
return []
}
},
conf: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
sidebarWidth: 200,
diagramWidth: 0,
diagramHeight: 0,
lf: '',
filename: '',
activeEdges: []
}
},
mounted() {
// const data = ''
this.filename = 'export.json'
// const d = window.sessionStorage.getItem(this.filename)
// if (d) {
// data = JSON.parse(d)
// }
this.initLogicFlow(this.conf)
},
methods: {
initLogicFlow(data) {
// 引入框选插件
LogicFlow.use(SelectionSelect)
LogicFlow.use(Menu)
LogicFlow.use(BpmnElement)
const lf = new LogicFlow({
container: this.$refs.diagram,
overlapMode: 1,
autoWrap: true,
metaKeyMultipleSelected: true,
keyboard: {
enabled: true
},
grid: {
size: 10,
type: 'dot'
}
})
lf.setTheme({
baseEdge: { strokeWidth: 1 },
baseNode: { strokeWidth: 1 },
nodeText: { overflowMode: 'autoWrap', lineHeight: 1.5 },
edgeText: { overflowMode: 'autoWrap', lineHeight: 1.5 }
})
// 注册自定义元素
registerCustomElement(lf)
lf.setDefaultEdgeType('pro-polyline')
lf.render(data)
this.lf = lf
this.lf.on('node:click', (e) => {
console.log('点击节点', e.data)
this.$refs.panelRef.open(e.data, this.fieldList)
})
// lf.renderRawData( )
},
$_dragInNode(type, text = '') {
this.lf.dnd.startDrag({
type,
text
})
},
// 获取可以进行设置的属性
$_getProperty() {
// this.lf.getProperties(node.id)
},
$setProperties(node, item) {
this.lf.setProperties(node.id, item)
},
$_setZIndex(node, type) {
this.lf.setElementZIndex(node.id, type)
},
importData(text) {
this.lf.renderRawData(text)
},
$_saveGraph() {
const data = this.lf.getGraphData()
this.download(this.filename, JSON.stringify(data))
},
download(filename, text) {
window.sessionStorage.setItem(filename, text)
const element = document.createElement('a')
element.setAttribute(
'href',
'data:text/plain;charset=utf-8,' + encodeURIComponent(text)
)
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
},
getData() {
/**
* 校验目标
* 1. 必须存在开始节点和结束节点
* 2. 连线方向正确
* 3. 多余的节点(不重要)
* 4. 所有分支必须结束节点
* 5. 检查审批节点设置情况
* 6. 一个节点可以有多个子网关,子网关只能通过一个,不能有多个普通子节点
*
*/
return new Promise((resolve, reject) => {
const data = this.lf.getGraphData()
console.log('data', data)
const nodes = data.nodes
const edges = data.edges
let haveMoreChildNode = false
const sourceNodeIdSum = {} //节点id->[子节点id]
edges.forEach((edge) => {
const targetNode = nodes.find((item) => item.id == edge.targetNodeId)
if (sourceNodeIdSum[edge.sourceNodeId]) {
sourceNodeIdSum[edge.sourceNodeId].push(targetNode)
for (const n of sourceNodeIdSum[edge.sourceNodeId]) {
console.log('n', n)
if (n.type != 'bpmn:exclusiveGateway') {
haveMoreChildNode = true
break
}
}
} else {
sourceNodeIdSum[edge.sourceNodeId] = [targetNode]
}
})
console.log('sourceNodeIdSum', sourceNodeIdSum)
if (haveMoreChildNode) {
// 如果都是网关就可以,等优化
return reject({
msg: '流程设计-一个节点只能有一个子节点,可以有多个网关'
})
}
// if (data.nodes.length != data.edges.length + 1) {
// return reject({
// msg: "流程设计-节点之间必须连线,可以清理多余的节点",//不是很重要
// });
// }
// 检查开始节点和结束节点是否存在
const findStartNode = nodes.find((item) => item.type == 'bpmn:startEvent')
const findEndNode = nodes.find((item) => item.type == 'bpmn:endEvent')
if (!findStartNode || !findEndNode) {
return reject({
msg: '流程设计-流程必须有开始节点和结束节点'
})
}
// 检查连线方向是否正确;
resolve({ formData: data })
})
}
}
}
</script>
<style lang="scss">
.diagram {
width: 100%;
height: 100%;
position: relative;
}
.diagram-toolbar {
position: absolute;
top: 10px;
right: 20px;
height: 40px;
padding: 0 10px;
/* width: 310px; */
display: flex;
align-items: center;
/* border-bottom: 1px solid #e5e5e5; */
z-index: 10;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-main {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.diagram-sidebar {
position: absolute;
left: 20px;
z-index: 10;
top: 50px;
width: 60px;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-container {
height: 100%;
.diagram-wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
.lf-diagram {
// box-shadow: 0px 0px 4px #838284;
width: 100%;
height: 100%;
}
}
}
/* 由于背景图和gird不对齐需要css处理一下 */
.diagram-container :v-deep .lf-background {
left: -9px;
}
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
background: white;
border-left: 1px solid #e8e8e8;
}
::-webkit-scrollbar-thumb {
border-width: 1px;
border-style: solid;
border-color: #fff;
border-radius: 6px;
background: #c9c9c9;
}
::-webkit-scrollbar-thumb:hover {
background: #b5b5b5;
}
</style>

View File

@@ -0,0 +1,135 @@
<template>
<div class="diagram-sidebar">
<div
class="image-node"
v-for="(item, index) of list"
:key="index"
@mousedown.stop.prevent="dragInNode(item.type)"
>
<img :src="item.imgUrl" alt="" srcset="" />
<div>
{{ item.name }}
</div>
</div>
<div
class="image-node"
@mousedown.stop.prevent="dragInNode('bpmn:startEvent','开始')"
>
<div class="pattern-start"></div>
<div>开始</div>
</div>
<div
class="image-node"
@mousedown.stop.prevent="dragInNode('bpmn:userTask','审批')"
>
<div class="pattern-user"></div>
<div>审批</div>
</div>
<div
class="image-node"
@mousedown.stop.prevent="dragInNode('bpmn:serviceTask','系统任务')"
>
<div class="pattern-user"></div>
<div>系统</div>
</div>
<div
class="image-node"
@mousedown.stop.prevent="dragInNode('bpmn:exclusiveGateway','网关')"
>
<div class="pattern-condition"></div>
<div>网关</div>
</div>
<div
class="image-node"
@mousedown.stop.prevent="dragInNode('bpmn:endEvent','结束')"
>
<div class="pattern-end"></div>
<div>结束</div>
</div>
</div>
</template>
<script>
// import IconCircle from './icon/Circle.vue'
import { List } from "./node";
console.log("List", List);
export default {
name: "DiagramSidebar",
data() {
return {
list: List.map((item) => {
return {
type: item.type,
...item.info,
};
}),
};
},
methods: {
dragInNode(type,text) {
console.log("dragInNode", type);
this.$emit("dragInNode", type,text);
},
},
// components: {
// // IconCircle,
// }
};
</script>
<style scoped>
.diagram-sidebar {
user-select: none;
text-align: center;
overflow: auto;
}
.image-node {
/* display: inline-block; */
/* width: 50%; */
margin: 20px 0;
cursor: pointer;
background-size: contain;
background-repeat: no-repeat;
user-select: none;
}
.image-node img {
max-width: 26px;
max-height: 26px;
user-select: none;
}
.image-node div {
font-size: 12px;
user-select: none;
}
.pattern-start,
.pattern-end,
.pattern-user,
.pattern-condition {
margin: auto;
width: 36px;
height: 36px;
cursor: grab;
opacity: 0.99;
}
.pattern-start {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==)
center center no-repeat;
}
.pattern-end {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC)
center center no-repeat;
}
.pattern-user {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==)
center center no-repeat;
}
.pattern-condition {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=)
center center no-repeat;
}
</style>

View File

@@ -0,0 +1,181 @@
<template>
<div>
<div class="toolbar-item" :class="{ 'selection-active': selectionOpened }" @click="$_selectionSelect()">
<area-select size="18" />
</div>
<div class="toolbar-item" @click="$_zoomIn()">
<zoom-in size="18" />
</div>
<div class="toolbar-item" @click="$_zoomOut()">
<zoom-out size="18" />
</div>
<div class="toolbar-item" :class="{ disabled: !undoAble }" @click="$_undo()">
<step-back size="18" />
</div>
<div class="toolbar-item" :class="{ disabled: !redoAble }" @click="$_redo()">
<step-foward size="18" />
</div>
<div class="toolbar-item" @click="$import">导入</div>
<div class="toolbar-item" @click="$_saveGraph">导出</div>
<div>
<el-select v-model="linetype" @change="$_changeLineType">
<el-option v-for="item in lineOptions" :key="item.value" :value="item.value" :label="item.label"></el-option>
</el-select>
</div>
</div>
</template>
<script>
// import { Sketch } from 'vue-color'
// import ColorFill from './icon/ColorFill.vue'
// import ColorText from './icon/ColorText.vue'
// import IconFont from './icon/Font.vue'
// import IconBlod from './icon/Blod.vue'
// import IconLine from './icon/Line.vue'
import ZoomIn from "./icon/ZoomIn.vue";
import ZoomOut from "./icon/ZoomOut.vue";
import StepBack from "./icon/StepBack.vue";
import StepFoward from "./icon/StepFoward.vue";
import AreaSelect from "./icon/AreaSelect.vue";
let fileHandle;
async function getFile() {
[fileHandle] = await window.showOpenFilePicker();
console.log("fileHandle", fileHandle);
}
async function getText() {
const file = await fileHandle.getFile();
const text = await file.text();
console.log(text);
return text;
}
async function writeFile() {
const writable = await fileHandle.createWritable();
await writable.write("测试一下");
await writable.close();
}
export default {
props: {
lf: Object,
activeEdges: Array,
fillColor: {
type: String,
default: "",
},
},
data() {
return {
selectionOpened: false,
undoAble: false,
redoAble: false,
colors: "#345678",
linetype: "pro-polyline",
lineOptions: [
{
value: "pro-polyline",
label: "折线",
},
{
value: "pro-line",
label: "直线",
},
{
value: "pro-bezier",
label: "曲线",
},
],
};
},
mounted() {
this.$props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
this.$data.redoAble = redoAble;
this.$data.undoAble = undoAble;
});
},
methods: {
async $import() {
try {
await getFile();
let text = await getText();
if(JSON.parse(text)){
this.$emit("importData",JSON.parse(text));
}
} catch (error) {
this.$message.error("文件读取错误");
}
},
$_changeFillColor(val) {
this.$emit("changeNodeFillColor", val.hex);
},
$_saveGraph() {
this.$emit("saveGraph");
},
$_zoomIn() {
this.$props.lf.zoom(true);
},
$_zoomOut() {
this.$props.lf.zoom(false);
},
$_undo() {
if (this.$data.undoAble) {
this.$props.lf.undo();
}
},
$_redo() {
if (this.$data.redoAble) {
this.$props.lf.redo();
}
},
$_selectionSelect() {
this.selectionOpened = !this.selectionOpened;
if (this.selectionOpened) {
this.lf.extension.selectionSelect.openSelectionSelect();
} else {
this.lf.extension.selectionSelect.closeSelectionSelect();
}
},
$_changeLineType(value) {
const { lf, activeEdges } = this.$props;
const { graphModel } = lf;
lf.setDefaultEdgeType(value);
if (activeEdges && activeEdges.length > 0) {
activeEdges.forEach((edge) => {
graphModel.changeEdgeType(edge.id, value);
});
}
},
},
components: {
// ColorFill,
// ColorText,
// IconFont,
// IconBlod,
// IconLine,
ZoomIn,
ZoomOut,
StepBack,
StepFoward,
AreaSelect,
// SketchPicker: Sketch
},
};
</script>
<style scoped>
.toolbar-item {
/* width: 18px;
height: 18px; */
float: left;
margin: 12px 6px;
padding: 5px;
cursor: pointer;
}
.selection-active {
background: rgba(0 ,0,0,0.2);
}
</style>

View File

@@ -0,0 +1,115 @@
<template>
<el-drawer
v-model="drawerVisible"
size="500px"
:title="node?.text?.value"
@close="close"
>
<div class="setting-block">
<!-- 开始节点 -->
{{ node }}
<div v-if="node.type == 'bpmn:startEvent'">开始节点</div>
<div v-if="node.type == 'bpmn:userTask'">
审批节点 设置审批人具体人员角色部门负责人岗位
</div>
<div v-if="node.type == 'bpmn:serviceTask'">系统任务</div>
<div v-if="node.type == 'bpmn:exclusiveGateway'">
<div>网关</div>
<div>从form取值判断</div>
</div>
<div v-if="node.type == 'bpmn:endEvent'">结束</div>
<!-- 网关和结束节点不需要表单权限设置 -->
<el-table
v-if="
['bpmn:startEvent', 'bpmn:userTask', 'bpmn:serviceTask'].includes(
node.type
)
"
fit
size="small"
:data="fieldList"
style="width: 100%"
>
<el-table-column prop="label" label="表单"></el-table-column>
<el-table-column label="权限">
<template #default="{ row }">
<el-radio-group v-model="row.auth">
<el-radio :label="1">读写</el-radio>
<el-radio :label="2">可读</el-radio>
<el-radio :label="3">隐藏</el-radio>
</el-radio-group>
</template>
</el-table-column>
</el-table>
<!-- {{ fieldList }} -->
<!-- 用户审批节点 -->
<!-- 系统任务节点 -->
</div>
</el-drawer>
</template>
<script>
export default {
name: "PropertyPanel",
props: {},
data() {
return {
drawerVisible: false,
node: {},
/**
* 表单列表
* [{
* id: 1,
* label: '表单1',
* auth: 1,
* }]
*/
fieldList: [],
};
},
methods: {
open(node, fieldList) {
this.node = node;
this.fieldList = fieldList.map((item) => {
let auth = 1;
let formId = item?.field?.id;
if (node?.properties?.fieldAuth?.[formId]) {
auth = node.properties.fieldAuth[formId];
}
return {
id: formId,
label: item?.field?.options?.label,
auth: auth,
};
});
this.drawerVisible = true;
},
close() {
var fieldAuth = {};
this.fieldList.forEach((item) => {
fieldAuth[item.id] = item.auth;
});
this.setProperties("fieldAuth", {
...fieldAuth,
});
},
setProperties(key, val) {
this.$emit("setProperties", this.node, {
[key]: val,
});
},
},
components: {},
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,12 @@
// 元素属性右侧面板默认属性
export const defatuleStyle = {
backgroundColor: '', // 填充色
gradientColor: '', // 渐变色
borderType: 0, // 边框类型
borderColor: '', // 填充颜色
borderWidth: 1, // 边框宽度
borderStyle: '', // 边框类型
fontSize: 12, // 文本大小
fontColor: '', // 文本颜色
fontWeight: '' // 文本加粗
}

View File

@@ -0,0 +1,69 @@
export const shortStyles = [
{
backgroundColor: 'rgb(255, 255, 255)',
borderWidth: '1px',
borderColor: 'rgb(42, 42, 42)'
},
{
backgroundColor: 'rgb(245, 245, 245)',
borderWidth: '1px',
borderColor: 'rgb(102, 102, 102)'
},
{
backgroundColor: 'rgb(218, 232, 252)',
borderWidth: '1px',
borderColor: 'rgb(108, 142, 191)'
},
{
backgroundColor: 'rgb(213, 232, 212)',
borderWidth: '1px',
borderColor: 'rgb(130, 179, 102)'
},
{
backgroundColor: 'rgb(255, 230, 204)',
borderWidth: '1px',
borderColor: 'rgb(215, 155, 0)'
},
{
backgroundColor: 'rgb(255, 242, 204)',
borderWidth: '1px',
borderColor: 'rgb(214, 182, 86)'
},
{
backgroundColor: 'rgb(248, 206, 204)',
borderWidth: '1px',
borderColor: 'rgb(184, 84, 80)'
},
{
backgroundColor: 'rgb(220, 210, 230)',
borderWidth: '1px',
borderColor: 'rgb(150, 115, 166)'
}
]
export const borderStyles = [
{
value: 'solid'
},
{
value: 'dashed'
},
{
value: 'dotted'
}
]
export const fontFamilies = [
{
value: 'Arial'
},
{
value: 'Verdana'
},
{
value: 'Georgia'
},
{
value: 'Times New Roman'
}
]

View File

@@ -0,0 +1,38 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<ellipse
cx="15.75"
cy="4.73"
rx="3.375"
ry="3.375"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></ellipse>
<path
d="M 15.75 8.1 L 15.75 19.35 M 15.75 10.35 L 9 10.35 M 15.75 10.35 L 22.5 10.35 M 15.75 19.35 L 9 28.35 M 15.75 19.35 L 22.5 28.35"
fill="none"
stroke="white"
stroke-width="9.3"
stroke-miterlimit="10"
pointer-events="stroke"
visibility="hidden"
></path>
<path
d="M 15.75 8.1 L 15.75 19.35 M 15.75 10.35 L 9 10.35 M 15.75 10.35 L 22.5 10.35 M 15.75 19.35 L 9 28.35 M 15.75 19.35 L 22.5 28.35"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,17 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M933.647059 0h-210.82353v90.352941h180.705883a30.117647 30.117647 0 0 1 30.117647 30.117647v180.705883h90.352941V90.352941a90.352941 90.352941 0 0 0-90.352941-90.352941zM361.411765 0h301.17647v90.352941H361.411765zM933.647059 361.411765h90.352941v301.17647h-90.352941zM361.411765 933.647059h301.17647v90.352941H361.411765zM0 361.411765h90.352941v301.17647H0zM90.352941 903.529412v-180.705883H0v210.82353a90.352941 90.352941 0 0 0 90.352941 90.352941h210.82353v-90.352941H120.470588a30.117647 30.117647 0 0 1-30.117647-30.117647zM933.647059 903.529412a30.117647 30.117647 0 0 1-30.117647 30.117647h-180.705883v90.352941h210.82353a90.352941 90.352941 0 0 0 90.352941-90.352941v-210.82353h-90.352941zM0 90.352941v210.82353h90.352941V120.470588a30.117647 30.117647 0 0 1 30.117647-30.117647h180.705883V0H90.352941a90.352941 90.352941 0 0 0-90.352941 90.352941z" p-id="1890">
</path>
</svg>
</template>
<script>
export default {
name:"AreaSelect",
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M426.857143 869.142857q42.285714 18.285714 80 18.285714 214.857143 0 214.857143-191.428571 0-65.142857-23.428572-102.857143-15.428571-25.142857-35.142857-42.285714t-38.571428-26.571429-46-14.285714-48-6-54-1.142857q-41.714286 0-57.714286 5.714286 0 30.285714-0.285714 90.857142t-0.285715 90.285715q0 4.571429-0.571428 38.571428t-0.285715 55.142857 2.571429 47.714286 6.857143 38z m-8-426.285714q24 4 62.285714 4 46.857143 0 81.714286-7.428572t62.857143-25.428571 42.571428-51.142857 14.571429-81.142857q0-40-16.571429-70t-45.142857-46.857143T559.428571 140t-70.857142-8q-28.571429 0-74.285715 7.428571 0 28.571429 2.285715 86.285715t2.285714 86.857143q0 15.428571-0.285714 45.714285t-0.285715 45.142857q0 26.285714 0.571429 39.428572z m-309.142857 508l1.142857-53.714286q8.571429-2.285714 48.571428-9.142857t60.571429-15.428571q4-6.857143 7.142857-15.428572t4.857143-19.142857 3.142857-18.571429 1.714286-21.428571 0.285714-19.428571V741.142857q0-561.142857-12.571428-585.714286-2.285714-4.571429-12.571429-8.285714t-25.428571-6.285714-28.285715-4-27.714285-2.571429-17.428572-1.714285l-2.285714-47.428572q56-1.142857 194.285714-6.571428t213.142857-5.428572q13.142857 0 39.142857 0.285714t38.571429 0.285715q40 0 78 7.428571t73.428571 24 61.714286 40.571429 42.285714 59.714285 16 78.571429q0 29.714286-9.428571 54.571429t-22.285714 41.142857T798.857143 412.571429t-41.714286 25.714285-48 22.857143q88 20 146.571429 76.571429t58.571428 141.714285q0 57.142857-20 102.571429t-53.428571 74.571429-78.857143 48.857142T668.571429 933.142857t-100.571429 8q-25.142857 0-75.428571-1.714286t-75.428572-1.714285q-60.571429 0-175.428571 6.285714t-132 6.857143z" p-id="8191">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,31 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<ellipse
cx="15.98"
cy="14.96"
rx="13.600000000000001"
ry="13.600000000000001"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></ellipse>
</g>
</svg>
</template>
<script>
export default {
}
</script>
<style scoped>
.svg-node {
left: 1px;
top: 1px;
width: 32px;
height: 30px;
display: block;
position: relative;
overflow: hidden;
}
</style>

View File

@@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path fill="currentColor" d="M810.666667 618.666667s-85.333333 93.866667-85.333334 149.333333c0 46.933333 38.4 85.333333 85.333334 85.333333s85.333333-38.4 85.333333-85.333333c0-55.466667-85.333333-149.333333-85.333333-149.333333M221.866667 554.666667L426.666667 349.866667l204.8 204.8m76.8-46.933334L324.266667 128 264.533333 187.733333l102.4 102.4-221.866666 217.6c-25.6 25.6-25.6 64 0 89.6l234.666666 234.666667c25.6 25.6 64 25.6 89.6 0l234.666667-234.666667c25.6-21.333333 29.866667-64 4.266667-89.6z" p-id="4284">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,15 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M512 725.333333a128 128 0 1 1 0 256 128 128 0 0 1 0-256zM469.333333 85.333333L234.666667 682.666667h96l47.786666-128h266.666667l47.786667 128h96L554.666667 85.333333h-85.333334z m-58.88 384L512 199.253333 613.546667 469.333333H410.453333z" p-id="4479"></path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 加号 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,9 9,9 9,0 18,0 18,9 27,9 27,18 18,18 18,27 9,27 9,18 0,18"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,27 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 5.78 6.46 C 5.78 3.64 10.35 1.36 15.98 1.36 C 18.69 1.36 21.28 1.9 23.19 2.85 C 25.11 3.81 26.18 5.11 26.18 6.46 L 26.18 23.46 C 26.18 26.28 21.61 28.56 15.98 28.56 C 10.35 28.56 5.78 26.28 5.78 23.46 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
<path
d="M 26.18 6.46 C 26.18 9.28 21.61 11.56 15.98 11.56 C 10.35 11.56 5.78 9.28 5.78 6.46"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 15.98 1.36 L 29.58 14.96 L 15.98 28.56 L 2.38 14.96 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,37 @@
<template>
<!-- 除号 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<circle
cx="13.5"
cy="4.5"
r="3.375"
fill="#fff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
/>
<polygon
points="0,10 27,10 27,17 0,17"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
<circle
cx="13.5"
cy="22.5"
r="3.375"
fill="#fff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
/>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="10,0 20,0 20,18 30,18 15,28 0,18 10,18"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,21 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<ellipse
cx="15.84"
cy="14.88"
rx="14.399999999999999"
ry="9.6"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></ellipse>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M450.857143 319.428571l-97.142857 257.142858q18.857143 0 78 1.142857t91.714285 1.142857q10.857143 0 32.571429-1.142857-49.714286-144.571429-105.142857-258.285715zM36.571429 950.857143l1.142857-45.142857q13.142857-4 32-7.142857t32.571428-6 28.285715-8.285715 25.428571-16.571428 17.714286-28.857143l135.428571-352 160-413.714286h73.142857q4.571429 8 6.285715 12l117.142857 274.285714q18.857143 44.571429 60.571428 147.142858t65.142857 156.857142q8.571429 19.428571 33.142858 82.571429t41.142857 96.285714q11.428571 25.714286 20 32.571429 10.857143 8.571429 50.285714 16.857143t48 11.714285q3.428571 21.714286 3.428571 32.571429 0 2.285714-0.285714 7.428571t-0.285714 7.428572q-36 0-108.571429-4.571429t-109.142857-4.571428q-43.428571 0-122.857143 4t-101.714285 4.571428q0-24.571429 2.285714-44.571428l74.857143-16q0.571429 0 7.142857-1.428572t8.857143-2 8.285714-2.571428 8.571429-3.714286 6.285714-4.571429 5.142857-6.285714 1.428571-8q0-9.142857-17.714285-55.142857t-41.142857-101.428571-24-57.142858l-257.142858-1.142857q-14.857143 33.142857-43.714285 111.714286T254.857143 850.857143q0 12.571429 8 21.428571t24.857143 14 27.714285 7.714286 32.571429 4.857143 23.428571 2.285714q0.571429 10.857143 0.571429 33.142857 0 5.142857-1.142857 15.428572-33.142857 0-99.714286-5.714286T171.428571 938.285714q-4.571429 0-15.142857 2.285715t-12.285714 2.285714q-45.714286 8-107.428571 8z" p-id="8338">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 八边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="19.74,0 28,8.26 28,19.74 19.74,28 8.26,28 0,19.74 0,8.26 8.26,0"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 六边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="6.16,0 21.84,0 28,14 21.84,28 6.16,28 0,14"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,13.6 9,2.2 9,11.2 18,11.2 18,2.2 27,13.6 18,27.2 18,18.2 9,18.2 9,27.2"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,15 10,0 10,10 30,10 30,20 10,20 10,30"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M127.389 851.634l724.21-724.21 45.198 45.196-724.211 724.212z" p-id="11226">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 减号 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,9 27,9 27,18 0,18"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 1.44 22.08 L 6.24 7.68 L 30.24 7.68 L 25.44 22.08 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 五边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,10.6 14,0 28,10.6 22.4,28 5.6,28"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,31 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="2.38"
y="1.36"
width="27.2"
height="27.2"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></rect>
</g>
</svg>
</template>
<script>
export default {
}
</script>
<style scoped>
.svg-node {
left: 1px;
top: 1px;
width: 32px;
height: 30px;
display: block;
position: relative;
overflow: hidden;
}
</style>

View File

@@ -0,0 +1,23 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="2.38"
y="1.36"
width="27.2"
height="27.2"
rx="3.16"
ry="3.16"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></rect>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,10 20,10 20,0 30,15 20,30 20,20 0,20"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 七边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="14,0 25.06,5.6 28,18.06 20.02,28 7.7,28 0,18.06 2.94,5.6"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M967.111111 967.111111h-113.777778v-113.777778c0-221.866667-176.355556-398.222222-398.222222-398.222222H113.777778V341.333333h341.333333c284.444444 0 512 227.555556 512 512v113.777778z" fill="#0D1733" p-id="1011">
</path>
<path d="M409.6 762.311111L51.2 398.222222 409.6 39.822222l85.333333 79.644445-284.444444 278.755555 284.444444 284.444445z" fill="#0D1733" p-id="1012">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M170.666667 967.111111H56.888889v-113.777778c0-284.444444 227.555556-512 512-512h341.333333v113.777778h-341.333333c-221.866667 0-398.222222 176.355556-398.222222 398.222222v113.777778z" fill="#0D1733" p-id="1167">
</path>
<path d="M614.4 762.311111L529.066667 682.666667l284.444444-284.444445-284.444444-278.755555L614.4 39.822222 972.8 398.222222z" fill="#0D1733" p-id="1168">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,158 @@
<template>
<svg class="svg-node">
<g>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 1.26 9.24 L 1.26 3.78 L 30.66 3.78 L 30.66 9.24"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
<path
d="M 1.26 9.24 L 1.26 25.62 L 30.66 25.62 L 30.66 9.24"
fill="none"
stroke="white"
stroke-width="9.3"
stroke-miterlimit="10"
pointer-events="stroke"
visibility="hidden"
></path>
<path
d="M 1.26 9.24 L 1.26 25.62 L 30.66 25.62 L 30.66 9.24"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="none"
></path>
<path
d="M 1.26 9.24 L 30.66 9.24"
fill="none"
stroke="white"
stroke-width="9.3"
stroke-miterlimit="10"
pointer-events="stroke"
visibility="hidden"
></path>
<path
d="M 1.26 9.24 L 30.66 9.24"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="none"
></path>
</g>
<g
fill="#000000"
font-family="Helvetica"
text-anchor="middle"
font-size="2.52px"
>
<text x="15.96" y="7.56">List</text>
</g>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="1.26"
y="9.24"
width="29.4"
height="5.46"
fill="none"
stroke="white"
pointer-events="stroke"
visibility="hidden"
stroke-width="9"
></rect>
<rect
x="1.26"
y="9.24"
width="29.4"
height="5.46"
fill="none"
stroke="none"
pointer-events="all"
></rect>
</g>
<g style="">
<clipPath id="mx-clip-1-9-31-9-0">
<rect x="1" y="9" width="31" height="9"></rect>
</clipPath>
<g
fill="#000000"
font-family="Helvetica"
clip-path="url(https://app.diagrams.net/#mx-clip-1-9-31-9-0)"
font-size="2.52px"
>
<text x="2.52" y="13.02">Item 1</text>
</g>
</g>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="1.26"
y="14.7"
width="29.4"
height="5.46"
fill="none"
stroke="white"
pointer-events="stroke"
visibility="hidden"
stroke-width="9"
></rect>
<rect
x="1.26"
y="14.7"
width="29.4"
height="5.46"
fill="none"
stroke="none"
pointer-events="all"
></rect>
</g>
<g style="">
<clipPath id="mx-clip-1-14-31-9-0">
<rect x="1" y="14" width="31" height="9"></rect>
</clipPath>
<g fill="#000000" font-family="Helvetica" font-size="2.52px">
<text x="2.52" y="18.48">Item 2</text>
</g>
</g>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="1.26"
y="20.16"
width="29.4"
height="5.46"
fill="none"
stroke="white"
pointer-events="stroke"
visibility="hidden"
stroke-width="9"
></rect>
<rect
x="1.26"
y="20.16"
width="29.4"
height="5.46"
fill="none"
stroke="none"
pointer-events="all"
></rect>
</g>
<g style="">
<clipPath id="mx-clip-1-20-31-9-0">
<rect x="1" y="20" width="31" height="9"></rect>
</clipPath>
<g fill="#000000" font-family="Helvetica" font-size="2.52px">
<text x="2.52" y="23.94">Item 3</text>
</g>
</g>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,46 @@
<template>
<svg>
<g>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<rect
x="0.98"
y="7.84"
width="29.4"
height="12.74"
fill="none"
stroke="white"
pointer-events="stroke"
visibility="hidden"
stroke-width="9"
></rect>
<rect
x="0.98"
y="7.84"
width="29.4"
height="12.74"
fill="none"
stroke="none"
pointer-events="all"
></rect>
</g>
<g style="">
<clipPath id="mx-clip-2-9-28-15-0">
<rect x="2" y="9" width="28" height="15"></rect>
</clipPath>
<g
fill="#000000"
font-family="Helvetica"
clip-path="url(https://app.diagrams.net/#mx-clip-2-9-28-15-0)"
font-size="5.88px"
>
<text x="3.92" y="16.66">Text Node</text>
</g>
</g>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 乘号 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,4.5 4.5,0 13.5,9 22.5,0 27,4.5 18,13.5 27,22.5 22.5,27 13.5,18 4.5,27 0,22.5 9,13.5"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<!-- 五边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="5.32,0 22.68,0 28,28 0,28"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 5.78 1.36 L 26.18 14.96 L 5.78 28.56 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points = "0,10 15,0 30,10 20,10 20,28 10,28 10,10"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,9 13.6,0 27.2,9 18.2,9 18.2,18 27.2,18 13.6,27 0,18 9,18 9,9"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M943.8 892.5l-201.4-201c24.2-29 43.9-61.3 58.7-96.3 20-47.3 30.1-97.6 30.1-149.4s-10.1-102-30.1-149.4c-19.3-45.7-47-86.7-82.1-122-35.2-35.2-76.2-62.9-121.9-82.2-47.3-20-97.5-30.2-149.3-30.2-51.8 0-102 10.2-149.3 30.2-45.7 19.3-86.7 47-121.9 82.2s-62.8 76.3-82.1 122c-20 47.3-30.1 97.6-30.1 149.4s10.1 102 30.1 149.4c19.3 45.7 47 86.7 82.1 122 35.2 35.2 76.2 62.9 121.9 82.2 47.3 20 97.5 30.2 149.3 30.2 51.7 0 102-10.2 149.3-30.2 34.6-14.7 66.6-34.1 95.3-58l201.5 201c6.9 6.9 15.9 10.3 24.9 10.3 9.1 0 18.1-3.5 25-10.4 13.8-13.7 13.8-36.1 0-49.8zM669.7 666.6c-0.4 0.4-0.8 0.7-1.2 1.1-0.3 0.3-0.6 0.6-0.8 0.9-59 58.3-137 90.4-219.9 90.4-83.5 0-162.1-32.6-221.2-91.7-59.1-59.1-91.6-137.8-91.6-221.4s32.5-162.3 91.6-221.4c59.1-59.1 137.6-91.7 221.2-91.7s162.1 32.6 221.2 91.7c59.1 59.1 91.6 137.8 91.6 221.4 0 83.3-32.3 161.6-90.9 220.7z" p-id="813">
</path>
<path d="M573.7 419H473v-98c0-19.5-13-35.3-32.5-35.3S408 301.5 408 321v98H305.3c-19.5 0-35.3 13-35.3 32.5s15.8 32.5 35.3 32.5H408v105.4c0 19.5 13 35.3 32.5 35.3s32.5-15.8 32.5-35.3V484h100.7c19.5 0 35.3-13 35.3-32.5S593.2 419 573.7 419z" p-id="814">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,18 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M946.9 897.7L744 695.2c24.4-29.2 44.2-61.7 59.1-97 20.2-47.7 30.4-98.3 30.4-150.5s-10.2-102.8-30.4-150.5c-19.5-46-47.3-87.4-82.8-122.9s-76.8-63.4-122.8-82.8c-47.7-20.2-98.3-30.4-150.4-30.4S344.4 71.3 296.8 91.5c-46 19.5-87.3 47.4-122.8 82.8-35.5 35.5-63.3 76.8-82.8 122.9-20.2 47.7-30.4 98.3-30.4 150.5S71 550.5 91.2 598.2c19.5 46 47.3 87.4 82.8 122.9s76.8 63.4 122.8 82.8c47.7 20.2 98.3 30.4 150.4 30.4s102.7-10.2 150.4-30.4c34.9-14.8 67.1-34.4 96.1-58.5l203 202.6c6.9 6.9 16 10.4 25.1 10.4 9.1 0 18.2-3.5 25.2-10.5 13.8-13.8 13.8-36.3-0.1-50.2zM447.2 763.2c-84.2 0-163.3-32.8-222.8-92.4C164.8 611.2 132 532 132 447.7c0-84.3 32.8-163.5 92.3-223.1 59.5-59.6 138.7-92.4 222.8-92.4s163.3 32.8 222.8 92.4c59.5 59.6 92.3 138.8 92.3 223.1 0 83.9-32.5 162.8-91.6 222.3-0.4 0.4-0.8 0.8-1.2 1.1-0.3 0.3-0.6 0.6-0.8 0.9-59.3 58.9-137.9 91.2-221.4 91.2z" p-id="967">
</path>
<path d="M574 416H303.7c-19.7 0-35.6 12.8-35.6 32.5S284 481 303.7 481H574c19.7 0 35.6-12.8 35.6-32.5S593.7 416 574 416z" p-id="968">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

View File

@@ -0,0 +1,49 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 下箭头
class DownArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 50
this.height = 80
}
}
class DownArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowWidth = 1/3 * width;
const upY = y - 1/2 * height;
const downY = y + 1/2 * height;
const downY2 = y + 1/5 * height;
const attrs = {
...style,
x,
y,
width,
height,
points: [
[x - 1/2 * ArrowWidth, downY2],
[x - 1/2 * width, downY2],
[x, downY],
[x + 1/2 * width, downY2],
[x + 1/2 * ArrowWidth, downY2],
[x + 1/2 * ArrowWidth, upY],
[x - 1/2 * ArrowWidth, upY],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'down-arrow',
view: DownArrowView,
model: DownArrowModel
}

View File

@@ -0,0 +1,56 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 水平双箭头
class HorizontalArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 40
}
}
class HorizontalArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowHeight = 1/3 * height;
const leftX = x - 1/2 * width;
const leftX2 = x - 1/5 * width;
const rightX = x + 1/2 * width;
const rightX2 = x + 1/5 * width;
const attrs = {
...style,
x,
y,
width,
height,
points: [
// 右箭头
[rightX2, y - 1/2 * ArrowHeight],
[rightX2, y - 1/2 * height],
[rightX, y],
[rightX2, y + 1/2 * height],
[rightX2, y + 1/2 * ArrowHeight],
// 左箭头
[leftX2, y + 1/2 * ArrowHeight],
[leftX2, y + 1/2 * height],
[leftX, y],
[leftX2, y - 1/2 * height],
[leftX2, y - 1/2 * ArrowHeight],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'horizontal-arrow',
view: HorizontalArrowView,
model: HorizontalArrowModel
}

View File

@@ -0,0 +1,48 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 左箭头
class LeftArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 50
}
}
class LeftArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowHeight = 1/3 * height;
const leftX = x - 1/2 * width;
const leftX2 = x - 1/5 * width;
const rightX = x + 1/2 * width;
const attrs = {
...style,
x,
y,
width,
height,
points: [
[leftX2, y - 1/2 * ArrowHeight],
[leftX2, y - 1/2 * height],
[leftX, y],
[leftX2, y + 1/2 * height],
[leftX2, y + 1/2 * ArrowHeight],
[rightX, y + 1/2 * ArrowHeight],
[rightX, y - 1/2 * ArrowHeight],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'left-arrow',
view: LeftArrowView,
model: LeftArrowModel
}

View File

@@ -0,0 +1,50 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 右箭头
class RightArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 50
}
}
class RightArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowHeight = 1/3 * height;
const leftX = x - 1/2 * width;
const rightX = x + 1/2 * width;
const rightX2 = x + 1/5 * width;
const attrs = {
...style,
x,
y,
width,
height,
points: [
[rightX2, y - 1/2 * ArrowHeight],
[rightX2, y - 1/2 * height],
[rightX, y],
[rightX2, y + 1/2 * height],
[rightX2, y + 1/2 * ArrowHeight],
[leftX, y + 1/2 * ArrowHeight],
[leftX, y - 1/2 * ArrowHeight],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'right-arrow',
view: RightArrowView,
model: RightArrowModel
}

View File

@@ -0,0 +1,49 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 上箭头
class UpArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 50
this.height = 80
}
}
class UpArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowWidth = 1/3 * width;
const upY = y - 1/2 * height;
const upY2 = y - 1/5 * height;
const downY = y + 1/2 * height;
const attrs = {
...style,
x,
y,
width,
height,
points: [
[x - 1/2 * ArrowWidth, upY2],
[x - 1/2 * width, upY2],
[x, upY],
[x + 1/2 * width, upY2],
[x + 1/2 * ArrowWidth, upY2],
[x + 1/2 * ArrowWidth, downY],
[x - 1/2 * ArrowWidth, downY],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'up-arrow',
view: UpArrowView,
model: UpArrowModel
}

View File

@@ -0,0 +1,56 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 竖直箭头
class VerticalArrowModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 40
this.height = 80
}
}
class VerticalArrowView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const ArrowWidth = 1/3 * width;
const upY = y - 1/2 * height;
const upY2 = y - 1/5 * height;
const downY = y + 1/2 * height;
const downY2 = y + 1/5 * height;
const attrs = {
...style,
x,
y,
width,
height,
points: [
// 上箭头
[x - 1/2 * ArrowWidth, upY2],
[x - 1/2 * width, upY2],
[x, upY],
[x + 1/2 * width, upY2],
[x + 1/2 * ArrowWidth, upY2],
// 下箭头
[x + 1/2 * ArrowWidth, downY2],
[x + 1/2 * width, downY2],
[x , downY],
[x - 1/2 * width, downY2],
[x - 1/2 * ArrowWidth, downY2],
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
);
}
}
export default {
type: 'vertical-arrow',
view: VerticalArrowView,
model: VerticalArrowModel
}

View File

@@ -0,0 +1,16 @@
import { BaseNode, BaseNodeModel } from '@logicflow/core'
class BaseNewNode extends BaseNode {
}
class BaseNewModel extends BaseNodeModel {
setAttributes () {
this.fill = 'red'
}
}
export default {
type: 'BaseNode',
view: BaseNewNode,
model: BaseNewModel
}

View File

@@ -0,0 +1,33 @@
import { EllipseResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 圆形
class CircleNewModel extends EllipseResize.model {
initNodeData(data) {
super.initNodeData(data)
this.rx = 35
this.ry = 35
}
setToBottom () {
this.zIndex = 0
}
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
export default {
type: 'pro-circle',
view: EllipseResize.view,
model: CircleNewModel
}

View File

@@ -0,0 +1,35 @@
import { DiamondResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 菱形
/**
* model控制初始化的值
*/
class DiamondModel extends DiamondResize.model {
initNodeData(data) {
super.initNodeData(data)
this.rx = 35
this.ry = 35
}
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
setToBottom () {
this.zIndex = 0
}
}
export default {
type: 'pro-diamond',
view: DiamondResize.view,
model: DiamondModel
}

View File

@@ -0,0 +1,19 @@
import CircleNode from './CircleNode'
// 椭圆
class EllipseNewModel extends CircleNode.model {
initNodeData(data) {
super.initNodeData(data)
this.rx = 60
this.ry = 30
}
getNodeStyle() {
const style = super.getNodeStyle()
return {...style}
}
}
export default {
type: 'pro-ellipse',
view: CircleNode.view,
model: EllipseNewModel
}

View File

@@ -0,0 +1,28 @@
import { RectResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 矩形
class RectNewModel extends RectResize.model {
setToBottom () {
this.zIndex = 0
}
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
export default {
type: 'pro-rect',
view: RectResize.view,
model: RectNewModel
}

View File

@@ -0,0 +1,14 @@
import RectNode from './RectNode'
// 带圆角的矩形
class RectRadiusModel extends RectNode.model {
setAttributes () {
super.setAttributes()
this.radius = 20
}
}
export default {
type: 'rect-radius',
view: RectNode.view,
model: RectRadiusModel
}

View File

@@ -0,0 +1,39 @@
import { TextNodeModel, TextNode } from '@logicflow/core'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 文本节点
class TextNewNode extends TextNode {
}
class TextNewModel extends TextNodeModel {
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
style.color = '#000'
if (properties.backgroundColor) {
style.backgroundStyle = {
fill: properties.backgroundColor
}
}
return getTextStyleFunction(style, properties)
}
setAttributes () {
super.setAttributes()
if (!this.text.value) {
this.text.value = 'text'
}
}
}
export default {
type: 'pro-text',
view: TextNewNode,
model: TextNewModel
}

View File

@@ -0,0 +1,27 @@
import { BezierEdge, BezierEdgeModel } from '@logicflow/core'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 贝塞尔曲线
class Model extends BezierEdgeModel {
constructor (data, graphModel) {
super(data, graphModel)
this.strokeWidth = 1
}
getTextStyle () {
const style = super.getTextStyle()
return getTextStyleFunction(style, this.properties)
}
getEdgeStyle () {
const attributes = super.getEdgeStyle()
const properties = this.properties;
const style = getShapeStyleFuction(attributes, properties)
style.stroke = 'rgb(24, 125, 255)'
return { ...style, fill: 'none' }
}
}
export default {
type: 'pro-bezier',
view: BezierEdge,
model: Model
}

View File

@@ -0,0 +1,27 @@
import { LineEdge, LineEdgeModel } from '@logicflow/core'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 直线
class Model extends LineEdgeModel {
constructor (data, graphModel) {
super(data, graphModel)
this.strokeWidth = 1
}
getTextStyle () {
const style = super.getTextStyle()
return getTextStyleFunction(style, this.properties)
}
getEdgeStyle () {
const attributes = super.getEdgeStyle()
const properties = this.properties;
const style = getShapeStyleFuction(attributes, properties)
style.stroke = 'rgb(24, 125, 255)'
return { ...style, fill: 'none' }
}
}
export default {
type: 'pro-line',
view: LineEdge,
model: Model
}

View File

@@ -0,0 +1,37 @@
import { PolylineEdge, PolylineEdgeModel } from '@logicflow/core'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 折线
class Model extends PolylineEdgeModel {
constructor (data, graphModel) {
super(data, graphModel)
this.strokeWidth = 1
}
setAttributes() {
this.isAnimation = true;
}
getEdgeAnimationStyle() {
const style = super.getEdgeAnimationStyle();
style.strokeDasharray = "50 5";
style.animationDuration = "10s";
style.stroke = 'rgb(24, 125, 255)'
return style;
}
getTextStyle () {
const style = super.getTextStyle()
return getTextStyleFunction(style, this.properties)
}
getEdgeStyle () {
const attributes = super.getEdgeStyle()
const properties = this.properties;
const style = getShapeStyleFuction(attributes, properties)
style.stroke = 'rgb(24, 125, 255)'
return { ...style, fill: 'none' }
}
}
export default {
type: 'pro-polyline',
view: PolylineEdge,
model: Model
}

View File

@@ -0,0 +1,61 @@
export const getShapeStyleFuction = (style, properties) => {
if (properties.backgroundColor) {
style.fill = properties.backgroundColor
}
if (properties.gradientColor && style.fill !== properties.gradientColor) {
style.fillGradient = properties.gradientColor
}
if (properties.borderColor) {
style.stroke = properties.borderColor
}
if (properties.borderWidth) {
style.strokeWidth = properties.borderWidth
}
if (properties.borderStyle) {
if (properties.borderStyle === 'solid') {
style.strokeDashArray = '0'
// nodeResize里的bug导致的,array小写了
style.strokeDasharray = '0'
}
if (properties.borderStyle === 'dashed') {
style.strokeDashArray = '3 3'
style.strokeDasharray = '3 3'
}
if (properties.borderStyle === 'dotted') {
style.strokeDashArray = '1 1'
style.strokeDasharray = '1 1'
}
if (properties.borderStyle === 'hidden') {
style.stroke = style.fill
}
}
return style
}
export const getTextStyleFunction = (style = {}, properties) => {
if (properties.fontColor) {
style.color = properties.fontColor
}
if (properties.fontSize) {
style.fontSize = properties.fontSize
}
if (properties.fontFamily) {
style.fontFamily = properties.fontFamily
}
if (properties.lineHeight) {
style.lineHeight = properties.lineHeight
}
if (properties.textAlign) {
style.textAlign = properties.textAlign
}
if (properties.fontWeight) {
style.fontWeight = properties.fontWeight
}
if (properties.textDecoration) {
style.textDecoration = properties.textDecoration
}
if (properties.fontStyle) {
style.fontStyle = properties.fontStyle
}
return style
}

View File

@@ -0,0 +1,44 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 左上角带ICON的节点
class IconNode extends RectNode.view {
getImageHref () {
return;
}
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const href = this.getImageHref()
const iconAttrs = {
x: x - 1/2 * width + 5,
y: y - 1/2 * height + 5, // icon在左上角
width: 25,
height: 18,
href,
// 根据宽高缩放
preserveAspectRatio: 'none meet'
}
const rectAttrs = {
...style,
strokeWidth: 1,
rx: 5,
ry: 5,
x: x- 1/2 * width,
y: y - 1/2 * height,
width,
height,
}
return h('g', {}, [
h('rect', { ...rectAttrs }),
h('image', { ...iconAttrs })
]
);
}
}
export default {
type: 'image-node',
view: IconNode,
model: RectNode.model
}

View File

@@ -0,0 +1,15 @@
import IconNode from './IconNode'
// 左上角ICON为消息的节点
class MessageNode extends IconNode.view {
getImageHref () {
return 'https://dpubstatic.udache.com/static/dpubimg/1TZgBoaq8G/message.png';
}
}
export default {
type: 'icon-message',
view: MessageNode,
model: IconNode.model
}

View File

@@ -0,0 +1,103 @@
// 基础图形
import CircleNode from "./basic/CircleNode";
import RectNode from "./basic/RectNode";
import RectRadiusNode from "./basic/RectRadiusNode";
import EllipseNode from "./basic/EllipseNode";
import TextNode from "./basic/TextNode";
import DiamondNode from "./basic/DiamondNode";
// // path绘制的个性化图形
// import CylindeNode from './path/CylindeNode'
// import TriangleNode from './path/TriangleNode'
// import ParallelogramNode from './path/ParallelogramNode'
// import ActorNode from './path/ActorNode'
// import StarNode from './path/Star'
// import PentagonNode from './path/PentagonNode'
// import HexagonNode from './path/HexagonNode'
// import SeptagonNode from './path/SeptagonNode'
// import HeptagonNode from './path/HeptagonNode'
// import TrapezoidNode from './path/TrapezoidNode'
// import CrossNode from './path/CrossNode'
// import MinusNode from './path/MinusNode'
// import TimesNode from './path/TimesNode'
// import DivideNode from './path/DivideNode'
// // 多边形绘制的箭头
// import LeftArrow from './arrow/LeftArrow'
// import RightArrow from './arrow/RightArrow'
// import HorizontalArrow from './arrow/HorizontalArrowNode'
// import UpArrow from './arrow/UpArrowNode'
// import DownArrow from './arrow/DownArrowNode'
// import VerticalArrow from './arrow/VerticalArrowNode'
// image绘制左上角icon节点
// import IconMessage from './icon/Message'
// 注册边
import Ployline from "./edge/Polyline";
import Line from "./edge/Line";
import Bezier from "./edge/Bezier";
export const List = [
// office_network,
// firewall,
// router,
// coreSwitch,
];
console.log(List);
export const registerCustomElement = (lf) => {
// 注册基础图形
// lf.register(CircleNode);
// lf.register(RectNode);
// lf.register(RectRadiusNode);
// lf.register(EllipseNode);
// lf.register(DiamondNode);
// lf.register(TextNode);
// lf.register(status_error);
List.forEach((item) => {
lf.register({
type: item.type,
view: item.view,
model: item.model,
});
});
// // 注册path绘制的个性化图形
// lf.register(CylindeNode)
// lf.register(TriangleNode)
// lf.register(ParallelogramNode)
// lf.register(ActorNode)
// lf.register(StarNode)
// lf.register(PentagonNode)
// lf.register(HexagonNode)
// lf.register(SeptagonNode)
// lf.register(HeptagonNode)
// lf.register(TrapezoidNode)
// lf.register(CrossNode)
// lf.register(MinusNode)
// lf.register(TimesNode)
// lf.register(DivideNode)
// // 注册多边形绘制的箭头
// lf.register(LeftArrow)
// lf.register(RightArrow)
// lf.register(HorizontalArrow)
// lf.register(UpArrow)
// lf.register(DownArrow)
// lf.register(VerticalArrow)
// // 注册image绘制图片节点
// lf.register(firewall)
// lf.register(ImageUser)
// lf.register(office_network)
// lf.register(status_success)
// lf.register(status_error)
// lf.register(router)
// // 注册image绘制左上角icon节点
// lf.register(IconMessage)
// // 注册边
lf.register(Ployline);
lf.register(Line);
lf.register(Bezier);
};

View File

@@ -0,0 +1,95 @@
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 人物
class ActorModel extends RectResize.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 40;
this.height = 80;
}
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class ActorView extends RectResize.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
// 人物头部圆形
const ellipseAttrs = {
...style,
cx: x,
cy: y - 3/8 * height,
rx: 1/4 * width,
ry: 1/8 * height,
width,
height
}
// 人物肩膀横线
const pathAAttrs = {
...style,
d: `M ${x - 1/2 * width} ${y - 1/8 * height} L ${x + 1/2 * width} ${y - 1/8 * height}`
}
// 人物身体躯干竖线
const pathBAttrs = {
...style,
d: `M ${x} ${y - 1/4 * height} L ${x} ${y + 1/5 * height}`
}
// 人物左腿斜线
const pathCAttrs = {
...style,
d: `M ${x} ${y + 1/5 * height} L ${x - 1/2 * width} ${y + 1/2 * height}`
}
// 人物右腿斜线
const pathDAttrs = {
...style,
d: `M ${x} ${y + 1/5 * height} L ${x + 1/2 * width} ${y + 1/2 * height}`
}
// 人物透明背景板
const bgAttrs = {
x: x - 1/5 * width,
y: y - 1/2 * height,
width: 2/5 * width,
height,
style: 'fill: transparent'
}
return h('g', {}, [
h('ellipse', {
...ellipseAttrs,
}),
h('path', {
...pathAAttrs,
}),
h('path', {
...pathBAttrs
}),
h('path', {
...pathCAttrs
}),
h('path', {
...pathDAttrs
}),
h('rect', {
...bgAttrs
})
]
);
}
}
export default {
type: 'actor',
view: ActorView,
model: ActorModel
}

View File

@@ -0,0 +1,66 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 加号
class CrossModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class CrossView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 1/2 * width, y - 1/6 * height],
[x - 1/6 * width, y - 1/6 * height],
[x - 1/6 * width, y - 1/2 * height],
[x + 1/6 * width, y - 1/2 * height],
[x + 1/6 * width, y - 1/6 * height],
[x + 1/2 * width, y - 1/6 * height],
[x + 1/2 * width, y + 1/6 * height],
[x + 1/6 * width, y + 1/6 * height],
[x + 1/6 * width, y + 1/2 * height],
[x - 1/6 * width, y + 1/2 * height],
[x - 1/6 * width, y + 1/6 * height],
[x - 1/2 * width, y + 1/6 * height],
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'cross',
view: CrossView,
model: CrossModel
}

View File

@@ -0,0 +1,92 @@
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 圆柱体
class CylindeModel extends RectResize.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 60
this.height = 80
}
getNodeStyle () {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle () {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class CylindeView extends RectResize.view {
getResizeShape () {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
// 圆柱体顶部椭圆
const ellipseAAttrs = {
...style,
cx: x,
cy: y - 1/3 * height,
rx: 1/2 * width,
ry: 1/6 * height,
width,
height
}
// 圆柱体左直线
const pathAAttrs = {
...style,
d: `M ${x - 1/2 * width} ${y - 1/3 * height} L ${x - 1/2 * width} ${y + 1/3 * height}`
}
// 圆柱体右直线
const pathBAttrs = {
...style,
d: `M ${x + 1/2 * width} ${y - 1/3 * height} L ${x + 1/2 * width} ${y + 1/3 * height}`
}
// 圆柱体下椭圆
const ellipseBAttrs = {
...style,
cx: x,
cy: y + 1/3 * height,
rx: 1/2 * width,
ry: 1/6 * height,
width,
height
}
// 圆柱体中间填充部分
const rectAttrs = {
...style,
x: x - 1/2 * width,
y: y - 1/3 * height,
width,
height: 2/3 * height,
stroke: 'transparent'
}
return h('g', {}, [
h('ellipse', {
...ellipseBAttrs
}),
h('rect', {
...rectAttrs
}),
h('path', {
...pathAAttrs
}),
h('path', {
...pathBAttrs
}),
h('ellipse', {
...ellipseAAttrs
})
])
}
}
export default {
type: 'cylinde',
model: CylindeModel,
view: CylindeView
}

View File

@@ -0,0 +1,84 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 除号
class DivideModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class DivideView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 1/2 * width, y - 1/8 * height],
[x + 1/2 * width, y - 1/8 * height],
[x + 1/2 * width, y + 1/8 * height],
[x - 1/2 * width, y + 1/8 * height],
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
}
// 除号中间横线
const lineAttrs = {
...attrs,
points: points.join(' ')
}
// 除号上圆点
const upEllipseAttrs = {
...attrs,
cy: y - 3/8 * height,
cx: x,
rx: 1/8* width,
ry: 1/8 * height
}
// 除号下圆点
const downEllipseAttrs = {
...attrs,
cy: y + 3/8 * height,
cx: x,
rx: 1/8 * width,
ry: 1/8 * height
}
return h('g', {}, [
h('polygon', { ...lineAttrs }),
h('ellipse', { ...upEllipseAttrs }),
h('ellipse', { ...downEllipseAttrs })
])
}
}
export default {
type: 'divide',
view: DivideView,
model: DivideModel
}

View File

@@ -0,0 +1,62 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 五边形
class HeptagonModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class HeptagonView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 0.205 * width, y - 0.5 * height],
[x + 0.205 * width, y - 0.5 * height],
[x + 0.5 * width, y - 0.205 * height],
[x + 0.5 * width, y + 0.205 * height],
[x + 0.205 * width, y + 0.5 * height],
[x - 0.205 * width, y + 0.5 * height],
[x - 0.5 * width, y + 0.205 * height],
[x - 0.5 * width, y - 0.205 * height]
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'heptagon',
view: HeptagonView,
model: HeptagonModel
}

View File

@@ -0,0 +1,60 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 六边形
class HexagonModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class HexagonView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 0.28 * width, y - 0.5 * height],
[x + 0.28 * width, y - 0.5 * height],
[x + 0.5 * width, y],
[x + 0.28 * width, y + 0.5 * height],
[x - 0.28 * width, y + 0.5 * height],
[x - 0.5 * width, y]
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'hexagon',
view: HexagonView,
model: HexagonModel
}

View File

@@ -0,0 +1,58 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 减号
class MinusModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 20
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class MinusView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 1/2 * width, y - 1/2 * height],
[x + 1/2 * width, y - 1/2 * height],
[x + 1/2 * width, y + 1/2 * height],
[x - 1/2 * width, y + 1/2 * height],
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'minus',
view: MinusView,
model: MinusModel
}

View File

@@ -0,0 +1,57 @@
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 平行四边形
class ParallelogramModel extends RectResize.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 100
this.height = 60
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class ParallelogramView extends RectResize.view {
getResizeShape() {
const { x, y, width, height } = this.props.model;
const style = this.props.model.getNodeStyle();
const pointList = [
[x - width / 2, y + height/2],
[x - width / 5, y - height/2],
[x + width / 2, y - height/2],
[x + width / 5, y + height/2]
];
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
]
)
}
}
export default {
type: 'parallelogram',
view: ParallelogramView,
model: ParallelogramModel
}

View File

@@ -0,0 +1,59 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 八边形
class PentagonModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class PentagonView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 0.5 * width, y],
[x, y - 0.5 * height],
[x + 0.5 * width, y],
[x + 0.3 * width, y + 0.5 * height],
[x - 0.3 * width, y + 0.5 * height]
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'pentagon',
view: PentagonView,
model: PentagonModel
}

View File

@@ -0,0 +1,61 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 七边形
class SeptagonModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class SeptagonView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x, y - 0.5 * height],
[x + 0.395 * width, y - 0.3 * height],
[x + 0.5 * width, y + 0.145 * height],
[x + 0.225 * width, y + 0.5 * height],
[x - 0.225 * width, y + 0.5 * height],
[x - 0.5 * width, y + 0.145 * height],
[x - 0.395 * width, y - 0.3 * height]
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'septagon',
view: SeptagonView,
model: SeptagonModel
}

View File

@@ -0,0 +1,40 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
// 五角星
class StarModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80;
this.height = 80;
}
}
class StarView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const svgAttr = {
x: x - 1/2 * width,
y: y - 1/2 * height,
width,
height,
}
const pathAAttrs = {
...style,
d: 'm0.36922,13.46587l12.98695,0l4.01307,-13.36885l4.01307,13.36885l12.98694,0l-10.50664,8.26231l4.01327,13.36885l-10.50665,-8.26253l-10.50664,8.26253l4.01327,-13.36885l-10.50665,-8.26231l0,0z'
}
return h('svg', { ...svgAttr, viewBox: '0 0 37 37' }, [
h('path', {
...pathAAttrs,
})
])
}
}
export default {
type: 'star',
view: StarView,
model: StarModel
}

View File

@@ -0,0 +1,66 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 乘号
class TimesModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class TimesView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 1/2 * width, y - 1/3 * height],
[x - 1/3 * width, y - 1/2 * height],
[x, y - 1/6 * height],
[x + 1/3 * width, y - 1/2 * height],
[x + 1/2 * width, y - 1/3 * height],
[x + 1/6 * width, y],
[x + 1/2 * width, y + 1/3 * height],
[x + 1/3 * width, y + 1/2 * height],
[x, y + 1/6 * height],
[x - 1/3 * width, y + 1/2 * height],
[x - 1/2 * width, y + 1/3 * height],
[x - 1/6 * width, y],
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'times',
view: TimesView,
model: TimesModel
}

View File

@@ -0,0 +1,58 @@
import { h } from '@logicflow/core'
import RectNode from '../basic/RectNode'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 五边形
class TrapezoidModel extends RectNode.model {
initNodeData(data) {
super.initNodeData(data)
this.width = 80
this.height = 80
}
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class TrapezoidView extends RectNode.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const pointList = [
[x - 0.31 * width, y - 0.5 * height],
[x + 0.31 * width, y - 0.5 * height],
[x + 0.5 * width, y + 0.5 * height],
[x - 0.5 * width, y + 0.5 * height]
]
const points = pointList.map(item => {
return `${item[0]},${item[1]}`
})
const attrs = {
...style,
x,
y,
width,
height,
points: points.join(' ')
}
return h('g', {}, [
h('polygon', { ...attrs })
])
}
}
export default {
type: 'trapezoid',
view: TrapezoidView,
model: TrapezoidModel
}

View File

@@ -0,0 +1,47 @@
import { h } from '@logicflow/core'
import { RectResize } from '@logicflow/extension'
import { getShapeStyleFuction, getTextStyleFunction } from '../getShapeStyleUtil'
// 三角形
class TriangleModel extends RectResize.model {
getNodeStyle() {
const style = super.getNodeStyle()
const properties = this.getProperties()
return getShapeStyleFuction(style, properties)
}
getTextStyle() {
const style = super.getTextStyle()
const properties = this.getProperties()
return getTextStyleFunction(style, properties)
}
}
class TriangleView extends RectResize.view {
getResizeShape() {
const { x, y, width, height } = this.props.model
const style = this.props.model.getNodeStyle()
const attrs = {
...style,
x,
y,
width,
height,
points: [
[x - width / 2, y + height / 2],
[x - width / 2, y - height / 2],
[x + width / 2, y]
]
}
return h('g', {}, [
h('polygon', { ...attrs })
]
)
}
}
export default {
type: 'triangle',
view: TriangleView,
model: TriangleModel
}

View File

@@ -0,0 +1,227 @@
<template>
<div class="diagram">
<div class="diagram-main">
<div class="diagram-container">
<div class="diagram-wrapper">
<div ref="diagram" class="lf-diagram"></div>
</div>
</div>
</div>
</div>
</template>
<script>
import LogicFlow from "@logicflow/core";
import { BpmnElement} from "@logicflow/extension";
// import { SelectionSelect, Menu } from "@logicflow/extension";
import "@logicflow/core/dist/style/index.css";
import "@logicflow/extension/lib/style/index.css";
import { registerCustomElement } from "./node";
export default {
name: "DiagramView",
components: {},
data() {
return {
lf: "",
activeNodes: [],
activeEdges: [],
properties: {},
timer: null,
time: 60000
};
},
watch: {
// appStore: {
// handler() {
// if (this.lf) {
// // this.lf.graphModel.resize();
// // this.lf.fitView();
// // 侧栏有动画,所以要加延时
// setTimeout(() => {
// this.lf.graphModel.resize();
// this.lf.fitView();
// }, 500);
// }
// },
// deep: true,
// },
},
mounted() {
// this.initLogicFlow(exportInfo);
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer)
}
},
methods: {
initLogicFlow(data) {
// 引入框选插件
// LogicFlow.use(SelectionSelect);
// LogicFlow.use(Menu);
LogicFlow.use(BpmnElement);
const lf = new LogicFlow({
container: this.$refs.diagram,
overlapMode: 1,
autoWrap: true,
stopScrollGraph: true,
stopZoomGraph: true,
stopMoveGraph: true,
metaKeyMultipleSelected: true,
keyboard: {
enabled: false,
},
isSilentMode: true,
grid: {
visible: false,
size: 1,
type: "mesh",
config: {
color: "rgba(255,255,255,0.1)",
thickness: 1,
},
},
background: {
backgroundColor: "rgba(29, 32, 98, 1)",
// backgroundImage:
// 'url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTSAwIDEwIEwgNDAgMTAgTSAxMCAwIEwgMTAgNDAgTSAwIDIwIEwgNDAgMjAgTSAyMCAwIEwgMjAgNDAgTSAwIDMwIEwgNDAgMzAgTSAzMCAwIEwgMzAgNDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QwZDBkMCIgb3BhY2l0eT0iMC4yIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNIDQwIDAgTCAwIDAgMCA0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDBkMGQwIiBzdHJva2Utd2lkdGg9IjEiLz48L3BhdHRlcm4+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JpZCkiLz48L3N2Zz4=")',
// backgroundRepeat: "repeat",
},
});
lf.setTheme({
baseEdge: { strokeWidth: 1 },
baseNode: { strokeWidth: 1 },
nodeText: { overflowMode: "autoWrap", lineHeight: 1.5 },
edgeText: { overflowMode: "autoWrap", lineHeight: 1.5 },
});
// 注册自定义元素
registerCustomElement(lf);
lf.setDefaultEdgeType("pro-polyline");
lf.render(data);
lf.fitView();
this.lf = lf;
},
setType(errorMap) {
const gatwayStatus = {
error: 0,
success: 0
}
let all = this.lf.getGraphRawData();
all.nodes.forEach((item) => {
if (!item.type.includes('status')) {
return
}
if (item.properties.deviceType == 1 && errorMap.T80ErrorArr.some(i => i == item.properties.equipmentId)) {
this.lf.changeNodeType(item.id, "status_error");
} else if (item.properties.deviceType == 2 && errorMap.ZLErrorArr.some(i => i == item.properties.equipmentId)) {
this.lf.changeNodeType(item.id, "status_error");
} else if (item.properties.deviceType == 3 && errorMap.TimeOutErrorArr.some(i => i == item.properties.equipmentId)) {
this.lf.changeNodeType(item.id, "status_error");
} else if (item.properties.deviceType == 3 || item.properties.deviceType == 2 || item.properties.deviceType == 1) {
this.lf.changeNodeType(item.id, "status_success");
} else if (item.properties.deviceType == 4) {
let equipments = item.properties.equipmentId.split(',')
equipments = equipments.map(i => i.trim())
if (equipments.every(equipmentId => errorMap.TimeOutErrorArr.includes(equipmentId))) {
gatwayStatus.error++
this.lf.changeNodeType(item.id, "status_error");
} else {
gatwayStatus.success++
this.lf.changeNodeType(item.id, "status_success");
}
}
});
this.$emit('gatewayStatus', gatwayStatus)
},
setTypeByDeviceID(deviceID, itemID, status) {
let all = this.lf.getGraphRawData();
all.nodes.forEach((item) => {
if (item.properties.deviceType) {
return
}
if (item.properties.deviceID == deviceID && item.properties.itemID == itemID && status == 1) {
this.lf.changeNodeType(item.id, "status_success");
} else if (item.properties.deviceID == deviceID && item.properties.itemID == itemID && status == 0) {
this.lf.changeNodeType(item.id, "status_error");
}
});
},
networkError() {
let all = this.lf.getGraphRawData();
all.nodes.forEach((item) => {
if (item.properties.deviceType) {
return
}
if (item.properties.deviceID && item.properties.itemID) {
this.lf.changeNodeType(item.id, "status_error");
}
});
},
},
};
</script>
<style scoped>
.diagram {
width: 100%;
height: 100%;
}
.diagram * {
box-sizing: border-box;
}
.diagram-main {
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
}
.diagram-container {
flex: 1;
}
/* 由于背景图和gird不对齐需要css处理一下 */
/* .diagram /deep/ .lf-background {
left: -9px;
} */
.diagram-wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
}
.lf-diagram {
box-shadow: 0px 0px 4px #838284;
width: 100%;
height: 100%;
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
background: white;
border-left: 1px solid #e8e8e8;
}
::-webkit-scrollbar-thumb {
border-width: 1px;
border-style: solid;
border-color: #fff;
border-radius: 6px;
background: #c9c9c9;
}
::-webkit-scrollbar-thumb:hover {
background: #b5b5b5;
}
</style>

View File

@@ -1,7 +1,7 @@
import * as ElementPlusIcons from '@element-plus/icons-vue'
import type { App } from 'vue'
//https://github.com/element-plus/element-plus/issues/7293
import 'element-plus/es/components/dialog/style/css'
// import 'element-plus/es/components/dialog/style/css'
export default (app: App<Element>) => {
// 全局注册ElementPlus图标

View File

@@ -59,7 +59,9 @@ const handleCommand = (command: any) => {
</script>
<style lang="scss" scoped>
.app-tabs {
@apply border-t border-br;
border-top: 1px solid var(--el-border-color);
// border-color: var(--el-border-color);
:deep(.el-tabs) {
height: 40px;
.el-tabs {
@@ -71,7 +73,7 @@ const handleCommand = (command: any) => {
}
&__nav-next,
&__nav-prev {
@apply text-xl;
font-size: var(--el-font-size-large);
}
&__nav-wrap::after {

View File

@@ -5,6 +5,13 @@ import './permission'
import './styles/index.scss'
import 'virtual:svg-icons-register'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import VForm3 from 'vform3-builds' //引入VForm3库
const app = createApp(App)
app.use(install)
app.use(ElementPlus)
app.use(VForm3)
app.mount('#app')

View File

@@ -8,9 +8,9 @@
position: static;
.el-dialog {
--el-dialog-content-font-size: var(--el-font-size-base);
--el-dialog-margin-top: 50px;
max-width: calc(100vw - 30px);
// --el-dialog-content-font-size: var(--el-font-size-base);
// --el-dialog-margin-top: 50px;
// max-width: calc(100vw - 20px);
flex: none;
display: flex;
flex-direction: column;

View File

@@ -1,6 +1,6 @@
@import 'tailwind.css';
@import 'element.scss';
@import 'dark.css';
@import 'var.css';
@import 'tailwind.css';
@import 'public.scss';

View File

@@ -16,3 +16,7 @@ body {
#nprogress .bar {
@apply bg-primary #{!important};
}
a {
text-decoration: none;
}

View File

@@ -1,3 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* @tailwind base; */
/* @tailwind components; */
@tailwind utilities;

View File

@@ -89,7 +89,11 @@
<el-table-column label="发布时间" prop="createTime" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button v-perms="['article:edit','article:add/edit']" type="primary" link>
<el-button
v-perms="['article:edit', 'article:add/edit']"
type="primary"
link
>
<router-link
:to="{
path: getRoutePath('article:add/edit'),

View File

@@ -26,27 +26,30 @@
新增
</el-button>
</div>
<el-table
class="mt-4"
size="large"
v-loading="pager.loading"
:data="pager.lists"
>
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="流程名称" prop="flowName" min-width="100" />
<el-table-column label="流程分类" prop="flowGroup" min-width="100" />
<el-table-column label="流程描述" prop="flowRemark" min-width="100" />
<el-table-column label="表单配置" prop="flowFormData" min-width="100" />
<el-table-column label="流程配置" prop="flowProcessData" min-width="100" />
<el-table-column label="操作" width="120" fixed="right">
<!-- <el-table-column label="表单配置" prop="flowFormData" min-width="100" />
<el-table-column label="流程配置" prop="flowProcessData" min-width="100" /> -->
<el-table-column label="操作" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['flow_template:edit']"
type="primary"
link
@click="handleConfig(row)"
>
配置
</el-button>
<!-- <el-button
v-perms="['flow_template:edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
</el-button> -->
<el-button
v-perms="['flow_template:del']"
type="danger"
@@ -62,19 +65,28 @@
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup
v-if="showEdit"
ref="editRef"
@success="getLists"
@close="showEdit = false"
/>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
<Approver ref="approverRef" :save="save"></Approver>
</div>
</template>
<script lang="ts" setup name="flow_template">
import { flow_template_delete, flow_template_lists } from '@/api/flow_template'
<script lang="ts" setup>
import {
flow_template_delete,
flow_template_lists,
flow_template_edit,
flow_template_add,
flow_template_detail
} from '@/api/flow_template'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
import Approver from '@/components/flow/Approver.vue'
defineOptions({
name: 'flow_template'
})
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive({
@@ -82,7 +94,7 @@ const queryParams = reactive({
flowGroup: '',
flowRemark: '',
flowFormData: '',
flowProcessData: '',
flowProcessData: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
@@ -90,19 +102,20 @@ const { pager, getLists, resetPage, resetParams } = usePaging({
params: queryParams
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
// showEdit.value = true
// await nextTick()
// editRef.value?.open('add')
approverRef.value?.open()
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.getDetail(data)
}
// const handleEdit = async (data: any) => {
// showEdit.value = true
// await nextTick()
// editRef.value?.open('edit')
// editRef.value?.getDetail(data)
// }
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
@@ -110,6 +123,61 @@ const handleDelete = async (id: number) => {
feedback.msgSuccess('删除成功')
getLists()
}
function save(info) {
return new Promise((resolve, reject) => {
if (info.id) {
flow_template_edit({
id: info.id,
flowName: info.basicSetting.flowName,
flowGroup: info.basicSetting.flowGroup,
flowRemark: info.basicSetting.flowRemark,
flowFormData: JSON.stringify(info.flowFormData),
flowProcessData: JSON.stringify(info.flowProcessData)
})
.then(() => {
feedback.msgSuccess('修改成功')
getLists()
resolve(true)
})
.catch((err) => {
feedback.msgError(err.message)
reject()
})
} else {
flow_template_add({
flowName: info.flowName,
flowGroup: info.flowGroup,
flowRemark: info.flowRemark,
flowFormData: JSON.stringify(info.flowFormData),
flowProcessData: JSON.stringify(info.flowProcessData)
})
.then(() => {
feedback.msgSuccess('新增成功')
getLists()
resolve(true)
})
.catch((err) => {
feedback.msgError(err.message)
reject()
})
}
})
}
const approverRef = shallowRef<InstanceType<typeof EditPopup>>()
const handleConfig = async (data: any) => {
console.log('toRaw(data)', toRaw(data))
approverRef.value?.open({
id: data.id,
basicSetting: {
flowName: data.flowName,
flowGroup: data.flowGroup,
flowRemark: data.flowRemark
},
flowFormData: JSON.parse(data.flowFormData),
flowProcessData: JSON.parse(data.flowProcessData)
} as any)
}
getLists()
</script>

View File

@@ -96,6 +96,7 @@ import type { ElTable, FormInstance } from 'element-plus'
import EditPopup from './edit.vue'
import { deptDelete, deptLists } from '@/api/org/department'
import feedback from '@/utils/feedback'
import { arrayToTree } from '@/utils/util'
const tableRef = shallowRef<InstanceType<typeof ElTable>>()
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const formRef = shallowRef<FormInstance>()
@@ -109,7 +110,10 @@ const queryParams = reactive({
const showEdit = ref(false)
const getLists = async () => {
loading.value = true
lists.value = await deptLists(queryParams)
const list = await deptLists(queryParams)
// 根据id和pid处理层级关系
lists.value = arrayToTree(list)
loading.value = false
}

View File

@@ -35,18 +35,18 @@ export default ({ mode }) => {
vueJsx(),
AutoImport({
imports: ['vue', 'vue-router'],
resolvers: [ElementPlusResolver()],
// resolvers: [ElementPlusResolver()],
eslintrc: {
enabled: true
}
}),
Components({
directoryAsNamespace: true,
resolvers: [ElementPlusResolver()]
}),
createStyleImportPlugin({
resolves: [ElementPlusResolve()]
directoryAsNamespace: true
// resolvers: [ElementPlusResolver()]
}),
// createStyleImportPlugin({
// resolves: [ElementPlusResolve()]
// }),
createSvgIconsPlugin({
// 配置路劲在你的src里的svg存放文件
iconDirs: [fileURLToPath(new URL('./src/assets/icons', import.meta.url))],