| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- <template>
- <div :class="{ 'ep-node': true, 'ep-node-arrows': !isStart }">
- <div :class="{ 'ep-node-content': true, 'ep-node-error': isError }">
- <!-- header -->
- <div class="ep-node-header" :style="{ color: config.color, 'background-color': config.bgColor }">
- <Icon class="ep-node-icon" :icon="config.icon.name" :color="config.icon.color || '#FFFFFF'" />
- <div class="ep-node-header-title">{{ config.title }}</div>
- <Icon class="ep-node-close cursor-pointer text-white" :icon="''" v-if="canRemoved" @click.stop="removeNode" />
- </div>
- <!-- body -->
- <div class="ep-node-body" @click="showNodeDrawer">
- <component ref="node" :is="nodeComponents[props.node.nodeType]" :tempNodeId="tempNodeId" :node="props.node" />
- </div>
- <!-- 校验错误提示 -->
- <div class="ep-node-error-msg" v-if="isError">
- <div class="ep-node-error-msg-box">
- <icon icon="svg:tips" :width="23" height="23" color="red" @mouseenter="showErrorTips(true)" @mouseleave="showErrorTips(false)" />
- <div class="ep-node-error-tips" v-if="errorTips">{{ errorMessage }}</div>
- </div>
- </div>
- </div>
- <NodeAdd :node="props.node" />
- <!-- 节点配置Drawer -->
- <BaseDrawer ref="nodeDrawer" @updateConfig="updateConfig" @cancelUpdateConfig="cancelUpdateConfig" />
- </div>
- </template>
- <script setup lang="ts" name="BaseNode">
- import { ref, shallowRef, onMounted, getCurrentInstance, defineAsyncComponent, watch, computed, onUnmounted, inject } from 'vue'
- import BaseDrawer from './BaseDrawer.vue'
- import NodeAdd from './node_add.vue'
- import { nodeConfigData, ProcessConstant } from '../../common/process.data'
- import { getUUID } from '../../common/common.util'
- import { EasyProcess } from '../../common/process.type'
- import { Validator } from '../../common/validator.util'
- import NodeStart from '../start/startNode.vue'
- import NodeOperation from '../operation/operationNode.vue'
- import NodeFault from '../fault/faultNode.vue'
- import NodeVoice from '../voice/voiceNode.vue'
- const nodeComponents = shallowRef({
- start: NodeStart,
- operation: NodeOperation,
- fault: NodeFault,
- voice: NodeVoice
- })
- const props = withDefaults(defineProps<{ node: EasyProcess.NodeConfig }>(), {})
- // 节点配置数据
- const config = ref(nodeConfigData[props.node.nodeType])
- const isStart = computed(() => props.node.nodeType == 'start')
- const validator = inject<Validator>(ProcessConstant.KEY_VALIDATOR)
- watch(
- () => props.node,
- () => {
- config.value = nodeConfigData[props.node.nodeType]
- validator?.validate()
- }
- )
- // ---------- 节点数据校验 ---------- start
- const errorTips = ref<boolean>(false)
- const showErrorTips = (flag: boolean) => (errorTips.value = flag)
- const errorMessage = computed<string>(() => {
- let result = validator?.getResult(tempNodeId)
- return result ? (result.message ?? '') : ''
- })
- const isError = computed<boolean>(() => {
- let result = validator?.getResult(tempNodeId)
- return result ? !result.valid : false
- })
- // ---------- 节点数据校验 --------- end
- // 节点是否可以被移除
- const canRemoved = computed(() => {
- if (isLastCondition.value) return false
- return config.value.canRemoved
- })
- // 是否是最后一个条件节点
- const isLastCondition = computed<boolean>(() => {
- return props.node.nodeType == 'condition' && props.node.isLastCondition
- })
- const { proxy } = getCurrentInstance()
- // 生成临时节点ID
- const tempNodeId = getUUID()
- onUnmounted(async () => {
- validator?.remove(tempNodeId)
- validator?.validate()
- })
- // 显示节点配置组件
- const showNodeDrawer = () => {
- if (config.value.hasDrawer) {
- if (isLastCondition()) {
- return false
- }
- proxy.$refs.nodeDrawer.show(props.node)
- }
- }
- // 移除当前节点
- const emit = defineEmits(['removeNode'])
- const removeNode = () => {
- emit('removeNode')
- }
- // 更新节点配置属性
- const updateConfig = (data: EasyProcess.NodeConfig) => {
- props.node = data
- validator?.validate()
- }
- // 取消更新节点配置属性
- const cancelUpdateConfig = () => validator?.validate()
- </script>
- <style lang="scss" scoped>
- .ep-node {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- margin: 0 100px;
- }
- .ep-node-arrows {
- &::before {
- position: absolute;
- top: -12px;
- left: 50%;
- width: 0;
- height: 4px;
- content: '';
- background: #f5f5f7;
- border-color: #cacaca transparent transparent;
- border-style: solid;
- border-width: 8px 6px 4px;
- -webkit-transform: translateX(-50%);
- transform: translateX(-50%);
- }
- }
- .ep-node-content {
- position: relative;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- align-items: center;
- width: 200px;
- min-height: 80px;
- font-size: 14px;
- word-break: break-word;
- white-space: normal;
- border-radius: 5px;
- box-shadow: 5px 5px 10px 2px rgb(0 0 0 / 20%);
- transition-duration: 0.1s;
- transition-property: box-shadow;
- &:hover {
- box-shadow: 5px 5px 12px 5px rgb(0 0 0 / 20%);
- }
- .ep-node-header {
- box-sizing: border-box;
- display: flex;
- align-items: center;
- width: 100%;
- padding: 5px 10px;
- color: #fff;
- background-color: #1e83e9;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- .ep-node-icon {
- font-size: 16px;
- }
- .ep-node-header-title {
- flex: 1;
- margin-left: 4px;
- }
- .ep-node-close {
- font-size: 16px;
- text-align: center;
- cursor: pointer;
- }
- }
- .ep-node-body {
- box-sizing: border-box;
- display: flex;
- flex: 1;
- flex-direction: column;
- justify-content: center;
- width: 100%;
- padding: 10px;
- color: #5a5e66;
- cursor: pointer;
- background-color: #fff;
- border-bottom-right-radius: 5px;
- border-bottom-left-radius: 5px;
- }
- }
- .ep-node-error {
- box-shadow: 0 0 10px 2px rgb(243 5 5 / 50%);
- &:hover {
- box-shadow: 0 0 12px 4px rgb(243 5 5 / 50%);
- }
- }
- .ep-node-error-msg {
- position: absolute;
- top: 50%;
- right: -55px;
- z-index: 1;
- transform: translateY(-50%);
- .ep-node-error-msg-box {
- position: relative;
- .ep-node-error-icon {
- width: 25px;
- height: 25px;
- cursor: pointer;
- }
- .ep-node-error-tips {
- position: absolute;
- top: 50%;
- left: 45px;
- z-index: 3;
- display: flex;
- min-width: 150px;
- padding: 16px;
- background-color: #fff;
- border-radius: 5px;
- box-shadow: 5px 5px 10px 2px rgb(0 0 0 / 20%);
- transform: translateY(-50%);
- &::before {
- position: absolute;
- top: 50%;
- left: -20px;
- width: 0;
- height: 0;
- content: '';
- border: 10px solid;
- border-color: transparent #fff transparent transparent;
- transform: translateY(-50%);
- }
- }
- }
- }
- .ep-node-move {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- }
- .ep-node-move-left {
- left: -30px;
- }
- .ep-node-move-right {
- right: -30px;
- }
- .ep-node-move-icon {
- width: 35px;
- height: 35px;
- cursor: pointer;
- }
- </style>
|