rr13k / vue3-super-flow

5 stars 2 forks source link

拖拽辅助线 不显示 #1

Open ZhaoYu8 opened 1 year ago

rr13k commented 1 year ago

请补充完整信息, 或示例代码...

ZhaoYu8 commented 1 year ago
<!--
 * @Author: 赵宇
 * @Description: 流程编辑
 * @Date: 2023-02-09 13:40:57
 * @LastEditTime: 2023-02-21 14:23:52
 * @LastEditors: zhao 13370229059@163.com
 * @FilePath: \pcj\src\page\flow\components\flowEdit.vue
-->
<template>
  <div class="flow">
    <z-button icon="check" @click="onCheck" class="ml-10 mt-10"> 确认 </z-button>
    <SuperFlow
      ref="superFlow"
      :node-list="params.nodeList"
      :link-list="params.linkList"
      :graph-menu="params.graphMenuList"
      :node-menu="params.nodeMenuList"
      :link-menu="params.linkMenuList"
      :enter-intercept="params.enterIntercept"
      :output-intercept="params.outputIntercept"
    >
      <template v-slot:node="{ meta }">
        <div :class="`flow-node flow-node-${meta.prop}`" :ref="'flow_' + meta.id">
          <header v-if="['end', 'start'].includes(meta.prop)">{{ meta.taskName }}</header>
          <el-input v-model="meta.taskName" v-else :class="`flow-node-input-${meta.prop}`"></el-input>
          <section v-if="!['end', 'start'].includes(meta.prop)">
            <el-select v-model="meta.taskType">
              <el-option v-for="item in taskOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </section>
        </div>
      </template>
      <template v-slot:menuItem="meta">
        <span class="super-flow__menu-item-content" v-if="meta.item.disabled">{{ meta.item.label }}</span>
      </template>
    </SuperFlow>
    <nodeEdit v-model="state.nodeShow" :editData="state.editData" :nodeList="state.nodeList" @onSave="onSave" />
  </div>
</template>

<script setup>
import nodeEdit from '@/page/flow/components/nodeEdit.vue';
import { flowNodeDefault } from '@/page/flow/flow.js';
import { SuperFlow } from 'vue3-super-flow';
import { taskOptions } from '@/config/data';
import 'vue3-super-flow/dist/style.css';
let route = useRoute();
let router = useRouter();
let $message = inject('$message');
let nodeId = ref(1000);
let superFlow = ref();
let getOnlyId = () => {
  return ++nodeId.value;
};
let urlParams = computed(() => route.query);
// 流程值处理
let params = reactive({
  nodeList: [],
  linkList: [],
  graphMenuList: [
    [
      {
        label: '开始节点',
        disable(graph) {
          return !!graph.nodeList.find(node => node.meta.prop === 'start');
        },
        selected: (graph, coordinate) => {
          const id = getOnlyId();
          let obj = {
            id,
            width: 70,
            height: 40,
            coordinate,
            meta: flowNodeDefault({
              id,
              prop: 'start',
              taskName: '开始',
              taskType: 0
            })
          };
          graph.addNode(obj);
        }
      },
      {
        label: '添加节点',
        disable: false,
        selected: (graph, coordinate) => {
          const id = getOnlyId();
          let obj = {
            id,
            width: 200,
            height: 100,
            coordinate,
            meta: flowNodeDefault({
              id,
              prop: 'approval',
              taskName: '节点' + (nodeId.value - 1000),
              taskType: 1
            })
          };
          console.log(graph);
          graph.addNode(obj);
        }
      },
      {
        label: '完成节点',
        disable(graph) {
          return !!graph.nodeList.find(point => point.meta.prop === 'end');
        },
        selected: (graph, coordinate) => {
          const id = getOnlyId();
          let obj = {
            id,
            width: 70,
            height: 40,
            coordinate, // 坐标
            meta: flowNodeDefault({
              id,
              prop: 'end',
              taskName: '完成',
              taskType: 999
            })
          };
          graph.addNode(obj);
        }
      }
    ]
  ],
  nodeMenuList: [
    [
      {
        label: '编辑',
        disable: graph => {
          // 修改的时候
          if (['start', 'end'].includes(graph.meta.prop)) {
            return true;
          }
          return false;
        },
        selected: node => {
          let { nodeList } = node.graph;
          console.log(nodeList, node);
          state.editData = node.meta;
          // 这里处理掉 开始 结束节点,省的传递子组件要处理
          state.nodeList = nodeList.map(r => r.meta).filter(r => ![0, 999].includes(r.taskType));
          state.nodeShow = true;
        }
      },

      {
        label: '删除',
        disable: graph => {
          return ['start', 'end'].includes(graph.meta.prop);
        },
        selected: (node, coordinate) => {
          node.remove();
        }
      }
    ]
  ],
  linkMenuList: [
    [
      {
        label: '删除',
        disable: false,
        selected(link, coordinate) {
          link.remove();
        }
      }
    ]
  ],
  // 连续结束限制。
  enterIntercept: (formNode, toNode, graph) => {
    const formType = formNode.meta.prop;
    switch (toNode.meta.prop) {
      case 'start':
        return false;
      case 'approval':
        return ['start', 'approval'].includes(formType);
      case 'end':
        return ['approval'].includes(formType);
      default:
        return true;
    }
  },
  // 连线限制,只要不是结束节点,都可以开始连线
  outputIntercept: (node, graph) => {
    return !(node.meta.prop === 'end');
  }
});
let state = reactive({
  nodeShow: false,
  editData: {},
  nodeList: []
});
// 点击保存
const onCheck = () => {
  let type = false;
  if (!superFlow.value) return;
  let graph = superFlow.value.graph.toJSON();
  let { nodeList, linkList } = graph;
  // 筛出 开始、结束节点 筛出 非开始、结束节点
  let nodeResult = [nodeList.filter(r => [0, 999].includes(r.meta.taskType)), nodeList.filter(r => ![0, 999].includes(r.meta.taskType))];
  // 必须具备开始 和 结束 节点 。 并且起码要有一个 任务节点
  type = nodeResult[0].length === 2 && nodeResult[1].length;
  // type 为真,才有必要判断线对不对
  if (type) {
    // 开始和结束 必须都要有连线
    let likeResult = [
      linkList.filter(r => r.startId === nodeResult[0].filter(n => n.meta.taskType === 0)[0].id),
      linkList.filter(r => r.endId === nodeResult[0].filter(n => n.meta.taskType === 999)[0].id)
    ];
    type = likeResult[0].length && likeResult[1].length; // 都可以存在多条分支分出去 ,也可以存在多条链接结束
  }
  if (type) {
    let arr = nodeList.filter(r => ![0, 999].includes(r.meta.taskType));
    // 判断除了开始 和 结束 ,其他节点 都必须要有开始 和结束 二种连线
    arr.map(r => {
      // 如果为 false 的就不要往下执行了!
      if (!type) return;
      let obtain = [linkList.filter(n => n.startId === r.id), linkList.filter(n => n.endId === r.id)];
      type = obtain[0].length && obtain[1].length;
    });
  }
  if (!type) {
    $message.warning('流程错误,请检查流程图配置!');
    return;
  }
  // 如果是业务单 必须要有一个发货节点。还只能有一个
  if (Number(urlParams.value.type) === 1) {
    if (nodeList.filter(r => r.meta.taskType === 5).length !== 1) {
      $message.warning('业务单必须要有发货节点,有且只能有一个!');
      return;
    }
  }
  // 如果是采购单 必须要有一个采购入库节点。还只能有一个
  if (Number(urlParams.value.type) === 2) {
    if (nodeList.filter(r => r.meta.taskType === 3).length !== 1) {
      $message.warning('采购单必须要有采购入库节点,有且只能有一个!');
      return;
    }
  }
  templateSave(nodeList, linkList);
};

const templateSave = async (nodeList, linkList) => {
  http.post('TemplateProgress/CreateOrUpdate', {
    id: 0,
    formSourceType: urlParams.value.type,
    processJson: JSON.stringify({ nodeList, linkList })
  });
  $message.success('创建成功!');
  router.push({
    path: 'flow',
    query: { type: urlParams.value.type }
  });
};

// 处理节点编辑
const onSave = val => {
  let nodeList = superFlow.value.graph.nodeList;
  const index = nodeList.findIndex(r => r.meta.id === val.id);
  console.log(nodeList, index);
  nodeList[index].meta = { ...val };
  state.nodeShow = false;
};
</script>

<style lang="scss" scoped>
.flow {
  height: 100%;
  width: 100%;
  background-color: #fff;
  position: relative;
}
</style>

<style lang="scss">
.super-flow__node {
  color: #fff;
  border: 0 !important;
  border-radius: 4px;
  overflow: hidden;
  .flow-node {
    height: 100%;
    display: flex;
    flex-direction: column;
    section {
      padding: 10px;
    }
    header {
      border-radius: 5px;
      font-size: 17px;
      height: 40px;
      line-height: 40px;
      padding: 0 12px;
      background-color: var(--el-color-warning);
      text-align: center;
    }
    &-start {
      header {
        background-color: var(--el-color-primary);
      }
    }
    &-end {
      header {
        background-color: var(--el-color-danger);
      }
    }
  }
  .flow-node-input-approval {
    .el-input__wrapper {
      background-color: var(--el-color-warning);
      box-shadow: none;
      border-radius: 0;
      input {
        color: #fff;
      }
    }
  }
}
.super-flow__menu-container {
  .super-flow__menu {
    padding: 0;
    border: 0;
    &-line {
      margin: 0 auto;
      width: 96%;
      display: none;
    }
    &-item {
      padding: 10px;
      width: 100%;
      &:nth-child(even) {
        background-color: #f2f6fc;
      }
      &:hover {
        background-color: #55abfc;
        color: #fff;
      }
      &-icon {
        display: none;
      }
      &-content {
        width: inherit;
        color: inherit;
      }
    }
  }

  .is-disabled {
    display: none;
    background-color: #efefef;

    &:hover {
      background-color: #efefef;
      color: #000;
    }
  }
}
</style>
rr13k commented 1 year ago

会在周末进行修复,如果你已经完成可以提交fork...

ZhaoYu8 commented 1 year ago

会在周末进行修复,如果你已经完成可以提交fork...

顺便修复下,无法的滚动的问题。 看代码是监听了onwheel事件。然后preventDefault 我现在是去编译后js里面删了 preventDefault() 事件。