vue3+vue-flow实现拖拽矩形框,端点连线,自定义宽高

发布于:2025-05-23 ⋅ 阅读:(20) ⋅ 点赞:(0)

vue3+vue-flow实现拖拽矩形框,端点连线,自定义宽高


前言

vue3+vue-flow实现拖拽矩形框,端点连线,自定义宽高

一、下载插件

 "@vue-flow/background": "^1.3.2",
"@vue-flow/controls": "^1.1.2",
"@vue-flow/core": "^1.42.4",
"@vue-flow/minimap": "^1.5.2",
"@vue-flow/node-resizer": "^1.4.0",

二、直接上代码

1.taskDetail.vue

代码如下(示例):

<template>
  <div class="app-container" style="height: calc(100vh - 100px)">
    <div class="taskcard-box">
      <el-card class="left-box" shadow="never">
        <!-- <TaskFlow ref="taskFlowRef" v-bind="taskFlowParams" /> -->
        <TaskFlow ref="taskFlowRef" :detailInfo="taskFlowParams" :key="1" v-model:unusedPort="unusedPort" />
      </el-card>
      <el-card class="right-box custom_right_box" shadow="never">
        <el-tabs type="border-card" class="demo-tabs">
          <el-tab-pane label="设置">
            <el-space direction="vertical">
              <el-form ref="formRef" :model="form" :rules="rules" label-width="auto">
                <el-form-item label="所属项目:">
                  <!-- <SpProjectSelect v-model="project.id" url="/project/listPage" method="post" disabled /> -->
                </el-form-item>
                <el-form-item label="任务名称:" prop="taskName">
                  <el-input v-model="form.taskName" placeholder="请输入任务名称" />
                </el-form-item>
                <el-form-item label="宽度:">
                  <el-input-number v-model="taskFlowParams.width" :min="800" :max="100000" />
                </el-form-item>
                <el-form-item label="高度:">
                  <el-input-number v-model="taskFlowParams.height" :min="800" :max="100000" />
                </el-form-item>
                <el-form-item label="时间间隔(ms):" prop="taskInterval">
                  <el-input-number v-model="form.taskInterval" :min="1" :max="10000000" />
                </el-form-item>
                <el-form-item label="任务周期:" prop="taskType">
                  <sp-select-dict v-model="form.taskType" dictType="task-type" />
                </el-form-item>
                <el-form-item label="状态:" prop="taskStatus">
                  <el-switch size="large" v-model="form.taskStatus" active-value="0" inactive-value="1" inline-prompt active-text="启用" inactive-text="禁用" />
                </el-form-item>
              </el-form>
            </el-space>
          </el-tab-pane>
          <el-tab-pane label="组件">
            <ComponentTree />
          </el-tab-pane>
        </el-tabs>
        <div class="btn-box">
          <el-button   @click="back">返回</el-button>
          <el-button type="primary" @click="save">保存</el-button>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script setup>
import TaskFlow from "@/views/comChunk/leftContent.vue";
import ComponentTree from "@/components/componentTree/ComponentTree.vue";
import { addTaskApi, taskUpdateByIdApi, getTaskDetailByIdApi } from "@/api/flow";
import { ElMessage ,ElLoading} from "element-plus";
const route = useRoute();
const router = useRouter();
const taskFlowRef = ref();
const formRef=  ref()
onMounted(() => {
  if (route.query.id) {
    form.value.id = route.query.id;
    getDetail();
  }
});
const data = reactive({
  form: {
    id: null,
    configJson: {
      height: 600,
      width: 1200,
    },
    taskStatus: "0",
    taskType: "",
    taskJson: {},
    taskName: "",
    taskInterval: null,
  },
  taskFlowParams: {
    data: {},
    width: 1200,
    height: 600,
    background: {
      color: "#fffbe6", // 设置画布背景颜色
    },
    grid: {
      size: 10, // 网格大小 10px
      visible: true, // 渲染网格背景
    },
  },
  rules: {
    taskName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
    taskType: [{ required: true, message: "任务类型不能为空", trigger: "blur" }],
    taskInterval: [
      {
        required: true,
        type: "number",
        message: "时间间隔不能为空",
        trigger: "blur",
      },
    ],
  },
  unusedPort: [],
});

