流程设计器
This commit is contained in:
parent
ccba9e88de
commit
e33a185c03
|
|
@ -1,5 +1,5 @@
|
|||
# 页面标题
|
||||
VITE_APP_TITLE=里派基础框架
|
||||
VITE_APP_TITLE=里派基础框架(开发版)
|
||||
|
||||
# 开发环境配置
|
||||
VITE_APP_ENV='development'
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@logicflow/core": "^2.2.0-alpha.0",
|
||||
"@logicflow/extension": "^2.2.0-alpha.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "1.12.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765187652838" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="131708" width="256" height="256"><path d="M960 317.03h-65.41V714.8c0 30.93-25.07 56-56 56H185.41c-30.93 0-56-25.07-56-56V317.03H64v521.16c0 30.93 25.07 56 56 56h784c30.93 0 56-25.07 56-56V317.03zM404.37 129.81h215.25v72.74H404.37z" p-id="131709"></path><path d="M621.6 501V249.08H406.34V501H302.78L512 710.22 721.22 501z" p-id="131710"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765186703331" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="111238" width="256" height="256"><path d="M896 928H128c-17.6 0-32-14.4-32-32s14.4-32 32-32h768c17.6 0 32 14.4 32 32s-14.4 32-32 32z m0-128H128c-17.6 0-32-14.4-32-32V608c0-52.8 43.2-96 96-96h204.8c-6.4-38.4-25.6-75.2-52.8-107.2-36.8-41.6-56-94.4-56-148.8 0-60.8 24-118.4 68.8-161.6 44.8-43.2 102.4-64 164.8-62.4C636.8 36.8 734.4 136 736 251.2c1.6 57.6-20.8 113.6-59.2 156.8-27.2 28.8-43.2 64-49.6 104H832c52.8 0 96 43.2 96 96v160c0 17.6-14.4 32-32 32z m-736-64h704V608c0-17.6-14.4-32-32-32H592c-17.6 0-32-14.4-32-32 0-67.2 24-131.2 68.8-179.2 28.8-30.4 43.2-70.4 43.2-112-1.6-83.2-70.4-153.6-153.6-156.8-44.8-1.6-86.4 14.4-116.8 44.8-32 30.4-49.6 72-49.6 115.2 0 38.4 14.4 76.8 40 105.6 46.4 52.8 72 116.8 72 182.4 0 17.6-14.4 32-32 32H192c-17.6 0-32 14.4-32 32v128z" p-id="111239"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765179193337" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="103617" width="256" height="256"><path d="M512 0C229.218 0 0 229.218 0 512s229.218 512 512 512 512-229.218 512-512S794.782 0 512 0z m0 944c-238.594 0-432-193.406-432-432S273.406 80 512 80s432 193.406 432 432-193.406 432-432 432z" p-id="103618"></path><path d="M512 672.312c-17.656 0-32 14.282-32 31.968s14.344 32.032 32 32.032 32-14.344 32-32.032-14.344-31.968-32-31.968zM512 544.062c-46.25 0-87.124 21.25-114.718 54.094l29.094 38.782c18.594-27.468 49.968-45.5 85.624-45.5s67.032 18.032 85.594 45.5l29.156-38.782c-27.656-32.844-68.5-54.094-114.75-54.094zM326.062 491.656l28.75 38.156c39.812-41 95.468-66.562 157.188-66.562 61.688 0 117.282 25.562 157.218 66.562l28.656-38.188c-48.062-46.812-113.562-75.75-185.876-75.75-72.374 0.002-137.874 28.938-185.936 75.782z" p-id="103619"></path><path d="M256 387.188l31.124 41.5c59.124-54.844 137.968-88.656 224.876-88.656s165.75 33.812 224.812 88.656L768 387.124c-67.844-61.188-157.468-98.782-256-98.782-98.562 0.002-188.124 37.596-256 98.846z" p-id="103620"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765187244666" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="113486" width="256" height="256"><path d="M811.008 768.170667v106.666666a106.666667 106.666667 0 0 1-106.666667 106.666667h-128a21.248 21.248 0 0 1-21.333333-21.333333V938.666667c0-75.52-43.306667-127.872-128.341333-127.872-84.224 0-128.085333 52.821333-128.085334 127.872v21.461333a21.333333 21.333333 0 0 1-21.333333 21.333333h-128a106.666667 106.666667 0 0 1-106.666667-106.709333l0.426667-128a21.333333 21.333333 0 0 1 21.333333-21.248h42.666667c58.752 0 106.410667-55.210667 106.410667-128 0-73.386667-47.36-128-106.410667-128H64.213333a21.333333 21.333333 0 0 1-21.333333-21.333333v-128a106.666667 106.666667 0 0 1 106.666667-106.666667h106.368V213.333333c0-97.066667 61.013333-170.538667 170.752-170.538666 107.008 0 171.392 75.434667 171.392 170.538666v0.128h106.837333a106.666667 106.666667 0 0 1 106.666667 106.666667v106.666667h20.778666c84.053333 0 149.077333 75.008 149.077334 170.666666 0 95.104-65.28 170.666667-149.077334 170.666667h-21.333333z m-42.666667-20.736v-0.597334a21.333333 21.333333 0 0 1 21.333334-21.333333h42.666666c58.752 0 106.410667-55.210667 106.410667-128 0-73.386667-47.36-128-106.410667-128h-42.666666a21.333333 21.333333 0 0 1-20.778667-26.325333V320.128a64 64 0 0 0-64-64h-126.890667a21.76 21.76 0 0 1-1.28 0 21.333333 21.333333 0 0 1-21.333333-21.333333V213.333333c0-72.917333-46.933333-127.872-128.725333-127.872-84.224 0-128.085333 52.821333-128.085334 127.872v21.461334a21.248 21.248 0 0 1-21.333333 21.333333H149.546667a64 64 0 0 0-64 64v106.666667h21.461333c84.053333 0 149.077333 75.008 149.077333 170.666666 0 95.104-65.28 170.666667-149.077333 170.666667h-21.418667l-0.341333 106.666667a64 64 0 0 0 64 64h106.666667V938.666667c0-97.066667 61.013333-170.538667 170.752-170.538667 110.592 0 171.008 73.002667 171.008 170.538667v0.170666h106.666666a64 64 0 0 0 64-64v-127.402666z" p-id="113487"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765195980045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="162965" width="256" height="256"><path d="M678.528 642.304c0 17.6-14.4 32-32 32h-268.992a32 32 0 0 1-32-32V381.696a32 32 0 0 1 32-32h268.992c17.6 0 32 14.4 32 32v260.608z" p-id="162966"></path><path d="M1015.552 512.128a502.656 502.656 0 0 0-503.68-503.68 502.208 502.208 0 0 0-356.096 147.264 502.016 502.016 0 0 0-147.328 356.416 500.288 500.288 0 0 0 146.816 356.736 499.584 499.584 0 0 0 356.544 146.688c277.312-2.816 503.744-226.24 503.744-503.424z m-947.968 0a444.288 444.288 0 0 1 444.288-444.544c246.976 0 447.296 200.128 447.296 444.544 0 244.032-200.32 444.416-447.296 444.416a442.304 442.304 0 0 1-444.288-444.416z" p-id="162967"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765195784018" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="151266" width="256" height="256"><path d="M605.866667 42.666667l375.466666 375.466666a132.721778 132.721778 0 0 1 0 187.733334l-375.466666 375.466666a132.721778 132.721778 0 0 1-187.733334 0l-375.466666-375.466666a132.721778 132.721778 0 0 1 0-187.733334l375.466666-375.466666a132.721778 132.721778 0 0 1 187.733334 0z m-136.192 29.582222l-5.973334 5.290667-386.161777 386.161777a68.266667 68.266667 0 0 0-5.290667 90.624l5.290667 5.973334 386.161777 386.161777a68.266667 68.266667 0 0 0 90.624 5.290667l5.973334-5.290667 386.161777-386.161777a68.266667 68.266667 0 0 0 5.290667-90.624l-5.290667-5.973334-386.161777-386.161777a68.266667 68.266667 0 0 0-90.624-5.290667z m147.399111 292.636444l42.040889 42.040889-105.130667 105.016889 105.130667 105.130667-42.040889 42.040889L512 553.984l-105.073778 105.130667-42.040889-42.040889 105.130667-105.130667-105.130667-105.016889 42.040889-42.040889L512 469.959111l105.073778-105.073778z" p-id="151267"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765011138233" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12401" width="256" height="256"><path d="M582.4 67.2H448c-54.4 0-99.2 44.8-99.2 99.2 0 54.4 44.8 99.2 99.2 99.2h134.4c54.4 0 99.2-44.8 99.2-99.2 0-54.4-44.8-99.2-99.2-99.2z m0 134.4H448c-19.2 0-32-16-32-32 0-19.2 16-32 32-32h134.4c19.2 0 32 16 32 32s-12.8 32-32 32z m0 198.4H448c-54.4 0-99.2 44.8-99.2 99.2 0 54.4 44.8 99.2 99.2 99.2h134.4c54.4 0 99.2-44.8 99.2-99.2 0-54.4-44.8-99.2-99.2-99.2z m0 134.4H448c-19.2 0-32-16-32-32 0-19.2 16-32 32-32h134.4c19.2 0 32 16 32 32s-12.8 32-32 32z m0 201.6H448c-54.4 0-99.2 44.8-99.2 99.2 0 54.4 44.8 99.2 99.2 99.2h134.4c54.4 0 99.2-44.8 99.2-99.2 0-54.4-44.8-99.2-99.2-99.2z m0 134.4H448c-19.2 0-32-16-32-32 0-19.2 16-32 32-32h134.4c19.2 0 32 16 32 32s-12.8 32-32 32z m-368-67.2c-35.2 0-70.4-12.8-96-38.4-25.6-25.6-38.4-57.6-38.4-96 0-35.2 12.8-70.4 38.4-96 25.6-25.6 57.6-38.4 96-38.4h67.2v-67.2h-67.2c-112 0-201.6 89.6-201.6 201.6s89.6 201.6 201.6 201.6v67.2l99.2-99.2L214.4 736v67.2zM816 134.4h-67.2v67.2H816c35.2 0 70.4 12.8 96 38.4 25.6 25.6 38.4 57.6 38.4 96s-12.8 70.4-38.4 96c-25.6 25.6-57.6 38.4-96 38.4v-67.2l-99.2 99.2 99.2 99.2v-67.2c112 0 201.6-89.6 201.6-201.6 0-108.8-89.6-198.4-201.6-198.4z" p-id="12402"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765195912695" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="160862" width="256" height="256"><path d="M509.437437 75.339339c14.35035 0 27.675676 5.637638 37.925926 15.375376L933.285285 476.636637c21.013013 21.013013 21.013013 54.838839 0 75.851851l-378.746746 378.746747c-21.013013 21.013013-54.838839 21.013013-75.851852 0l-385.921922-385.921922c-21.013013-21.013013-21.013013-54.838839 0-75.851852L471.511512 91.227227c10.25025-10.25025 24.088088-15.887888 37.925925-15.887888m0-72.776776C476.124124 2.562563 443.835836 15.887888 420.26026 39.463463l-379.259259 379.25926c-49.201201 49.201201-49.201201 129.153153 0 178.866867l385.921922 385.921922c49.201201 49.201201 129.153153 49.201201 178.866867 0L984.024024 604.764765c49.201201-49.201201 49.201201-129.153153 0-178.866867L598.614615 39.975976C575.039039 16.4004 543.263263 3.075075 509.437437 2.562563z" p-id="160863"></path><path d="M544.800801 308.532533c3.075075 0 5.637638 2.562563 5.637637 5.637637v160.416417h159.903904c3.075075 0 6.15015 2.562563 6.15015 5.637637v64.576577c0 3.075075-2.562563 5.637638-5.637637 5.637637h-159.903904v158.366367c0 3.075075-2.562563 5.637638-5.637638 5.637637H480.224224c-3.075075 0-5.637638-2.562563-5.637637-5.637637l-0.512513-158.366367H314.17017c-3.075075 0-5.637638-2.562563-5.637637-5.637637V480.736737c0-3.075075 2.562563-5.637638 5.637637-5.637638h159.903904l-0.512512-160.928929c0.512513-3.075075 2.562563-5.637638 5.637637-5.637637 1.025025-0.512513 65.601602 0 65.601602 0z" p-id="160864"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765172711806" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15580" width="256" height="256"><path d="M529.222243 943.53334c-247.171426 0-448.25314-201.081715-448.25314-448.241884 0-247.171426 201.081715-448.25314 448.25314-448.25314s448.25314 201.081715 448.25314 448.25314C977.475384 742.451626 776.393669 943.53334 529.222243 943.53334zM529.222243 80.927147c-228.483808 0-414.364309 185.880501-414.364309 414.364309 0 228.472552 185.880501 414.353053 414.364309 414.353053S943.586552 723.764008 943.586552 495.291456C943.586552 266.807648 757.706051 80.927147 529.222243 80.927147z" p-id="15581"></path><path d="M770.723529 539.980261c-24.644283 0-44.677549-20.044522-44.677549-44.688805s20.033265-44.699038 44.677549-44.699038 44.699038 20.054755 44.699038 44.699038S795.367813 539.980261 770.723529 539.980261z" p-id="15582"></path><path d="M529.046235 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S553.690518 539.980261 529.046235 539.980261z" p-id="15583"></path><path d="M295.068296 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S319.712579 539.980261 295.068296 539.980261z" p-id="15584"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765195930707" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="161927" width="256" height="256"><path d="M601.838933 53.248l368.64 369.0496a123.426133 123.426133 0 0 1-0.955733 174.557867l-372.599467 372.9408a123.426133 123.426133 0 0 1-174.557866 0.955733l-368.64-369.0496a123.357867 123.357867 0 0 1 0.955733-174.557867L427.485867 54.135467A123.4944 123.4944 0 0 1 601.838933 53.248z m-125.815466 39.5264l-5.393067 4.846933-372.9408 372.9408a61.8496 61.8496 0 0 0-5.256533 81.92l4.778666 5.3248 368.64 369.0496a61.44 61.44 0 0 0 81.92 4.369067l5.461334-4.778667 372.9408-372.9408a61.917867 61.917867 0 0 0 5.256533-81.92l-4.778667-5.3248-368.64-369.0496a61.44 61.44 0 0 0-81.92-4.369066z m41.7792 238.933333a184.32 184.32 0 1 1-186.1632 184.32 185.1392 185.1392 0 0 1 186.1632-184.661333z m0 61.44a122.88 122.88 0 1 0 124.1088 122.88 123.426133 123.426133 0 0 0-124.1088-123.2896z" p-id="161928"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765187091244" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="112280" width="256" height="256"><path d="M934 271c0-90-73-163-163-163H292.3c-66.5 0-118.8 56.7-113.5 122.9L221.1 704H91l-1 54c0 84.6 66.4 153.6 150 157.8v0.2h424.3c98.2 0 177.7-79.6 177.7-177.7L795.8 328H934v-57zM171.6 834.4c-20.3-20.3-31.5-47.3-31.6-76l0.1-4.4h85.4l9.9 111.3c-24-2.8-46.3-13.5-63.8-30.9zM792 740.9c-0.7 33.2-13.9 64.2-37.4 87.7-24.1 24.1-56.2 37.4-90.3 37.4H285.7l-57.1-639.3c-1.4-17.9 4.6-35 16.8-48.2 12.2-13.2 28.9-20.5 46.9-20.5h19c23.4 26.3 37.7 61 37.7 99 0 25.7-6.5 49.9-18 71h414.4L792 740.9zM884 278H397.9c0.7-7 1.1-14 1.1-21 0-36-9.4-69.8-26-99h398c30.2 0 58.6 11.8 79.9 33.1S884 240.8 884 271v7zM664.5 515h-297v-50h297v50z m0 123.2h-297v-50h297v50z" p-id="112281"></path></svg>
|
||||
</template>
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<div v-if="navMenus.length<=0" style="padding:20px;">
|
||||
<el-alert title="无子集菜单" center type="info" :closable="false"></el-alert>
|
||||
<el-alert :title="t('menu.noSubmenu')" center type="info" :closable="false"></el-alert>
|
||||
</div>
|
||||
<template v-for="navMenu in navMenus" v-bind:key="navMenu">
|
||||
<el-menu-item v-if="!hasChildren(navMenu)" :index="navMenu.path">
|
||||
<a v-if="navMenu.meta&&navMenu.meta.type=='link'" :href="navMenu.path" target="_blank"
|
||||
<a v-if="navMenu.meta&&navMenu.meta.type==='link'" :href="navMenu.path" target="_blank"
|
||||
@click.stop='()=>{}'></a>
|
||||
<el-icon v-if="navMenu.meta&&navMenu.meta?.icon">
|
||||
<component :is="navMenu.meta?.icon || 'el-icon-menu'"/>
|
||||
</el-icon>
|
||||
<template #title>
|
||||
<span>{{ navMenu.meta.title }}</span>
|
||||
<span v-if="navMenu.meta.tag" class="menu-tag">{{ navMenu.meta.tag }}</span>
|
||||
<span v-if="navMenu.meta.tag" class="menu-tag">{{ navMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<el-sub-menu v-else :index="navMenu.path">
|
||||
|
|
@ -20,14 +20,20 @@
|
|||
<component :is="navMenu.meta?.icon || 'el-icon-menu'"/>
|
||||
</el-icon>
|
||||
<span>{{ navMenu.meta.title }}</span>
|
||||
<span v-if="navMenu.meta.tag" class="menu-tag">{{ navMenu.meta.tag }}</span>
|
||||
<span v-if="navMenu.meta.tag" class="menu-tag">{{ navMenu.meta.title }}</span>
|
||||
</template>
|
||||
<NavMenu :navMenus="navMenu.children"></NavMenu>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup name="NavMenu">
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
defineOptions({
|
||||
name: 'NavMenu'
|
||||
})
|
||||
const {t} = useI18n()
|
||||
const props = defineProps(['navMenus']);
|
||||
|
||||
function hasChildren(item) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<div class="sc-search">
|
||||
<el-input ref="input" v-model="searchText" placeholder="搜索" size="large" clearable prefix-icon="el-icon-search"
|
||||
<el-input ref="input" v-model="searchText" placeholder="搜索" size="large" clearable
|
||||
prefix-icon="el-icon-search"
|
||||
:trigger-on-focus="false" @input="inputChange"/>
|
||||
<div class="sc-search-history" v-if="history.length>0">
|
||||
<el-tag closable effect="dark" type="info" v-for="(item, index) in history" :key="item"
|
||||
|
|
@ -8,7 +9,7 @@
|
|||
</el-tag>
|
||||
</div>
|
||||
<div class="sc-search-result">
|
||||
<div class="sc-search-no-result" v-if="result.length<=0">暂无搜索结果</div>
|
||||
<div class="sc-search-no-result" v-if="result.length<=0">{{ t('menu.noSearchResults') }}</div>
|
||||
<ul v-else>
|
||||
<el-scrollbar max-height="366px">
|
||||
<li v-for="item in result" :key="item.path" @click="to(item)">
|
||||
|
|
@ -24,10 +25,12 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted, getCurrentInstance} from "vue";
|
||||
import tools from "@/utils/tools.js";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ref, onMounted, getCurrentInstance} from "vue"
|
||||
import tools from "@/utils/tools.js"
|
||||
import {useRouter} from "vue-router"
|
||||
import {useI18n} from "vue-i18n"
|
||||
|
||||
const {t} = useI18n()
|
||||
const {proxy} = getCurrentInstance()
|
||||
const router = useRouter()
|
||||
|
||||
|
|
@ -53,10 +56,10 @@ function inputChange(value) {
|
|||
|
||||
function filterMenu(map) {
|
||||
map.forEach(item => {
|
||||
if (item.meta.hidden || item.meta.type == "button") {
|
||||
if (item.meta.hidden || item.meta.type === "button") {
|
||||
return false
|
||||
}
|
||||
if (item.meta.type == 'iframe') {
|
||||
if (item.meta.type === 'iframe') {
|
||||
item.path = `/i/${item.name}`
|
||||
}
|
||||
if (item.children && item.children.length > 0 && !item.component) {
|
||||
|
|
@ -84,10 +87,10 @@ function menuFilter(queryString) {
|
|||
//匹配系统路由
|
||||
const routes = router.getRoutes();
|
||||
const filterRouter = filterMenu.map((m) => {
|
||||
if (m.meta.type == "link") {
|
||||
return routes.find(r => r.path == '/' + m.path)
|
||||
if (m.meta.type === "link") {
|
||||
return routes.find(r => r.path === '/' + m.path)
|
||||
} else {
|
||||
return routes.find(r => r.path == m.path)
|
||||
return routes.find(r => r.path === m.path)
|
||||
}
|
||||
});
|
||||
//重组对象
|
||||
|
|
@ -95,7 +98,7 @@ function menuFilter(queryString) {
|
|||
res.push({
|
||||
name: item.name,
|
||||
type: item.meta.type,
|
||||
path: item.meta.type == "link" ? item.path.slice(1) : item.path,
|
||||
path: item.meta.type === "link" ? item.path.slice(1) : item.path,
|
||||
icon: item.meta.icon,
|
||||
title: item.meta.title,
|
||||
breadcrumb: item.meta.breadcrumb.map(v => v.meta.title).join(' - ')
|
||||
|
|
@ -109,7 +112,7 @@ function to(item) {
|
|||
history.value.push(searchText.value)
|
||||
tools.data.set("SEARCH_HISTORY", history.value)
|
||||
}
|
||||
if (item.type == "link") {
|
||||
if (item.type === "link") {
|
||||
setTimeout(() => {
|
||||
let a = document.createElement("a")
|
||||
a.style = "display: none"
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
<el-form ref="form" label-width="120px" label-position="left" style="padding:0 20px;">
|
||||
<el-divider>{{ t('user.thememode') }}</el-divider>
|
||||
<el-row class="pi-theme" :gutter="20">
|
||||
<el-col :span="8"><img src="/images/light.png" class="pi-pic" :class="{'active': dark == 'light'}"
|
||||
<el-col :span="8"><img src="/images/light.png" class="pi-pic" :class="{'active': dark === 'light'}"
|
||||
@click="themeClick('light')"/>
|
||||
<el-text type="info" class="pi-text">浅色</el-text>
|
||||
<el-text type="info" class="pi-text">{{t('system.lightColor')}}</el-text>
|
||||
</el-col>
|
||||
<el-col :span="8"><img src="/images/dark.png" class="pi-pic" :class="{'active': dark == 'dark'}"
|
||||
<el-col :span="8"><img src="/images/dark.png" class="pi-pic" :class="{'active': dark === 'dark'}"
|
||||
@click="themeClick('dark')"/>
|
||||
<el-text type="info" class="pi-text">深色</el-text>
|
||||
<el-text type="info" class="pi-text">{{t('system.darkColor')}}</el-text>
|
||||
</el-col>
|
||||
<el-col :span="8"><img src="/images/follow.png" class="pi-pic" :class="{'active': dark == 'follow'}"
|
||||
<el-col :span="8"><img src="/images/follow.png" class="pi-pic" :class="{'active': dark === 'follow'}"
|
||||
@click="themeClick('follow')"/>
|
||||
<el-text type="info" class="pi-text">跟随系统</el-text>
|
||||
<el-text type="info" class="pi-text">{{t('system.followSystem')}}</el-text>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider></el-divider>
|
||||
|
|
@ -51,13 +51,13 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, watch} from "vue";
|
||||
import {ref, watch} from "vue"
|
||||
import colorTool from '@/utils/color'
|
||||
import tools from "@/utils/tools";
|
||||
import config from "@/config";
|
||||
import globalStore from "@/store/global.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {setupI18n} from "@/locales/setup.js";
|
||||
import tools from "@/utils/tools"
|
||||
import config from "@/config"
|
||||
import globalStore from "@/store/global.js"
|
||||
import {useI18n} from "vue-i18n"
|
||||
import {setupI18n} from "@/locales/setup.js"
|
||||
|
||||
const global = globalStore()
|
||||
const {t} = useI18n()
|
||||
|
|
@ -115,10 +115,10 @@ watch(colorPrimary, (val) => {
|
|||
})
|
||||
|
||||
function themeClick(val) {
|
||||
if (val == 'dark') {
|
||||
if (val === 'dark') {
|
||||
document.documentElement.classList.add("dark")
|
||||
localStorage.setItem("APP_DARK", val)
|
||||
} else if (val == 'light') {
|
||||
} else if (val === 'light') {
|
||||
document.documentElement.classList.remove("dark")
|
||||
localStorage.setItem("APP_DARK", val)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -22,33 +22,33 @@
|
|||
<el-icon>
|
||||
<el-icon-refresh/>
|
||||
</el-icon>
|
||||
刷新
|
||||
{{t('menu.refresh')}}
|
||||
</li>
|
||||
<hr>
|
||||
<li @click="closeTabs()" :class="contextMenuItem.meta.affix?'disabled':''">
|
||||
<el-icon>
|
||||
<el-icon-close/>
|
||||
</el-icon>
|
||||
关闭标签
|
||||
{{t('menu.closeTab')}}
|
||||
</li>
|
||||
<li @click="closeOtherTabs()">
|
||||
<el-icon>
|
||||
<el-icon-folder-delete/>
|
||||
</el-icon>
|
||||
关闭其他标签
|
||||
{{t('menu.closeOtherTabs')}}
|
||||
</li>
|
||||
<hr>
|
||||
<li @click="maximize()">
|
||||
<el-icon>
|
||||
<el-icon-full-screen/>
|
||||
</el-icon>
|
||||
最大化
|
||||
{{t('menu.maximize')}}
|
||||
</li>
|
||||
<li @click="openWindow()">
|
||||
<el-icon>
|
||||
<el-icon-copy-document/>
|
||||
</el-icon>
|
||||
在新的窗口中打开
|
||||
{{t('menu.openInNewWindow')}}
|
||||
</li>
|
||||
</ul>
|
||||
</transition>
|
||||
|
|
@ -65,7 +65,9 @@ import keepAliveStore from "@/store/keepAlive";
|
|||
import iframeStore from "@/store/iframe";
|
||||
import {useRouter, useRoute} from "vue-router";
|
||||
import {getMenu} from "@/utils/route"
|
||||
import {useI18n} from "vue-i18n"
|
||||
|
||||
const {t} = useI18n()
|
||||
const viewTags = viewTagsStore()
|
||||
const keepAlive = keepAliveStore()
|
||||
const iframe = iframeStore()
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, watch} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {ref, watch} from "vue"
|
||||
import {useRoute} from "vue-router"
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
let breadList = ref([])
|
||||
|
||||
getBreadcrumb();
|
||||
|
|
@ -37,7 +36,7 @@ watch(route, () => {
|
|||
})
|
||||
|
||||
function getBreadcrumb() {
|
||||
breadList.value = route.meta.breadcrumb;
|
||||
breadList.value = route.meta.breadcrumb
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@
|
|||
<div class="pi-side-split-scroll">
|
||||
<el-scrollbar>
|
||||
<ul>
|
||||
<li v-for="item in menu" :key="item" :class="pmenu.path==item.path?'active':''"
|
||||
<li v-for="item in menu" :key="item" :class="pmenu.path===item.path?'active':''"
|
||||
@click="showMenu(item)">
|
||||
<el-icon>
|
||||
<component :is="item.meta?.icon || 'el-icon-menu'"/>
|
||||
|
|
@ -248,7 +248,6 @@ import userbar from './components/userbar.vue';
|
|||
import iframeView from './components/iframeView.vue';
|
||||
import globalStore from "@/store/global.js";
|
||||
import keepAliveStore from "@/store/keepAlive.js";
|
||||
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import config from "@/config";
|
||||
import {getMenu} from '@/utils/route'
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import {ElNotification} from 'element-plus';
|
|||
import config from "@/config"
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import tools from '@/utils/tools';
|
||||
import api from "@/api";
|
||||
import sRouter from './system';
|
||||
import tools from '@/utils/tools'
|
||||
import api from "@/api"
|
||||
import sRouter from './system'
|
||||
import {treeFilter, filterAsyncRouter, flatAsyncRoutes} from '@/utils/route'
|
||||
import {beforeEach, afterEach} from '@/utils/route';
|
||||
import {beforeEach, afterEach} from '@/utils/route'
|
||||
import i18n from "@/locales"
|
||||
|
||||
//系统路由
|
||||
const routes = sRouter
|
||||
|
|
@ -93,7 +94,7 @@ router.afterEach((to, from) => {
|
|||
router.onError((error) => {
|
||||
NProgress.done();
|
||||
ElNotification.error({
|
||||
title: '路由错误',
|
||||
title: i18n.global.t('menu.routingError'),
|
||||
message: error.message
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="item in langs" :key="item.value" :command="item"
|
||||
:class="{'selected':lang==item.value}">{{ item.name }}
|
||||
:class="{'selected':lang===item.value}">{{ item.name }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
|
|
@ -133,9 +133,9 @@ let isLogin = ref(false);
|
|||
|
||||
const darkConfig = localStorage.getItem('APP_DARK') || sysConfig.DARK
|
||||
|
||||
if (darkConfig == "dark") {
|
||||
if (darkConfig === "dark") {
|
||||
dark.value = true
|
||||
} else if (darkConfig == 'follow') {
|
||||
} else if (darkConfig === 'follow') {
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
if (systemTheme.matches) {
|
||||
dark.value = true
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
</pi-table>
|
||||
<el-drawer v-model="drawerShow" :size="450" title="翻译管理" destroy-on-close>
|
||||
<el-drawer v-model="drawerShow" :size="450" title="翻译管理" destroy-on-close :close-on-click-modal="false">
|
||||
<save ref="saveRef" @success="tableRef.refresh()" @closed="drawerShow=false"></save>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,282 @@
|
|||
<template>
|
||||
<el-container class="flow-editor">
|
||||
<left-panel v-if="lf" :lf="lf"></left-panel>
|
||||
<div ref="containerRef" class="flow-container"></div>
|
||||
<div class="right-panel" v-if="activeNode"></div>
|
||||
<menu-panel v-if="lf" :lf="lf" class="menu-panel"/>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted, onUnmounted} from "vue"
|
||||
import LogicFlow from "@logicflow/core"
|
||||
import {MiniMap, Snapshot} from "@logicflow/extension"
|
||||
import "@logicflow/core/lib/style/index.css"
|
||||
import "@logicflow/extension/lib/style/index.css"
|
||||
import leftPanel from "./left.vue"
|
||||
import menuPanel from "./menu.vue"
|
||||
import {StartNodeModel, StartNodeView, START_NODE_TYPES} from "./model/StartNode"
|
||||
import {EventNodeModel, EventNodeView, EVENT_NODE_TYPES} from "./model/EventNode"
|
||||
import {GatewayNodeModel, GatewayNodeView, GATEWAY_NODE_TYPES} from "./model/GatewayNode"
|
||||
import {CatchNodeModel, CatchNodeView, CATCH_NODE_TYPES} from "./model/CatchNode"
|
||||
import {EndNodeModel, EndNodeView, END_NODE_TYPES} from "./model/EndNode"
|
||||
import {CustomLineModel, CustomLine, CUSTOM_LINE} from "./model/CustomLine"
|
||||
import {ElMessageBox} from 'element-plus'
|
||||
import {useI18n} from "vue-i18n"
|
||||
|
||||
const containerRef = ref(HTMLElement | null);
|
||||
const {t} = useI18n()
|
||||
let lf = ref(LogicFlow | null);
|
||||
let activeNode = ref({})
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
window.addEventListener("keydown", handleKeydown);
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("keydown", handleKeydown);
|
||||
})
|
||||
|
||||
function init() {
|
||||
lf.value = new LogicFlow({
|
||||
container: containerRef.value,
|
||||
grid: {
|
||||
size: 20, // 网格间距
|
||||
visible: true, // 显示网格
|
||||
type: "dot", // dot(点) / mesh(格子线)
|
||||
config: {
|
||||
color: "#dcdfe6", // 网格颜色
|
||||
thickness: 1, // 网格粗细
|
||||
}
|
||||
},
|
||||
background: {
|
||||
color: "#f7f8fa"
|
||||
},
|
||||
plugins: [MiniMap, Snapshot],
|
||||
pluginsOptions: {
|
||||
miniMap: {
|
||||
headerTitle: '小地图',
|
||||
isShowHeader: true,
|
||||
showEdge: true,
|
||||
isShowCloseIcon: true,
|
||||
bottomPosition: 10,
|
||||
rightPosition: 10
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/** 注册自定义节点 */
|
||||
registerCustomNodes()
|
||||
/** 注册自定义连线 */
|
||||
registerCustomEdge()
|
||||
|
||||
/** 监听节点点击 */
|
||||
lf.value.on("node:click", ({data}) => {
|
||||
activeNode.value = data
|
||||
})
|
||||
|
||||
lf.value.on("edge:click", ({data}) => {
|
||||
activeNode.value = data
|
||||
})
|
||||
|
||||
lf.value.on("blank:click", () => {
|
||||
activeNode.value = {}
|
||||
});
|
||||
|
||||
// 初始渲染
|
||||
lf.value.render({
|
||||
nodes: [
|
||||
{id: "1", type: "start-basic", x: 200, y: 200, text: "开始节点"},
|
||||
{id: "2", type: "event-approval", x: 400, y: 200, text: "审批节点"},
|
||||
],
|
||||
edges: [
|
||||
{sourceNodeId: "1", targetNodeId: "2", type: CUSTOM_LINE.LINE_TYPE}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
/** 注册自定义节点 */
|
||||
function registerCustomNodes() {
|
||||
if (!lf.value) return;
|
||||
|
||||
// 开始节点
|
||||
Object.values(START_NODE_TYPES).map(i => {
|
||||
lf.value.register({
|
||||
type: i,
|
||||
view: StartNodeView,
|
||||
model: StartNodeModel
|
||||
});
|
||||
})
|
||||
|
||||
// 事件节点
|
||||
Object.values(EVENT_NODE_TYPES).map(i => {
|
||||
lf.value.register({
|
||||
type: i,
|
||||
view: EventNodeView,
|
||||
model: EventNodeModel
|
||||
});
|
||||
})
|
||||
|
||||
// 网关节点
|
||||
Object.values(GATEWAY_NODE_TYPES).map(i => {
|
||||
lf.value.register({
|
||||
type: i,
|
||||
view: GatewayNodeView,
|
||||
model: GatewayNodeModel
|
||||
});
|
||||
})
|
||||
|
||||
// 捕获节点
|
||||
Object.values(CATCH_NODE_TYPES).map(i => {
|
||||
lf.value.register({
|
||||
type: i,
|
||||
view: CatchNodeView,
|
||||
model: CatchNodeModel
|
||||
});
|
||||
})
|
||||
|
||||
// 结束节点
|
||||
Object.values(END_NODE_TYPES).map(i => {
|
||||
lf.value.register({
|
||||
type: i,
|
||||
view: EndNodeView,
|
||||
model: EndNodeModel
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function registerCustomEdge() {
|
||||
if (!lf.value) return;
|
||||
|
||||
lf.value.register({
|
||||
type: CUSTOM_LINE.LINE_TYPE,
|
||||
view: CustomLine,
|
||||
model: CustomLineModel
|
||||
});
|
||||
lf.value.setDefaultEdgeType(CUSTOM_LINE.LINE_TYPE);
|
||||
}
|
||||
|
||||
/** 更新节点文本 */
|
||||
function updateNodeText() {
|
||||
if (!lf.value || !activeNode.value) return;
|
||||
lf.value.updateText(activeNode.value.id, activeNode.value.text.value);
|
||||
}
|
||||
|
||||
/** 更新节点属性 */
|
||||
function updateNodeProps() {
|
||||
if (!lf.value || !activeNode.value) return;
|
||||
lf.value.setProperties(activeNode.value.id, activeNode.value.properties);
|
||||
}
|
||||
|
||||
// 快捷键设置
|
||||
const handleKeydown = (event) => {
|
||||
if (event.key === "Delete" || event.key === "Backspace") {
|
||||
if (Object.keys(activeNode.value).length !== 0) {
|
||||
ElMessageBox.confirm(
|
||||
activeNode.value.type === 'line' ? t('flow.deleteLine') : t('flow.deleteNode'),
|
||||
t('system.warning'),
|
||||
{
|
||||
confirmButtonText: t('system.ok'),
|
||||
cancelButtonText: t('system.cancel'),
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
if (activeNode.value.type === 'line') {
|
||||
lf.value.deleteEdge(activeNode.value.id);
|
||||
} else {
|
||||
lf.value.deleteNode(activeNode.value.id);
|
||||
}
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const directionKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
|
||||
if (directionKeys.includes(event.key)) {
|
||||
// 获取当前选中的所有元素
|
||||
const selectedElements = lf.value.getSelectElements();
|
||||
const selectedNodes = selectedElements.nodes;
|
||||
|
||||
// 如果没有节点被选中,则不执行操作
|
||||
if (selectedNodes.length === 0) return;
|
||||
|
||||
// 根据按键计算移动偏移量
|
||||
let deltaX = 0;
|
||||
let deltaY = 0;
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
deltaY = -1;
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
deltaY = 1;
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
deltaX = -1;
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
deltaX = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// 遍历所有选中的节点进行移动
|
||||
selectedNodes.forEach(node => {
|
||||
const newNodeX = node.x + deltaX;
|
||||
const newNodeY = node.y + deltaY;
|
||||
|
||||
// 获取节点模型并移动
|
||||
const nodeModel = lf.value.getNodeModelById(node.id);
|
||||
if (nodeModel) {
|
||||
nodeModel.moveTo({x: newNodeX, y: newNodeY});
|
||||
}
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flow-editor {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.flow-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: calc(100% - 3px);
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
width: 320px;
|
||||
background: #fff;
|
||||
border-left: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
:deep(.lf-mini-map) {
|
||||
background: #FFF;
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
:deep(.lf-mini-map-header) {
|
||||
background: #f5f5f5;
|
||||
border: 0;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
:deep(.lf-mini-map-close) {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
:deep(.lf-minimap-viewport) {
|
||||
border: 2px solid #409EFF;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<template>
|
||||
<el-aside class="left-panel">
|
||||
<el-collapse v-model="node" accordion>
|
||||
<el-collapse-item title="开始事件" name="start">
|
||||
<div class="panel-item" v-for="item in startList" :key="item.type" @mousedown="startDrag(item)">
|
||||
<el-icon size="16" color="#67C23A">
|
||||
<component :is="item.icon"/>
|
||||
</el-icon>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="活动事件" name="event">
|
||||
<div class="panel-item" v-for="item in eventList" :key="item.type" @mousedown="startDrag(item)">
|
||||
<el-icon size="16" color="#409EFF">
|
||||
<component :is="item.icon"/>
|
||||
</el-icon>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="网关事件" name="gateway">
|
||||
<div class="panel-item" v-for="item in gatewayList" :key="item.type" @mousedown="startDrag(item)">
|
||||
<el-icon size="16" color="#E6A23C">
|
||||
<component :is="item.icon"/>
|
||||
</el-icon>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="捕获事件" name="catch">
|
||||
<div class="panel-item" v-for="item in catchList" :key="item.type" @mousedown="startDrag(item)">
|
||||
<el-icon size="16" color="#FF85C0">
|
||||
<component :is="item.icon"/>
|
||||
</el-icon>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="结束事件" name="end">
|
||||
<div class="panel-item" v-for="item in endList" :key="item.type" @mousedown="startDrag(item)">
|
||||
<el-icon size="16" color="#F56C6C">
|
||||
<component :is="item.icon"/>
|
||||
</el-icon>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {reactive, ref} from "vue";
|
||||
import LogicFlow from "@logicflow/core";
|
||||
import {START_NODE_TYPES} from "./model/StartNode"
|
||||
import {EVENT_NODE_TYPES} from "./model/EventNode"
|
||||
import {GATEWAY_NODE_TYPES} from "./model/GatewayNode"
|
||||
import {CATCH_NODE_TYPES} from "./model/CatchNode"
|
||||
import {END_NODE_TYPES} from "./model/EndNode"
|
||||
|
||||
interface Node {
|
||||
type: string,
|
||||
label: string,
|
||||
icon: string
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
lf: {type: LogicFlow}
|
||||
})
|
||||
|
||||
const node = ref('start')
|
||||
|
||||
const startList = reactive<Node[]>([
|
||||
{type: START_NODE_TYPES.BASIC, label: "开始节点", icon: "el-icon-video-play"},
|
||||
{type: START_NODE_TYPES.TIMER, label: "定时节点", icon: "el-icon-clock"},
|
||||
{type: START_NODE_TYPES.MESSAGE, label: "消息节点", icon: "pi-icon-message"},
|
||||
{type: START_NODE_TYPES.COMMAND, label: "指令节点", icon: "pi-icon-command"}
|
||||
])
|
||||
const eventList = reactive<Node[]>([
|
||||
{type: EVENT_NODE_TYPES.APPROVAL, label: "审批节点", icon: "pi-icon-approval"},
|
||||
{type: EVENT_NODE_TYPES.SCRIPT, label: "脚本节点", icon: "pi-icon-script"},
|
||||
{type: EVENT_NODE_TYPES.CUSTOM, label: "自定义节点", icon: "pi-icon-custom"},
|
||||
{type: EVENT_NODE_TYPES.EMAIL, label: "邮件节点", icon: "el-icon-message"},
|
||||
{type: EVENT_NODE_TYPES.ACCEPT, label: "接收节点", icon: "pi-icon-accept"}
|
||||
])
|
||||
const gatewayList = reactive<Node[]>([
|
||||
{type: GATEWAY_NODE_TYPES.EXCLUSIVE, label: "排他节点", icon: "pi-icon-exclusive"},
|
||||
{type: GATEWAY_NODE_TYPES.INCLUSIVE, label: "并行网关", icon: "pi-icon-inclusive"},
|
||||
{type: GATEWAY_NODE_TYPES.PARALLEL, label: "包容网关", icon: "pi-icon-parallel"}
|
||||
])
|
||||
const catchList = reactive<Node[]>([
|
||||
{type: CATCH_NODE_TYPES.TIMER, label: "定时节点", icon: "el-icon-clock"},
|
||||
{type: CATCH_NODE_TYPES.MESSAGE, label: "消息节点", icon: "pi-icon-message"},
|
||||
{type: CATCH_NODE_TYPES.COMMAND, label: "指令节点", icon: "pi-icon-command"}
|
||||
])
|
||||
const endList = reactive<Node[]>([
|
||||
{type: END_NODE_TYPES.CLOSE, label: "结束节点", icon: "pi-icon-end"}
|
||||
])
|
||||
|
||||
/** 提供拖拽到画布功能 */
|
||||
function startDrag(item: Node) {
|
||||
props.lf.dnd.startDrag({type: item.type, text: item.label});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.left-panel {
|
||||
width: 130px;
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
user-select: none;
|
||||
|
||||
.panel-item {
|
||||
padding: 8px;
|
||||
background: #eef2ff;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
cursor: grab;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
:deep(.el-collapse) {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:deep(.el-collapse-item__content) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<div class="menu-panel">
|
||||
<el-icon size="18" title="放大" @click="lf.zoom(true)">
|
||||
<component :is="'el-icon-zoom-in'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="缩小" @click="lf.zoom(false)">
|
||||
<component :is="'el-icon-zoom-out'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="大小还原" @click="lf.resetZoom()">
|
||||
<component :is="'el-icon-refresh-left'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="居中" @click="lf.translateCenter()">
|
||||
<component :is="'el-icon-aim'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="位置还原" @click="lf.resetTranslate()">
|
||||
<component :is="'el-icon-position'"/>
|
||||
</el-icon>
|
||||
<el-icon :class="{disabled: !canUndo}" size="18" title="上一步" @click="canUndo && lf.undo()">
|
||||
<component :is="'el-icon-back'"/>
|
||||
</el-icon>
|
||||
<el-icon :class="{disabled: !canRedo}" size="18" title="下一步" @click="canRedo && lf.redo()">
|
||||
<component :is="'el-icon-right'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="删除" @click="remove">
|
||||
<component :is="'el-icon-delete'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="小地图" @click="map">
|
||||
<component :is="'el-icon-map-location'"/>
|
||||
</el-icon>
|
||||
<el-icon size="18" title="下载图片" @click="download">
|
||||
<component :is="'el-icon-download'"/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {onMounted, onUnmounted, ref} from "vue";
|
||||
import LogicFlow from "@logicflow/core";
|
||||
import {ElMessageBox} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const props = defineProps({
|
||||
lf: {type: LogicFlow}
|
||||
})
|
||||
const {t} = useI18n()
|
||||
|
||||
let canUndo = ref(false)
|
||||
let canRedo = ref(false)
|
||||
|
||||
const updateHistoryButtons = () => {
|
||||
// 直接从 lf.history 读取最新长度
|
||||
canUndo.value = props.lf.history.undos.length > 0;
|
||||
canRedo.value = props.lf.history.redos.length > 0;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (props.lf) {
|
||||
props.lf.on('history:change', updateHistoryButtons)
|
||||
// 初始化一次状态
|
||||
updateHistoryButtons()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 记得移除监听器
|
||||
props.lf?.off('history:change', updateHistoryButtons)
|
||||
})
|
||||
|
||||
function remove() {
|
||||
// 在你的Vue组件或事件回调中
|
||||
const selectedElements = props.lf.getSelectElements()
|
||||
// 提取选中的节点
|
||||
const selectedNodes = selectedElements.nodes
|
||||
if (selectedNodes.length > 0) {
|
||||
ElMessageBox.confirm(t('flow.deleteNode'), t('system.warning'), {
|
||||
confirmButtonText: t('system.ok'), cancelButtonText: t('system.cancel'), type: 'warning'
|
||||
}).then(() => {
|
||||
props.lf.deleteNode(selectedNodes[0].id)
|
||||
}).catch(() => {
|
||||
})
|
||||
return
|
||||
}
|
||||
// 提取选中的连线
|
||||
const selectedEdges = selectedElements.edges
|
||||
if (selectedEdges.length > 0) {
|
||||
ElMessageBox.confirm(t('flow.deleteLine'), t('system.warning'), {
|
||||
confirmButtonText: t('system.ok'), cancelButtonText: t('system.cancel'), type: 'warning'
|
||||
}).then(() => {
|
||||
props.lf.deleteEdge(selectedEdges[0].id)
|
||||
}).catch(() => {
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function map() {
|
||||
const miniMap = props.lf.extension.miniMap as any
|
||||
if (miniMap.isShow) {
|
||||
miniMap.hide()
|
||||
} else {
|
||||
miniMap.show()
|
||||
}
|
||||
}
|
||||
|
||||
function download() {
|
||||
props.lf.getSnapshot("下载-" + (Date.now()), {backgroundColor: "#FFFFFF"})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-panel {
|
||||
background: rgb(255, 255, 255);
|
||||
top: 10px;
|
||||
right: 330px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
padding: 10px;
|
||||
box-shadow: 3px 0 10px 1px #e4e0db;
|
||||
gap: 10px;
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import {RectNodeModel, RectNode, h} from "@logicflow/core"
|
||||
|
||||
export const CATCH_NODE_TYPES = {
|
||||
TIMER: 'catch-timer',
|
||||
MESSAGE: 'catch-message',
|
||||
COMMAND: 'catch-command'
|
||||
};
|
||||
|
||||
export class CatchNodeModel extends RectNodeModel {
|
||||
initNodeData(data) {
|
||||
super.initNodeData(data)
|
||||
// 默认尺寸
|
||||
this.width = data.width || 40
|
||||
this.height = data.height || 40
|
||||
// 禁止编辑
|
||||
this.text.editable = false
|
||||
this.text.draggable = false
|
||||
}
|
||||
|
||||
getTextStyle() {
|
||||
return {
|
||||
...super.getTextStyle(),
|
||||
display: 'none'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class CatchNodeView extends RectNode {
|
||||
getShape() {
|
||||
const {model} = this.props;
|
||||
const {x, y, width, height, type} = model;
|
||||
|
||||
let iconPaths: string[] = [];
|
||||
switch (type) {
|
||||
case CATCH_NODE_TYPES.TIMER:
|
||||
iconPaths = ['M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896', 'M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32', 'M500.641792 243.539968h-44.91264v322.17088h322.17088v-44.91264h-277.25824z']
|
||||
break;
|
||||
case CATCH_NODE_TYPES.MESSAGE:
|
||||
iconPaths = ['M529.222243 943.53334c-247.171426 0-448.25314-201.081715-448.25314-448.241884 0-247.171426 201.081715-448.25314 448.25314-448.25314s448.25314 201.081715 448.25314 448.25314C977.475384 742.451626 776.393669 943.53334 529.222243 943.53334zM529.222243 80.927147c-228.483808 0-414.364309 185.880501-414.364309 414.364309 0 228.472552 185.880501 414.353053 414.364309 414.353053S943.586552 723.764008 943.586552 495.291456C943.586552 266.807648 757.706051 80.927147 529.222243 80.927147z', 'M770.723529 539.980261c-24.644283 0-44.677549-20.044522-44.677549-44.688805s20.033265-44.699038 44.677549-44.699038 44.699038 20.054755 44.699038 44.699038S795.367813 539.980261 770.723529 539.980261z', 'M529.046235 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S553.690518 539.980261 529.046235 539.980261z', 'M295.068296 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S319.712579 539.980261 295.068296 539.980261z'];
|
||||
break;
|
||||
case CATCH_NODE_TYPES.COMMAND:
|
||||
iconPaths = ['M512 0C229.218 0 0 229.218 0 512s229.218 512 512 512 512-229.218 512-512S794.782 0 512 0z m0 944c-238.594 0-432-193.406-432-432S273.406 80 512 80s432 193.406 432 432-193.406 432-432 432z', 'M512 672.312c-17.656 0-32 14.282-32 31.968s14.344 32.032 32 32.032 32-14.344 32-32.032-14.344-31.968-32-31.968zM512 544.062c-46.25 0-87.124 21.25-114.718 54.094l29.094 38.782c18.594-27.468 49.968-45.5 85.624-45.5s67.032 18.032 85.594 45.5l29.156-38.782c-27.656-32.844-68.5-54.094-114.75-54.094zM326.062 491.656l28.75 38.156c39.812-41 95.468-66.562 157.188-66.562 61.688 0 117.282 25.562 157.218 66.562l28.656-38.188c-48.062-46.812-113.562-75.75-185.876-75.75-72.374 0.002-137.874 28.938-185.936 75.782z', 'M256 387.188l31.124 41.5c59.124-54.844 137.968-88.656 224.876-88.656s165.75 33.812 224.812 88.656L768 387.124c-67.844-61.188-157.468-98.782-256-98.782-98.562 0.002-188.124 37.596-256 98.846z'];
|
||||
break;
|
||||
}
|
||||
// 图标缩放比例
|
||||
const iconScale = 0.025;
|
||||
|
||||
return h('g', {},
|
||||
// 方形
|
||||
h('rect', {
|
||||
x: x - width / 2,
|
||||
y: y - height / 2,
|
||||
width,
|
||||
height,
|
||||
fill: '#FDAED5',
|
||||
stroke: '#FF85C0',
|
||||
strokeWidth: 2,
|
||||
rx: 10,
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 1
|
||||
}),
|
||||
|
||||
...iconPaths.map(d => h("path", {
|
||||
d,
|
||||
fill: '#FF85C0',
|
||||
transform: `translate(${x}, ${y}) scale(${iconScale}) translate(-512,-512)`
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import {PolylineEdgeModel, PolylineEdge, h} from '@logicflow/core';
|
||||
|
||||
export const CUSTOM_LINE = {
|
||||
LINE_TYPE: 'line'
|
||||
};
|
||||
|
||||
// 自定义连线模型
|
||||
export class CustomLineModel extends PolylineEdgeModel {
|
||||
initEdgeData(data) {
|
||||
super.initEdgeData(data);
|
||||
|
||||
// 禁止编辑标签
|
||||
this.text.editable = false;
|
||||
this.text.draggable = false;
|
||||
}
|
||||
|
||||
getEdgeStyle() {
|
||||
const style = super.getEdgeStyle();
|
||||
const {isSelected} = this;
|
||||
|
||||
if (isSelected) {
|
||||
style.strokeWidth = 3
|
||||
style.stroke = "#909399"
|
||||
} else {
|
||||
style.strokeWidth = 2
|
||||
style.stroke = "#B1B3B8"
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
setAttributes() {
|
||||
this.isAnimation = true
|
||||
}
|
||||
|
||||
getEdgeAnimationStyle() {
|
||||
const style = super.getEdgeAnimationStyle()
|
||||
style.strokeDasharray = '15 5'
|
||||
style.animationDuration = '10s'
|
||||
style.stroke = '#B1B3B8'
|
||||
return style
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomLine extends PolylineEdge {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import {CircleNodeModel, CircleNode, h} from "@logicflow/core"
|
||||
|
||||
export const END_NODE_TYPES = {
|
||||
CLOSE: 'end-close'
|
||||
};
|
||||
|
||||
export class EndNodeModel extends CircleNodeModel {
|
||||
initNodeData(data) {
|
||||
super.initNodeData(data);
|
||||
this.r = data.r || 20;
|
||||
// 禁止编辑
|
||||
this.text.editable = false;
|
||||
this.text.draggable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认锚点:去掉右侧
|
||||
*/
|
||||
getDefaultAnchor() {
|
||||
const anchors = super.getDefaultAnchor();
|
||||
return anchors.filter(a => {
|
||||
return a.x <= this.x;
|
||||
});
|
||||
}
|
||||
|
||||
getTextStyle() {
|
||||
return {
|
||||
...super.getTextStyle(),
|
||||
display: 'none'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class EndNodeView extends CircleNode {
|
||||
getShape() {
|
||||
const {model} = this.props
|
||||
const {x, y, r, type} = model
|
||||
|
||||
let iconPaths: string[] = [];
|
||||
switch (type) {
|
||||
case END_NODE_TYPES.CLOSE:
|
||||
iconPaths = ['M678.528 642.304c0 17.6-14.4 32-32 32h-268.992a32 32 0 0 1-32-32V381.696a32 32 0 0 1 32-32h268.992c17.6 0 32 14.4 32 32v260.608z']; // 三角形
|
||||
break;
|
||||
}
|
||||
|
||||
return h('g', {},
|
||||
// 外圆
|
||||
h('circle', {
|
||||
cx: x,
|
||||
cy: y,
|
||||
r,
|
||||
fill: '#F89898',
|
||||
stroke: '#F56C6C',
|
||||
strokeWidth: 2,
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 1
|
||||
}),
|
||||
...iconPaths.map(d => h("path", {
|
||||
d,
|
||||
fill: '#F56C6C',
|
||||
transform: `translate(${x}, ${y}) scale(0.03) translate(-512, -512)`
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import {RectNodeModel, RectNode, h} from "@logicflow/core"
|
||||
|
||||
export const EVENT_NODE_TYPES = {
|
||||
APPROVAL: 'event-approval',
|
||||
SCRIPT: 'event-script',
|
||||
CUSTOM: 'event-custom',
|
||||
EMAIL: 'event-email',
|
||||
ACCEPT: 'event-accept'
|
||||
};
|
||||
|
||||
export class EventNodeModel extends RectNodeModel {
|
||||
initNodeData(data) {
|
||||
super.initNodeData(data);
|
||||
// 默认尺寸
|
||||
this.width = data.width || 120;
|
||||
this.height = data.height || 50;
|
||||
// 禁止编辑
|
||||
this.text.editable = false;
|
||||
this.text.draggable = false;
|
||||
}
|
||||
|
||||
getTextStyle() {
|
||||
return {
|
||||
...super.getTextStyle(),
|
||||
display: 'none'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class EventNodeView extends RectNode {
|
||||
getShape() {
|
||||
const {model} = this.props
|
||||
const {x, y, width, height, type, text} = model
|
||||
|
||||
let iconPaths: string[] = [];
|
||||
switch (type) {
|
||||
case EVENT_NODE_TYPES.APPROVAL:
|
||||
iconPaths = ['M896 928H128c-17.6 0-32-14.4-32-32s14.4-32 32-32h768c17.6 0 32 14.4 32 32s-14.4 32-32 32z m0-128H128c-17.6 0-32-14.4-32-32V608c0-52.8 43.2-96 96-96h204.8c-6.4-38.4-25.6-75.2-52.8-107.2-36.8-41.6-56-94.4-56-148.8 0-60.8 24-118.4 68.8-161.6 44.8-43.2 102.4-64 164.8-62.4C636.8 36.8 734.4 136 736 251.2c1.6 57.6-20.8 113.6-59.2 156.8-27.2 28.8-43.2 64-49.6 104H832c52.8 0 96 43.2 96 96v160c0 17.6-14.4 32-32 32z m-736-64h704V608c0-17.6-14.4-32-32-32H592c-17.6 0-32-14.4-32-32 0-67.2 24-131.2 68.8-179.2 28.8-30.4 43.2-70.4 43.2-112-1.6-83.2-70.4-153.6-153.6-156.8-44.8-1.6-86.4 14.4-116.8 44.8-32 30.4-49.6 72-49.6 115.2 0 38.4 14.4 76.8 40 105.6 46.4 52.8 72 116.8 72 182.4 0 17.6-14.4 32-32 32H192c-17.6 0-32 14.4-32 32v128z']; // 三角形
|
||||
break;
|
||||
case EVENT_NODE_TYPES.SCRIPT:
|
||||
iconPaths = ['M934 271c0-90-73-163-163-163H292.3c-66.5 0-118.8 56.7-113.5 122.9L221.1 704H91l-1 54c0 84.6 66.4 153.6 150 157.8v0.2h424.3c98.2 0 177.7-79.6 177.7-177.7L795.8 328H934v-57zM171.6 834.4c-20.3-20.3-31.5-47.3-31.6-76l0.1-4.4h85.4l9.9 111.3c-24-2.8-46.3-13.5-63.8-30.9zM792 740.9c-0.7 33.2-13.9 64.2-37.4 87.7-24.1 24.1-56.2 37.4-90.3 37.4H285.7l-57.1-639.3c-1.4-17.9 4.6-35 16.8-48.2 12.2-13.2 28.9-20.5 46.9-20.5h19c23.4 26.3 37.7 61 37.7 99 0 25.7-6.5 49.9-18 71h414.4L792 740.9zM884 278H397.9c0.7-7 1.1-14 1.1-21 0-36-9.4-69.8-26-99h398c30.2 0 58.6 11.8 79.9 33.1S884 240.8 884 271v7zM664.5 515h-297v-50h297v50z m0 123.2h-297v-50h297v50z'];
|
||||
break;
|
||||
case EVENT_NODE_TYPES.CUSTOM:
|
||||
iconPaths = ['M811.008 768.170667v106.666666a106.666667 106.666667 0 0 1-106.666667 106.666667h-128a21.248 21.248 0 0 1-21.333333-21.333333V938.666667c0-75.52-43.306667-127.872-128.341333-127.872-84.224 0-128.085333 52.821333-128.085334 127.872v21.461333a21.333333 21.333333 0 0 1-21.333333 21.333333h-128a106.666667 106.666667 0 0 1-106.666667-106.709333l0.426667-128a21.333333 21.333333 0 0 1 21.333333-21.248h42.666667c58.752 0 106.410667-55.210667 106.410667-128 0-73.386667-47.36-128-106.410667-128H64.213333a21.333333 21.333333 0 0 1-21.333333-21.333333v-128a106.666667 106.666667 0 0 1 106.666667-106.666667h106.368V213.333333c0-97.066667 61.013333-170.538667 170.752-170.538666 107.008 0 171.392 75.434667 171.392 170.538666v0.128h106.837333a106.666667 106.666667 0 0 1 106.666667 106.666667v106.666667h20.778666c84.053333 0 149.077333 75.008 149.077334 170.666666 0 95.104-65.28 170.666667-149.077334 170.666667h-21.333333z m-42.666667-20.736v-0.597334a21.333333 21.333333 0 0 1 21.333334-21.333333h42.666666c58.752 0 106.410667-55.210667 106.410667-128 0-73.386667-47.36-128-106.410667-128h-42.666666a21.333333 21.333333 0 0 1-20.778667-26.325333V320.128a64 64 0 0 0-64-64h-126.890667a21.76 21.76 0 0 1-1.28 0 21.333333 21.333333 0 0 1-21.333333-21.333333V213.333333c0-72.917333-46.933333-127.872-128.725333-127.872-84.224 0-128.085333 52.821333-128.085334 127.872v21.461334a21.248 21.248 0 0 1-21.333333 21.333333H149.546667a64 64 0 0 0-64 64v106.666667h21.461333c84.053333 0 149.077333 75.008 149.077333 170.666666 0 95.104-65.28 170.666667-149.077333 170.666667h-21.418667l-0.341333 106.666667a64 64 0 0 0 64 64h106.666667V938.666667c0-97.066667 61.013333-170.538667 170.752-170.538667 110.592 0 171.008 73.002667 171.008 170.538667v0.170666h106.666666a64 64 0 0 0 64-64v-127.402666z'];
|
||||
break;
|
||||
case EVENT_NODE_TYPES.EMAIL:
|
||||
iconPaths = ['M128 224v512a64 64 0 0 0 64 64h640a64 64 0 0 0 64-64V224zm0-64h768a64 64 0 0 1 64 64v512a128 128 0 0 1-128 128H192A128 128 0 0 1 64 736V224a64 64 0 0 1 64-64', 'M904 224 656.512 506.88a192 192 0 0 1-289.024 0L120 224zm-698.944 0 210.56 240.704a128 128 0 0 0 192.704 0L818.944 224z'];
|
||||
break;
|
||||
case EVENT_NODE_TYPES.ACCEPT:
|
||||
iconPaths = ['M960 317.03h-65.41V714.8c0 30.93-25.07 56-56 56H185.41c-30.93 0-56-25.07-56-56V317.03H64v521.16c0 30.93 25.07 56 56 56h784c30.93 0 56-25.07 56-56V317.03zM404.37 129.81h215.25v72.74H404.37z', 'M621.6 501V249.08H406.34V501H302.78L512 710.22 721.22 501z'];
|
||||
break;
|
||||
}
|
||||
|
||||
// 图标缩放比例
|
||||
const iconScale = 0.015;
|
||||
|
||||
// 图标在矩形左上角偏移
|
||||
const iconOffsetX = -width/2 + 16; // 左边距16px
|
||||
const iconOffsetY = -height/2 + 16; // 上边距16px
|
||||
|
||||
return h('g', {},
|
||||
// 矩形
|
||||
h('rect', {
|
||||
x: x - width / 2,
|
||||
y: y - height / 2,
|
||||
width,
|
||||
height,
|
||||
fill: '#79BBFF',
|
||||
stroke: '#409EFF',
|
||||
strokeWidth: 2,
|
||||
rx: 10,
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 1
|
||||
}),
|
||||
|
||||
// 图标左上角
|
||||
...iconPaths.map(d => h('path', {
|
||||
d,
|
||||
fill: '#409EFF',
|
||||
transform: `translate(${x + iconOffsetX}, ${y + iconOffsetY}) scale(${iconScale}) translate(-512,-512)`
|
||||
})),
|
||||
|
||||
// 文字居中
|
||||
h('text', {
|
||||
x,
|
||||
y,
|
||||
textAnchor: 'middle',
|
||||
dominantBaseline: 'middle',
|
||||
fontSize: 14,
|
||||
fill: '#333'
|
||||
}, text.value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import {BaseNodeModel, BaseNode, h} from "@logicflow/core"
|
||||
|
||||
export const GATEWAY_NODE_TYPES = {
|
||||
EXCLUSIVE: 'gateway-exclusive',
|
||||
PARALLEL: 'gateway-parallel',
|
||||
INCLUSIVE: 'gateway-inclusive'
|
||||
};
|
||||
|
||||
export class GatewayNodeModel extends BaseNodeModel {
|
||||
initNodeData(data) {
|
||||
super.initNodeData(data)
|
||||
// 默认尺寸
|
||||
this.width = data.width || 50
|
||||
this.height = data.height || 50
|
||||
// 禁止编辑
|
||||
this.text.editable = false
|
||||
this.text.draggable = false
|
||||
this.allowOutgoing = true
|
||||
this.allowIncoming = true
|
||||
|
||||
this.ports = [
|
||||
{ id: 'top', type: 'inout', position: { x: 0.5, y: 0 } },
|
||||
{ id: 'right', type: 'inout', position: { x: 1, y: 0.5 } },
|
||||
{ id: 'bottom', type: 'inout', position: { x: 0.5, y: 1 } },
|
||||
{ id: 'left', type: 'inout', position: { x: 0, y: 0.5 } }
|
||||
];
|
||||
}
|
||||
|
||||
getTextStyle() {
|
||||
return {
|
||||
...super.getTextStyle(),
|
||||
display: 'none'
|
||||
};
|
||||
}
|
||||
|
||||
// 返回默认锚点(四个顶点)
|
||||
getDefaultAnchor() {
|
||||
const { x, y, width, height } = this;
|
||||
return this.ports.map(port => ({
|
||||
id: port.id,
|
||||
x: x + (port.position.x - 0.5) * width,
|
||||
y: y + (port.position.y - 0.5) * height
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class GatewayNodeView extends BaseNode {
|
||||
getShape() {
|
||||
const {model} = this.props;
|
||||
const {x, y, width, height, type} = model;
|
||||
|
||||
// 四个顶点
|
||||
const points = [
|
||||
[x, y - height / 2], // 上
|
||||
[x + width / 2, y], // 右
|
||||
[x, y + height / 2], // 下
|
||||
[x - width / 2, y] // 左
|
||||
];
|
||||
|
||||
// 拼接 path 字符串
|
||||
const pathD = `M ${points.map(p => p.join(',')).join(' L ')} Z`;
|
||||
let iconPaths: string[] = [];
|
||||
|
||||
switch (type) {
|
||||
case GATEWAY_NODE_TYPES.EXCLUSIVE:
|
||||
iconPaths = ['M764.288 214.592 512 466.88 259.712 214.592a31.936 31.936 0 0 0-45.12 45.12L466.752 512 214.528 764.224a31.936 31.936 0 1 0 45.12 45.184L512 557.184l252.288 252.288a31.936 31.936 0 0 0 45.12-45.12L557.12 512.064l252.288-252.352a31.936 31.936 0 1 0-45.12-45.184z'];
|
||||
break;
|
||||
case GATEWAY_NODE_TYPES.PARALLEL:
|
||||
iconPaths = ['M512.00337692 223.62507194c-39.07811828 0-76.40824868 7.54812851-112.02349786 22.7966725-35.61524846 15.24854397-66.28448731 35.85361048-92.03419966 61.53711098-25.75633368 25.82254479-46.28194643 56.45205638-61.51062641 92.02757833-15.26178662 35.70794488-22.88274757 72.93213694-22.88274757 112.07646705 0 39.01190645 7.62096168 76.36852217 22.88274757 111.94404411 15.22868071 35.71456621 35.75429346 66.3440778 61.51062641 92.1666226 25.74971235 25.69012185 56.41895047 46.14952278 92.03419966 61.53049039a284.03475437 284.03475437 0 0 0 112.02349786 22.80329382c39.06487635 0 76.39500676-7.69379412 112.01025522-22.80329382 35.61524846-15.38096763 66.28448731-35.84698987 92.03419965-61.5304904 25.75633368-25.82254479 46.28194643-56.45205638 61.51062642-92.16662258 15.28827122-35.57552195 22.88274757-72.93213694 22.88274758-111.94404412 0-39.1443301-7.5944771-76.36852217-22.88274758-112.07646704-15.22868071-35.57552195-35.75429346-66.21165414-61.51062642-92.03419894-25.74971235-25.67687918-56.41895047-46.28194643-92.03419965-61.53049038C588.39838368 231.17982179 551.06163194 223.62507194 511.99675559 223.62507194m0-82.41364616c50.20167629 0 98.25809517 9.75297643 144.02359033 29.39797427 45.79860107 19.63837652 85.22764104 46.0104785 118.27387798 79.10968462 33.07272152 32.96678243 59.41833818 72.38920181 79.03023011 118.2606353 19.61851326 45.73901058 29.43770153 93.81529271 29.45094418 143.94413656 0.03972724 50.27450871-9.81918826 98.35079085-29.45094418 144.08980216-19.62513458 45.87143423-45.97075126 85.29385288-79.03023011 118.254014-33.03299426 33.10582743-72.43554966 59.47792868-118.27387797 79.12292725C610.19526027 872.88993219 562.19181056 882.78195289 512.00337692 882.78195289c-50.18843363 0-98.19188333-9.89202143-144.02359031-29.39797427-45.85157025-19.63837652-85.26736828-46.0104785-118.28712063-79.1096846C216.62656579 741.30751156 190.28757045 701.8850922 170.66243587 656.00703736 151.03068066 610.27464813 141.17176516 562.19836599 141.21149168 511.93047787c0.01324266-50.13546446 9.83243092-98.21174661 29.45094419-143.94413656 19.61189194-45.88467617 45.950888-85.3004742 79.03023011-118.26725664 33.0396156-33.10582743 72.47527689-59.47130809 118.28712063-79.11630594C413.73866043 150.96440221 461.78845799 141.21142578 511.99675559 141.21142578'];
|
||||
break;
|
||||
case GATEWAY_NODE_TYPES.INCLUSIVE:
|
||||
iconPaths = ['M480 480V128a32 32 0 0 1 64 0v352h352a32 32 0 1 1 0 64H544v352a32 32 0 1 1-64 0V544H128a32 32 0 0 1 0-64z'];
|
||||
break;
|
||||
}
|
||||
|
||||
return h('g', {},
|
||||
// 菱形
|
||||
h('path', {
|
||||
d: pathD,
|
||||
fill: '#EEBE77',
|
||||
stroke: '#E6A23C',
|
||||
strokeWidth: 2,
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 1
|
||||
}),
|
||||
|
||||
...iconPaths.map(d => h("path", {
|
||||
d,
|
||||
fill: '#E6A23C',
|
||||
transform: `translate(${x}, ${y}) scale(0.03) translate(-512, -512)`
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
import {CircleNodeModel, CircleNode, h} from "@logicflow/core"
|
||||
|
||||
export const START_NODE_TYPES = {
|
||||
BASIC: 'start-basic',
|
||||
TIMER: 'start-timer',
|
||||
MESSAGE: 'start-message',
|
||||
COMMAND: 'start-command'
|
||||
};
|
||||
|
||||
export class StartNodeModel extends CircleNodeModel {
|
||||
initNodeData(data) {
|
||||
super.initNodeData(data);
|
||||
this.r = data.r || 20;
|
||||
// 禁止编辑
|
||||
this.text.editable = false;
|
||||
this.text.draggable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认锚点:去掉左侧
|
||||
*/
|
||||
getDefaultAnchor() {
|
||||
const anchors = super.getDefaultAnchor();
|
||||
return anchors.filter(a => {
|
||||
return a.x >= this.x;
|
||||
});
|
||||
}
|
||||
|
||||
getTextStyle() {
|
||||
return {
|
||||
...super.getTextStyle(),
|
||||
display: 'none'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class StartNodeView extends CircleNode {
|
||||
getShape() {
|
||||
const {model} = this.props
|
||||
const {x, y, r, type} = model
|
||||
|
||||
let iconPaths: string[] = [];
|
||||
switch (type) {
|
||||
case START_NODE_TYPES.BASIC:
|
||||
iconPaths = ['M334.456 840.52a30.112 30.112 0 0 1-30.104-30.104V196.032c0-11.408 6.44-21.816 16.64-26.928a30.048 30.048 0 0 1 31.512 2.848l409.616 307.176a30.104 30.104 0 0 1 0 48.16l-409.616 307.2a29.888 29.888 0 0 1-18.048 6.032zM364.56 256.24v493.976l329.296-247L364.56 256.24z']; // 三角形
|
||||
break;
|
||||
case START_NODE_TYPES.TIMER:
|
||||
iconPaths = ['M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32', 'M500.641792 243.539968h-44.91264v322.17088h322.17088v-44.91264h-277.25824z'];
|
||||
break;
|
||||
case START_NODE_TYPES.MESSAGE:
|
||||
iconPaths = ['M770.723529 539.980261c-24.644283 0-44.677549-20.044522-44.677549-44.688805s20.033265-44.699038 44.677549-44.699038 44.699038 20.054755 44.699038 44.699038S795.367813 539.980261 770.723529 539.980261z', 'M529.046235 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S553.690518 539.980261 529.046235 539.980261z', 'M295.068296 539.980261c-24.644283 0-44.699038-20.044522-44.699038-44.688805s20.054755-44.699038 44.699038-44.699038 44.677549 20.054755 44.677549 44.699038S319.712579 539.980261 295.068296 539.980261z'];
|
||||
break;
|
||||
case START_NODE_TYPES.COMMAND:
|
||||
iconPaths = ['M512 672.312c-17.656 0-32 14.282-32 31.968s14.344 32.032 32 32.032 32-14.344 32-32.032-14.344-31.968-32-31.968zM512 544.062c-46.25 0-87.124 21.25-114.718 54.094l29.094 38.782c18.594-27.468 49.968-45.5 85.624-45.5s67.032 18.032 85.594 45.5l29.156-38.782c-27.656-32.844-68.5-54.094-114.75-54.094zM326.062 491.656l28.75 38.156c39.812-41 95.468-66.562 157.188-66.562 61.688 0 117.282 25.562 157.218 66.562l28.656-38.188c-48.062-46.812-113.562-75.75-185.876-75.75-72.374 0.002-137.874 28.938-185.936 75.782z', 'M256 387.188l31.124 41.5c59.124-54.844 137.968-88.656 224.876-88.656s165.75 33.812 224.812 88.656L768 387.124c-67.844-61.188-157.468-98.782-256-98.782-98.562 0.002-188.124 37.596-256 98.846z'];
|
||||
break;
|
||||
}
|
||||
|
||||
return h('g', {},
|
||||
// 外圆
|
||||
h('circle', {
|
||||
cx: x,
|
||||
cy: y,
|
||||
r,
|
||||
fill: '#4caf50',
|
||||
stroke: '#67C23A',
|
||||
strokeWidth: 2,
|
||||
fillOpacity: 0.3,
|
||||
strokeOpacity: 1
|
||||
}),
|
||||
...iconPaths.map(d => h("path", {
|
||||
d,
|
||||
fill: '#67C23A',
|
||||
transform: `translate(${x}, ${y}) scale(0.03) translate(-512, -512)`
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue