From e33a185c03c38f2ccaf8298f2624bccdea272845 Mon Sep 17 00:00:00 2001 From: zhang zhuo Date: Tue, 9 Dec 2025 18:00:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E7=A8=8B=E8=AE=BE=E8=AE=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- package.json | 2 + src/assets/icons/Accept.vue | 3 + src/assets/icons/Approval.vue | 3 + src/assets/icons/Command.vue | 3 + src/assets/icons/Custom.vue | 3 + src/assets/icons/End.vue | 3 + src/assets/icons/Exclusive.vue | 3 + src/assets/icons/Flow.vue | 3 + src/assets/icons/Inclusive.vue | 3 + src/assets/icons/Message.vue | 3 + src/assets/icons/Parallel.vue | 3 + src/assets/icons/Script.vue | 3 + src/layout/components/NavMenu.vue | 16 +- src/layout/components/search.vue | 27 ++- src/layout/components/setting.vue | 28 +-- src/layout/components/tags.vue | 12 +- src/layout/components/topbar.vue | 7 +- src/layout/index.vue | 3 +- src/router/index.ts | 11 +- src/views/system/login/index.vue | 6 +- src/views/system/translation/index.vue | 2 +- src/views/tools/flow/index.vue | 282 ++++++++++++++++++++++ src/views/tools/flow/left.vue | 133 ++++++++++ src/views/tools/flow/menu.vue | 132 ++++++++++ src/views/tools/flow/model/CatchNode.ts | 70 ++++++ src/views/tools/flow/model/CustomLine.ts | 47 ++++ src/views/tools/flow/model/EndNode.ts | 65 +++++ src/views/tools/flow/model/EventNode.ts | 94 ++++++++ src/views/tools/flow/model/GatewayNode.ts | 94 ++++++++ src/views/tools/flow/model/StartNode.ts | 77 ++++++ 31 files changed, 1091 insertions(+), 52 deletions(-) create mode 100644 src/assets/icons/Accept.vue create mode 100644 src/assets/icons/Approval.vue create mode 100644 src/assets/icons/Command.vue create mode 100644 src/assets/icons/Custom.vue create mode 100644 src/assets/icons/End.vue create mode 100644 src/assets/icons/Exclusive.vue create mode 100644 src/assets/icons/Flow.vue create mode 100644 src/assets/icons/Inclusive.vue create mode 100644 src/assets/icons/Message.vue create mode 100644 src/assets/icons/Parallel.vue create mode 100644 src/assets/icons/Script.vue create mode 100644 src/views/tools/flow/index.vue create mode 100644 src/views/tools/flow/left.vue create mode 100644 src/views/tools/flow/menu.vue create mode 100644 src/views/tools/flow/model/CatchNode.ts create mode 100644 src/views/tools/flow/model/CustomLine.ts create mode 100644 src/views/tools/flow/model/EndNode.ts create mode 100644 src/views/tools/flow/model/EventNode.ts create mode 100644 src/views/tools/flow/model/GatewayNode.ts create mode 100644 src/views/tools/flow/model/StartNode.ts diff --git a/.env.development b/.env.development index 80cc26b..4165644 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,5 @@ # 页面标题 -VITE_APP_TITLE=里派基础框架 +VITE_APP_TITLE=里派基础框架(开发版) # 开发环境配置 VITE_APP_ENV='development' diff --git a/package.json b/package.json index 522068b..173084e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/assets/icons/Accept.vue b/src/assets/icons/Accept.vue new file mode 100644 index 0000000..2aca67a --- /dev/null +++ b/src/assets/icons/Accept.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Approval.vue b/src/assets/icons/Approval.vue new file mode 100644 index 0000000..e8e8e8e --- /dev/null +++ b/src/assets/icons/Approval.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Command.vue b/src/assets/icons/Command.vue new file mode 100644 index 0000000..e6f9769 --- /dev/null +++ b/src/assets/icons/Command.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Custom.vue b/src/assets/icons/Custom.vue new file mode 100644 index 0000000..ecd692b --- /dev/null +++ b/src/assets/icons/Custom.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/End.vue b/src/assets/icons/End.vue new file mode 100644 index 0000000..1846ece --- /dev/null +++ b/src/assets/icons/End.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Exclusive.vue b/src/assets/icons/Exclusive.vue new file mode 100644 index 0000000..0921b1c --- /dev/null +++ b/src/assets/icons/Exclusive.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Flow.vue b/src/assets/icons/Flow.vue new file mode 100644 index 0000000..59f6631 --- /dev/null +++ b/src/assets/icons/Flow.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Inclusive.vue b/src/assets/icons/Inclusive.vue new file mode 100644 index 0000000..e3e19a7 --- /dev/null +++ b/src/assets/icons/Inclusive.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Message.vue b/src/assets/icons/Message.vue new file mode 100644 index 0000000..38258bb --- /dev/null +++ b/src/assets/icons/Message.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Parallel.vue b/src/assets/icons/Parallel.vue new file mode 100644 index 0000000..63f4e6c --- /dev/null +++ b/src/assets/icons/Parallel.vue @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/Script.vue b/src/assets/icons/Script.vue new file mode 100644 index 0000000..33bae24 --- /dev/null +++ b/src/assets/icons/Script.vue @@ -0,0 +1,3 @@ + diff --git a/src/layout/components/NavMenu.vue b/src/layout/components/NavMenu.vue index f3b2dec..1d06d95 100644 --- a/src/layout/components/NavMenu.vue +++ b/src/layout/components/NavMenu.vue @@ -1,17 +1,17 @@ - diff --git a/src/layout/index.vue b/src/layout/index.vue index 48cd7c2..a5991b9 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -182,7 +182,7 @@
    -
  • @@ -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' diff --git a/src/router/index.ts b/src/router/index.ts index 1afc60b..abaf6e4 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -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 }); }); diff --git a/src/views/system/login/index.vue b/src/views/system/login/index.vue index 747ccb8..449c07a 100644 --- a/src/views/system/login/index.vue +++ b/src/views/system/login/index.vue @@ -22,7 +22,7 @@ @@ -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 diff --git a/src/views/system/translation/index.vue b/src/views/system/translation/index.vue index d9bc001..fdd04d2 100644 --- a/src/views/system/translation/index.vue +++ b/src/views/system/translation/index.vue @@ -43,7 +43,7 @@ - + diff --git a/src/views/tools/flow/index.vue b/src/views/tools/flow/index.vue new file mode 100644 index 0000000..6c11521 --- /dev/null +++ b/src/views/tools/flow/index.vue @@ -0,0 +1,282 @@ + + + + + diff --git a/src/views/tools/flow/left.vue b/src/views/tools/flow/left.vue new file mode 100644 index 0000000..5f2f09f --- /dev/null +++ b/src/views/tools/flow/left.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/src/views/tools/flow/menu.vue b/src/views/tools/flow/menu.vue new file mode 100644 index 0000000..c56a00f --- /dev/null +++ b/src/views/tools/flow/menu.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/views/tools/flow/model/CatchNode.ts b/src/views/tools/flow/model/CatchNode.ts new file mode 100644 index 0000000..2c6ec67 --- /dev/null +++ b/src/views/tools/flow/model/CatchNode.ts @@ -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)` + })) + ); + } +} diff --git a/src/views/tools/flow/model/CustomLine.ts b/src/views/tools/flow/model/CustomLine.ts new file mode 100644 index 0000000..418a664 --- /dev/null +++ b/src/views/tools/flow/model/CustomLine.ts @@ -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 { + +} + diff --git a/src/views/tools/flow/model/EndNode.ts b/src/views/tools/flow/model/EndNode.ts new file mode 100644 index 0000000..011127c --- /dev/null +++ b/src/views/tools/flow/model/EndNode.ts @@ -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)` + })) + ) + } +} diff --git a/src/views/tools/flow/model/EventNode.ts b/src/views/tools/flow/model/EventNode.ts new file mode 100644 index 0000000..1777f72 --- /dev/null +++ b/src/views/tools/flow/model/EventNode.ts @@ -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) + ); + } +} diff --git a/src/views/tools/flow/model/GatewayNode.ts b/src/views/tools/flow/model/GatewayNode.ts new file mode 100644 index 0000000..c692fe2 --- /dev/null +++ b/src/views/tools/flow/model/GatewayNode.ts @@ -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)` + })) + ); + } +} diff --git a/src/views/tools/flow/model/StartNode.ts b/src/views/tools/flow/model/StartNode.ts new file mode 100644 index 0000000..d83b4d6 --- /dev/null +++ b/src/views/tools/flow/model/StartNode.ts @@ -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)` + })) + ) + } +}