const { form, taskFlowParams, rules, unusedPort } = toRefs(data);

const getDetail = async () => {
  const res = await getTaskDetailByIdApi({ id: form.value.id });
  if (res.code == 200 && res.data) {
    form.value = {...form.value ,...res.data };
    const edgesData = res.data?.taskJson?.cells.filter((item) => item.shape === "edge");
    const nodesData = res.data?.taskJson?.cells.filter((item) => item.shape !== "edge");

    await nextTick(() => {
      nodesData.forEach((item) => taskFlowRef.value?.addNodesToFlow(item));
      taskFlowRef.value?.addEdgesToFlow(edgesData);
    });

    // 确保 taskFlowParams 变化不会导致递归
    taskFlowParams.value = { ...taskFlowParams.value, width: res.data.configJson.width, height: res.data.configJson.height };
  }
}; 

/* 保存 */
let loading = ref(null);
const save = async () => {
  formRef.value?.validate(async (valid) => {
    if (!valid) return;
    loading.value = ElLoading.service({
      text: "Loading",

      background: "rgba(0, 0, 0, 0.7)",
    });

    try {
     
      let data = {
        ...form.value,
        id: form.value?.id ? form.value.id : undefined,
      };

      let nodesData = taskFlowRef.value?.nodes;
      let edgesData = taskFlowRef.value?.edges;
      data.taskJson = await processModuleJson(nodesData, edgesData);

 
      data.configJson = {
        height: taskFlowParams.height || 600,
        width: taskFlowParams.width || 1200,
      };
      // data.imageUrl = "";
      console.log("form.value", form.value);
      console.log("data", data);
      console.log("data", data.id);

     
      const res = !data.id ? await addTaskApi({ ...data }) : await taskUpdateByIdApi({ ...data });

      console.log(res);
      if (res.code == 200) {
        ElMessage({
          type: "success",
          message: data.id ? "修改成功" : "添加成功",
        });
        router.back()
      }
    } finally {
      loading.value.close();
    }
  });
};

/* 处理moduleJson数据 */
const processModuleJson = (nodesData, edgesData) => {
  let nodeArr = nodesData.map((item) => {
    // console.log(item);

    let ports = {};
    if (item.data.ports?.items && item.data.ports?.items.length > 0) {
      ports = item.data.ports;
    } else {
      ports = {
        groups: {
          in: {
            position: { name: "left" },
          }, // 你可以自定义 `in` 端口组的属性
          out: {
            lable: { position: { name: "right" } },
            position: { name: "right" },
          }, // 你可以自定义 `out` 端口组的属性
        },
        items: item.data.ports || [], // 这里存放原来的 ports 数组
      };
    }
    let tools = {};
    if (item.data.tools?.items && item.data.tools?.items.length > 0) {
      tools = item.data.tools;
    } else {
      tools = {
        items: item.data.tools,
      };
    }

    return {
      // ...item,
      portMarkup: [],

      router: {},
      size: {},

      ...item.data,
      shape: "rect",
      componentId: item.data.componentId,
      id: item.id,
      ports: ports,
      tools: tools,
      position: item.position,
      width: item.dimensions.width,
      height: item.dimensions.height,
    };
  });

  let edgeArr = edgesData.map((item) => {
    return {
      ...item,
      shape: "edge",
      source: {
        cell: item.source,
        port: item.sourceHandle,
      },
      target: {
        cell: item.target,
        port: item.targetHandle,
      },
    };
  });

  // form.value.moduleJson = {
  //   cells: [...nodesData, ...edgesData],
  // };

  return { cells: [...nodeArr, ...edgeArr] };
};

const back = ()=>{
  router.back()
}
</script>

<style lang="scss" scoped>
.taskcard-box {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  width: 100%;
  height: 100%;
}
.right-box {
  width: 350px;
  height: 100%;
}
.left-box {
  flex: 1;
  max-height: calc(100vh - 100px);
  overflow: auto;
  margin-right: 10px;
}
.btn-box {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 10px;
}
.demo-tabs {
  max-height: calc(100vh - 180px);
  overflow: scroll;
}
</style>

2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。


网站公告

今日签到

点亮在社区的每一天
去签到